前情提要
这里实现了打印文件的缩放算法 缩放打印文件(prt,prn)
核心功能如下:
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;
}
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;
}
使用sse 128
void CZoomPrtFile::zoomPrtFileSSE128(BYTE* pTargetData)
{
const float xRatio = static_cast<float>(m_perWidth - 1) / m_zoomWidth;
const float yRatio = static_cast<float>(m_perHeight - 1) / m_zoomHeight;
__m128 xmmRatio = _mm_set1_ps(xRatio);
__m128 ymmRatio = _mm_set1_ps(yRatio);
__m128i colorDeep = _mm_set1_epi32(m_header.nImageColorDeep);
__m128i bitMask = _mm_set1_epi8(0x07);
unsigned char mask = (1 << m_header.nImageColorNum) - 1;
__m128i mmMask = _mm_set1_epi32(mask);
BYTE* pSourceLineData = new BYTE[m_header.nBytePerLine];
int nTargetLineSize = (m_zoomWidth * m_header.nImageColorDeep + 7) / 8;
for (int row = 0; row < m_zoomHeight; row++)
{
int 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 (int column = 0; column < m_zoomWidth; column+=4)
{
// 加载128位值。返回值代表寄存器的变量中的相同值,地址p不需要16字节对齐。
__m128i xmmColumn = _mm_setr_epi32(column, column + 1, column + 2, column + 3);
// 列索引转换为浮点数
__m128 xmmColumnF = _mm_cvtepi32_ps(xmmColumn);
// 乘以缩放比例 转换为整数
__m128i xmmSrcXInt = _mm_cvttps_epi32(_mm_mul_ps(xmmColumnF, xmmRatio));
//原图
xmmSrcXInt = _mm_mullo_epi32(xmmSrcXInt, colorDeep);
// 方法1:右移三位实现除以8
__m128i xmmSrcXByteIndex = _mm_srli_epi32(xmmSrcXInt, 3);// 字节索引
__m128i xmmSrcXBitIndex = _mm_and_si128(xmmSrcXInt, bitMask);// 位索引
//目标图
__m128i xmmDesX = _mm_mullo_epi32(xmmColumn, colorDeep);//位索引
__m128i xmmDesXByteIndex = _mm_srli_epi32(xmmDesX, 3);// 字节索引
__m128i xmmDesXBitIndex = _mm_and_si128(xmmDesX, bitMask);// 位索引
//源数据
alignas(16) int srcXByteIndex[4];//
_mm_store_si128((__m128i*)srcXByteIndex, xmmSrcXByteIndex);
alignas(16) int srcXBitIndex[4];//
_mm_store_si128((__m128i*)srcXBitIndex, xmmSrcXBitIndex);
unsigned char pixel[4]{
(pSourceLineData[srcXByteIndex[0]] >> srcXBitIndex[0])& mask,
(pSourceLineData[srcXByteIndex[1]] >> srcXBitIndex[1])& mask,
(pSourceLineData[srcXByteIndex[2]] >> srcXBitIndex[2])& mask,
(pSourceLineData[srcXByteIndex[3]] >> srcXBitIndex[3])& mask
};
//目标数据
int y = (row * m_header.nImageColorNum + ColorNum) * nTargetLineSize + sizeof(m_header);
BYTE* desDataPointer = pTargetData + y;
alignas(16) int DesXByteIndex[4];
_mm_store_si128((__m128i*)DesXByteIndex, xmmDesXByteIndex);
alignas(16) int DesXBitIndex[4];//
_mm_store_si128((__m128i*)DesXBitIndex, xmmDesXBitIndex);
desDataPointer[DesXByteIndex[0]] = (desDataPointer[DesXByteIndex[0]] & ~(mask << DesXBitIndex[0])) |
((pixel[0] /*& mask*/ ) << DesXBitIndex[0]);
desDataPointer[DesXByteIndex[1]] = (desDataPointer[DesXByteIndex[1]] & ~(mask << DesXBitIndex[1])) |
((pixel[1] /*& mask*/) << DesXBitIndex[1]);
desDataPointer[DesXByteIndex[2]] = (desDataPointer[DesXByteIndex[2]] & ~(mask << DesXBitIndex[2])) |
((pixel[2] /*& mask*/) << DesXBitIndex[2]);
desDataPointer[DesXByteIndex[3]] = (desDataPointer[DesXByteIndex[3]] & ~(mask << DesXBitIndex[3])) |
((pixel[3] /*& mask*/) << DesXBitIndex[3]);
}
}
}
}
本来提取像素和设置像素都应该用sse写的,但是折磨了chatgpt好几天 也没有写出来。
所以这里仅用sse优化 源数据以及目标数据坐标的计算
即使是这样优化效果也很好