打印机支持的文件为 prt 或者prn
这里介绍如何缩放打印文件
打印文件格式如下:
cpp
struct SRipHeader
{
int nSignature;
int nVersion;
int nImageWidth; // RIP Image pixel width
int nImageHeight; // RIP Image pixel height
int nImageColorNum; //RIP image Color number include 4 (YMCK) 6 YMCKLcLm 8 YMCKLcLmOrGr
int nImageColorDeep; //1,2,4,8 RIP image output bit per color
int nImageResolutionX; //RIP image X resolution, 180,360,720
int nImageResolutionY; //RIP Image Y resolution, 186,372,558,744
int nCompressMode; // First version should be 0 , no compress mode
int nBytePerLine; //First version used for no compress mode
int nBidirection; // Bidirection for 1, Unidirection for 0
int nPass; //1,2,3,4,6,8,12 Pass
int nSpeed; //High speed 0 Middle speed 1 Low Speed 2
///Version 2 Change
unsigned char nExtraChannel;
unsigned char nVSDMode; //Set VSD Mode for EPSON PrintHead driver
unsigned char nEpsonPrintMode; // High Qulity :0 ,High Speed: 1
unsigned char nChannelColorName[16]; //color for each channel
unsigned char biCompression; // whether or not use data compression;0:no Compression;1:RLE4;2:RLE8
int nPreviewImgByteSize; // If the preview is included, it is the number of bytes in the preview, otherwise it should be 0.
unsigned char bPreviewImg; // Whether it contains a preview;0:no preview;1:bmp(24bit,rgb);
unsigned char nReserve[2]; //Fill with 0
unsigned char nPrtNum;
unsigned char nChannel[4];
};
注意:读文件时,首先需要解析文件头,如上
假设是4色(ymck),位深(nImageColorDeep)为2的打印文件,则文件内容如下:
Y : 00 01 01 10 11 10
M: 11 10 01 11 00 00
C: 00 10 01 00 11 00
K : 00 00 01 00 00 01
也就是说我们看见的图片的每一行对应打印文件的四行,每2位代表一个颜色
图片的宽度为nImageWidth,那么文件这一行的长度为:(nImageWidth * nImageColorDeep+7)/8
因为文件必须为 8位对齐
最邻近算法缩放图片
cpp
#pragma once
#include "PrtFile.h"
#include <string>
#include<fstream>
#include <mutex>
#include "windows.h"
class CZoomPrtFile :
public CPrtFile
{
public:
CZoomPrtFile();
virtual ~CZoomPrtFile();
bool Open(LPCTSTR szFileName);
virtual void Close();
virtual int Seek(uint64 pos);
virtual int Read(void* buf, int size, int count);
virtual int ReadLine(BYTE* pData, int nLine, int xStart, int nLen);
virtual void AbortRead();
void setZoom(size_t zoomWidth, size_t zoomHeight);
bool saveZoomPrtFile(const std::string& prtFile,size_t zoomWidth, size_t zoomHeight);
bool saveZoomPrtFile(const std::string& prtFile);
void zoomPrtFileparallel(BYTE* pTargetData);
/*void zoomPrtFileThreadProc(BYTE* pTargetData, int ColorNum);*/
void zoomPrtFileThreadProc(BYTE* pTargetData, int start, int endRow);
private:
void zoomPrtFile(BYTE* pTargetData);
unsigned char getPixel(unsigned char* data, int x, int nImageColorDeep);
void setPixel(unsigned char* data, int x, unsigned char pixel, int nImageColorDeep);
bool writePrtFile(const std::string& prtFile, unsigned char* data, size_t outDataSize);
unsigned char getPixel(unsigned char data, int x, int nImageColorDeep);
private:
FILE* m_fp;
bool m_bAbort;
size_t m_zoomWidth;
size_t m_zoomHeight;
size_t m_perWidth;
size_t m_perHeight;
std::mutex fileMutex; // 文件锁
};
cpp
cpp
#include "CZoomPrtFile.h"
#include <Windows.h>
#include<vector>
#include <thread>
#include <chrono>
#include <iostream>
using namespace std;
CZoomPrtFile::CZoomPrtFile() :
m_fp(NULL),
m_bAbort(false),
m_zoomWidth(-1),
m_zoomHeight(-1)
{
}
CZoomPrtFile::~CZoomPrtFile()
{
Close();
}
bool CZoomPrtFile::Open(LPCTSTR szFileName)
{
m_fp = _wfsopen(szFileName, L"rb", _SH_DENYNO);
if (!m_fp)
{
return false;
}
if (OpenPrt())
{
m_perWidth = m_header.nImageWidth;
m_perHeight = m_header.nImageHeight;
return true;
}
else
{
return false;
}
}
void CZoomPrtFile::Close()
{
if (m_fp)
{
fclose(m_fp);
m_fp = NULL;
}
}
int CZoomPrtFile::Seek(uint64 pos)
{
return _fseeki64(m_fp, pos, SEEK_SET);
}
int CZoomPrtFile::Read(void* buf, int size, int count)
{
//std::lock_guard<std::mutex> locker(fileMutex);
return (int)fread(buf, size, count, m_fp);
}
int CZoomPrtFile::ReadLine(BYTE* pData, int nLine, int xStart, int nLen)
{
//std::lock_guard<std::mutex> locker(fileMutex); fseek和fread单独使用线程安全 fseek和fread联合使用需要加锁或者采用临界区
Seek(sizeof(m_header) + (int64)nLine * m_header.nBytePerLine + xStart);
Read(pData, 1, nLen);
return 0;
while (true)
{
if (m_bAbort)
{
break;
}
if (Seek(sizeof(m_header) + (int64)nLine * m_header.nBytePerLine + xStart) != 0)
{
Sleep(10);
continue;
}
if (Read(pData, 1, nLen) != nLen)
{
Sleep(10);
continue;;
}
else
{
return nLen;
}
}
return 0;
}
void CZoomPrtFile::AbortRead()
{
m_bAbort = true;
}
void CZoomPrtFile::setZoom(size_t zoomWidth, size_t zoomHeight)
{
m_zoomWidth = zoomWidth;
m_zoomHeight = zoomHeight;
}
bool CZoomPrtFile::saveZoomPrtFile(const std::string& prtFile,size_t zoomWidth, size_t zoomHeight)
{
m_zoomWidth = zoomWidth;
m_zoomHeight = zoomHeight;
return saveZoomPrtFile(prtFile);
}
bool CZoomPrtFile::saveZoomPrtFile(const std::string& prtFile)
{
// Get Start Time
std::chrono::system_clock::time_point start = std::chrono::system_clock::now();
bool ok = false;
if (m_zoomWidth > 1 && m_zoomHeight > 1 && m_fp)
{
int nTargetLineByteSize = (m_zoomWidth * m_header.nImageColorDeep + 7) / 8;
int nTargetDataSize = sizeof(m_header) + nTargetLineByteSize * m_header.nImageColorNum * m_zoomHeight;
BYTE* pTargetData = new BYTE[nTargetDataSize];
memset(pTargetData, 0, nTargetDataSize);
SRipHeader zoomHeader(m_header);
zoomHeader.nImageHeight = m_zoomHeight;
zoomHeader.nImageWidth = m_zoomWidth;
zoomHeader.nBytePerLine = nTargetLineByteSize;
memcpy(pTargetData, &zoomHeader, sizeof(zoomHeader));
zoomPrtFile(pTargetData);
//zoomPrtFileparallel(pTargetData);
ok=writePrtFile(prtFile, pTargetData, nTargetDataSize);
delete[] pTargetData;
// Get End Time
auto end = std::chrono::system_clock::now();
auto diff = std::chrono::duration_cast <std::chrono::milliseconds> (end - start).count();
std::cout << prtFile<<" . Total Time Taken = " << diff << " milliseconds" << " . Total size = " << m_header.nBytePerLine* m_header.nImageHeight * m_header.nImageColorNum + sizeof(m_header) << "byte"
" . target file size = " << zoomHeader.nBytePerLine * zoomHeader.nImageHeight * zoomHeader.nImageColorNum + sizeof(zoomHeader) << std::endl;
}
return ok;
}
void CZoomPrtFile::zoomPrtFile(BYTE* pTargetData)
{
float xRatio = static_cast<float>(m_perWidth - 1) / m_zoomWidth;
float yRatio = static_cast<float>(m_perHeight - 1) / m_zoomHeight;
int srcX=0, srcY=0;
int nTargetLineSize = (m_zoomWidth * m_header.nImageColorDeep + 7) / 8;
BYTE* pSourceLineData = new BYTE[m_header.nBytePerLine];
for (size_t row = 0; row < m_zoomHeight; row++)
{
srcY = static_cast<int>(yRatio * row);
for (int ColorNum = 0; ColorNum < m_header.nImageColorNum; ColorNum++)
{
memset(pSourceLineData, 0, m_header.nBytePerLine);
ReadLine(pSourceLineData, srcY * m_header.nImageColorNum + ColorNum, 0, m_header.nBytePerLine);
for (size_t column = 0; column < m_zoomWidth; column++)
{
srcX = static_cast<int>(xRatio * column);
// 获取源图像的 bit像素值
unsigned char srcValue = getPixel(pSourceLineData, srcX, m_header.nImageColorDeep);
int y = (row * m_header.nImageColorNum + ColorNum) * nTargetLineSize + sizeof(m_header);
// 设置目标图像的2bit像素值
setPixel(pTargetData+y,column, srcValue, m_header.nImageColorDeep);
}
}
}
delete[] pSourceLineData;
}
void CZoomPrtFile::zoomPrtFileparallel(BYTE* pTargetData)
{
std::vector<std::thread> threadPool;
int threadNum = 8;
int step = m_zoomHeight / threadNum;
for (int i = 0; i < threadNum -1; i++)
{
threadPool.push_back(std::thread(&CZoomPrtFile::zoomPrtFileThreadProc, this, pTargetData, i* step,(i+1)* step));
}
zoomPrtFileThreadProc(pTargetData, (threadNum - 1) * step, m_zoomHeight);
for (int i = 0; i < threadNum - 1; i++)
{
threadPool[i].join();
}
}
void CZoomPrtFile::zoomPrtFileThreadProc(BYTE* pTargetData, int start, int endRow)
{
float xRatio = static_cast<float>(m_perWidth - 1) / m_zoomWidth;
float yRatio = static_cast<float>(m_perHeight - 1) / m_zoomHeight;
int srcX = 0, srcY = 0;
int nTargetLineSize = (m_zoomWidth * m_header.nImageColorDeep + 7) / 8;
BYTE* pSourceLineData = new BYTE[m_header.nBytePerLine];
for (size_t row = start; row < endRow; row++)
{
srcY = static_cast<int>(yRatio * row);
for (int ColorNum = 0; ColorNum < m_header.nImageColorNum; ColorNum++)
{
memset(pSourceLineData, 0, m_header.nBytePerLine);
ReadLine(pSourceLineData, srcY * m_header.nImageColorNum + ColorNum, 0, m_header.nBytePerLine);
for (size_t column = 0; column < m_zoomWidth; column++)
{
srcX = static_cast<int>(xRatio * column);
// 获取源图像的 bit像素值
int byteIndex = srcX * m_header.nImageColorDeep / 8; // 字节索引
unsigned char srcValue = getPixel(pSourceLineData[byteIndex], srcX, m_header.nImageColorDeep);
int y = (row * m_header.nImageColorNum + ColorNum) * nTargetLineSize + sizeof(m_header);
// 设置目标图像的2bit像素值
setPixel(pTargetData + y, column, srcValue, m_header.nImageColorDeep);
}
}
}
delete[] pSourceLineData;
}
//
//void CZoomPrtFile::zoomPrtFileThreadProc(BYTE* pTargetData, int ColorNum)
//{
// float xRatio = static_cast<float>(m_perWidth - 1) / m_zoomWidth;
// float yRatio = static_cast<float>(m_perHeight - 1) / m_zoomHeight;
// int srcX = 0, srcY = 0;
//
// int nTargetLineSize = (m_zoomWidth * m_header.nImageColorDeep + 7) / 8;
// BYTE* pSourceLineData = new BYTE[m_header.nBytePerLine];
// for (size_t row = 0; row < m_zoomHeight; row++)
// {
// srcY = static_cast<int>(yRatio * row);
// memset(pSourceLineData, 0, m_header.nBytePerLine);
// ReadLine(pSourceLineData, srcY * m_header.nImageColorNum + ColorNum, 0, m_header.nBytePerLine);
//
// for (size_t column = 0; column < m_zoomWidth; column++)
// {
// srcX = static_cast<int>(xRatio * column);
// // 获取源图像的 bit像素值
// unsigned char srcValue = getPixel(pSourceLineData, srcX, m_header.nImageColorDeep);
// // 设置目标图像的2bit像素值
// int y = (row * m_header.nImageColorNum + ColorNum)* nTargetLineSize + sizeof(m_header);
// setPixel(pTargetData+y, column, srcValue, m_header.nImageColorDeep);
// }
// }
// delete[] pSourceLineData;
// return;
//}
unsigned char CZoomPrtFile::getPixel(unsigned char* data, int x, int nImageColorDeep)
{
//unsigned char存储 8/int nImageColorDeep 个 int nImageColorDeep bit像素 ,其中 nImageColorDeep :1,2,4,8 RIP image output bit per color
int byteIndex = x * nImageColorDeep / 8; // 字节索引
int bitIndex = (x * nImageColorDeep) % 8; // 位索引
// 创建掩码
unsigned char mask = (1 << nImageColorDeep) - 1;
//std::lock_guard<std::mutex> locker(fileMutex);
// 位运算提取像素
unsigned char pixel;
{
std::lock_guard<std::mutex> locker(fileMutex);
pixel = data[byteIndex];
}
pixel = (pixel >> bitIndex) & mask;
return pixel;
}
unsigned char CZoomPrtFile::getPixel(unsigned char data, int x, int nImageColorDeep)
{
//unsigned char存储 8/int nImageColorDeep 个 int nImageColorDeep bit像素 ,其中 nImageColorDeep :1,2,4,8 RIP image output bit per color
int byteIndex = x * nImageColorDeep / 8; // 字节索引
int bitIndex = (x * nImageColorDeep) % 8; // 位索引
// 创建掩码
unsigned char mask = (1 << nImageColorDeep) - 1;
//std::lock_guard<std::mutex> locker(fileMutex);
// 位运算提取像素
unsigned char pixel = (data >> bitIndex) & mask;
return pixel;
}
void CZoomPrtFile::setPixel(unsigned char* data,int x, unsigned char pixel, int nImageColorDeep)
{
//int y = (int64)nLine * nTargetLineSize + sizeof(m_header);
int byteIndex = x * nImageColorDeep / 8;//在第y行的byte的位置
int bitIndex = (x * nImageColorDeep) % 8;
// 创建掩码
unsigned char mask = (1 << nImageColorDeep) - 1;
// 清空原像素
unsigned char temp = data[byteIndex];
temp &= ~(mask << bitIndex);
temp |= (pixel & mask) << bitIndex;
//std::lock_guard<std::mutex> locker(fileMutex);
data[byteIndex] = temp;
//data[byteIndex] &= ~(mask << bitIndex);
设置新像素
//data[ byteIndex] |= (pixel & mask) << bitIndex;
}
bool CZoomPrtFile::writePrtFile(const std::string& prtFile, unsigned char* data, size_t outDataSize)
{
if (data == nullptr) {
return false;
}
//Write file
std::ofstream outFile;
outFile.open(prtFile, std::ofstream::binary);
if (!outFile.is_open()) {
return false;
}
for (size_t i = 0; i < outDataSize; i++) {
outFile << data[i];
}
outFile.close();
return true;
}
main
cpp
#include "CZoomPrtFile.h"
#include <iostream>
#include <fstream>
#include"base.h"
using namespace std;
void test()
{
std::ifstream ifs("D:\\doc\\prt\\1111111.prn");
if (!ifs.is_open())
{
return;
}
ifs.seekg(0, ios_base::end); //先把文件输入流指针定位到文档末尾来获取文档的长度
int length = ifs.tellg();
cout << " 1111111.prn size is " << length << endl;
}
int main()
{
test();
CZoomPrtFile zoomPrtFile;
zoomPrtFile.Open(L"D:\\doc\\prt\\1111111.prn");
cout << " test 单线程"<< endl;
zoomPrtFile.saveZoomPrtFile("D:\\doc\\prt\\1111111Zoom05.prn", 3259 * 0.5, 4605 * 0.5);
zoomPrtFile.saveZoomPrtFile("D:\\doc\\prt\\1111111Zoom08.prn", 3259 * 0.8, 4605 * 0.8);
zoomPrtFile.saveZoomPrtFile("D:\\doc\\prt\\1111111Zoom15.prn", 3259 * 1.5, 4605 * 1.5);
zoomPrtFile.saveZoomPrtFile("D:\\doc\\prt\\1111111Zoom20.prn", 3259 * 2, 4605 * 2);
return 0;
}
/*
处理的速度要到至少500MB/S
test 多线程 8个线程
D:\doc\prt\1111111Zoom05.prn . Total Time Taken = 769 milliseconds . source size = 26303844 byte target file size = 6574596,
D:\doc\prt\1111111Zoom08.prn . Total Time Taken = 1738 milliseconds . source size = 26303844 byte target file size = 16813860
D:\doc\prt\1111111Zoom15.prn . Total Time Taken = 5812 milliseconds . source size = 26303844 byte target file size = 59082562
D:\doc\prt\1111111Zoom20.prn . Total Time Taken = 10308 milliseconds . source size = 26303844 byte target file size = 105086184
test 单线程
D:\doc\prt\1111111Zoom05.prn . Total Time Taken = 1926 milliseconds . source size = 26303844 byte . target file size = 6574596
D:\doc\prt\1111111Zoom08.prn . Total Time Taken = 4626 milliseconds . source size = 26303844 byte . target file size = 16813860
D:\doc\prt\1111111Zoom15.prn . Total Time Taken = 16128 milliseconds . source size = 26303844 byte . target file size = 59082562
D:\doc\prt\1111111Zoom20.prn . Total Time Taken = 28593 milliseconds . source size = 26303844 byte . target file size = 105086184
*/