#include "pch.h" #include "Mem\CImageBuf.h" #include #include "GdCpp.h" //#include "json.h" #include "aLog.h" #include // FILE, _wfopen_s, fwrite, fclose // 颜色类型与BPP的对应关系 std::map sImageInfo::MapColor2BBP; // 颜色类型与BPP的对应关系 std::map sImageInfo::MapBBP2Color; static RGBQUAD bmiColors[256] = { 0 }; bool CImageBuf::saveBMP(const wchar_t* filename) { if (!filename) return false; FILE* f = nullptr; errno_t err = _wfopen_s(&f, filename, L"wb"); // 二进制写入,覆盖创建 if (err != 0 || !f) { return false; } bool ret = false; do { BITMAPFILEHEADER fileheader = {}; BITMAPINFOHEADER infoheader = {}; static const char _blank[2] = { 0 }; // 填充信息头 infoheader.biSize = sizeof(BITMAPINFOHEADER); infoheader.biWidth = Width; infoheader.biHeight = -Height; // top-down BMP infoheader.biPlanes = 1; infoheader.biBitCount = BPP * 8; infoheader.biCompression = BI_RGB; // 0 = BI_RGB infoheader.biSizeImage = LineSize * Height; infoheader.biXPelsPerMeter = 3780; infoheader.biYPelsPerMeter = 3780; infoheader.biClrUsed = 0; infoheader.biClrImportant = 0; // 文件头 fileheader.bfType = 0x4D42; // 'BM' = 19778 fileheader.bfReserved1 = 0; fileheader.bfReserved2 = 0; // 计算像素数据偏移 if (BPP == 3) { fileheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 2; // +2 for alignment } else if (BPP == 1) { fileheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD) + 2; } else { // 不支持的 BPP break; } fileheader.bfSize = fileheader.bfOffBits + infoheader.biSizeImage; // 写入文件头 if (fwrite(&fileheader, sizeof(fileheader), 1, f) != 1) break; if (fwrite(&infoheader, sizeof(infoheader), 1, f) != 1) break; // 写入调色板(仅 8-bit) if (BPP == 1) { if (bmiColors[255].rgbRed == 0) { for (int i = 0; i < 256; i++) { bmiColors[i].rgbRed = (BYTE)i; bmiColors[i].rgbGreen = (BYTE)i; bmiColors[i].rgbBlue = (BYTE)i; bmiColors[i].rgbReserved = 0; } } if (fwrite(bmiColors, sizeof(RGBQUAD), 256, f) != 256) break; } // 写入对齐填充(2 字节) if (fwrite(_blank, sizeof(_blank), 1, f) != 1) break; // 写入像素数据 if (fwrite(Addr(), 1, infoheader.biSizeImage, f) != infoheader.biSizeImage) break; ret = true; } while (0); // 错误处理:记录失败原因(可选) if (!ret) { alog->error(L"Failed to write BMP file: {}", filename); } if (f) fclose(f); return ret; } // 保存原始数据 bool CImageBuf::saveRaw(std::wstring& filename) { if (filename.empty()) return false; FILE* f = nullptr; errno_t err = _wfopen_s(&f, filename.c_str(), L"wb"); if (err != 0 || !f) { return false; } size_t written = fwrite(Addr(), 1, ImageSize, f); fclose(f); return (written == ImageSize); } // 从 std::wstring 加载原始数据 bool CImageBuf::loadRaw(std::wstring& filename) { if (filename.empty()) return false; FILE* f = nullptr; errno_t err = _wfopen_s(&f, filename.c_str(), L"rb"); if (err != 0 || !f) { return false; } size_t read = fread(Addr(), 1, ImageSize, f); fclose(f); return (read == ImageSize); } // 从 const wchar_t* 加载原始数据 bool CImageBuf::loadRaw(const wchar_t* filename) { if (!filename) return false; FILE* f = nullptr; errno_t err = _wfopen_s(&f, filename, L"rb"); if (err != 0 || !f) { return false; } size_t read = fread(Addr(), 1, ImageSize, f); fclose(f); return (read == ImageSize); } void CImageBuf::debugCopyErr(int err, const char* exinfo) { /*switch(err){ case Ok: break; case Err_DstWidth: qsError() << exinfo << "dest w is larger than width"; break; case Err_DstHeight: qsError() << exinfo << "dest y is larger than height"; break; case Warn_CropWidth: qsWarn() << exinfo << "image is croped in width"; break; case Warn_CropHeight: qsWarn() << exinfo << "image is croped in height"; break; }*/ } ///将来源目标图像缓冲区的(sx,sy,sw,sh)区域的数据复制到目标图像缓冲区的(dx,dy)处。两者的bpp必须相同 int CImageBuf::copy(CImageBuf* src, int sx, int sy, int sw, int sh, CImageBuf* dst, int dx, int dy, const char* debugstr) { int ret = 0; uint8_t* sp = src->getAddr(sx, sy); uint8_t* dp = dst->getAddr(dx, dy); int dw = dst->Width - dx; //目标缓冲区可写的宽度 int dh = dst->Height - dy; //目标缓冲区可写的高度 do { if (dw <= 0) { ret = Err_DstWidth; //dx超出了目标缓冲区的范围 break; } if (dh <= 0) { ret = Err_DstHeight; //dy超出了目标缓冲区的范围 break; } //判断宽度是否超出 if (sw > dw) { sw = dw; ret = Warn_CropWidth; } if (sh > dh) { sh = dh; ret = Warn_CropHeight; } size_t line = size_t(sw * src->BPP); for (int h = 0; h < sh; h++) { memcpy(dp, sp, line); sp += src->LineSize; dp += dst->LineSize; } } while (0); if (debugstr) { debugCopyErr(ret, debugstr); } return ret; } int CImageBuf::copy(CImageBuf* src, int sx, int sy, int sw, int sh, uint8_t* dst) { int ret = 0; uint8_t* sp = src->getAddr(sx, sy); uint8_t* dp = dst; do { size_t line = size_t(sw * src->BPP); for (int h = 0; h < sh; h++) { memcpy(dp, sp, line); sp += src->LineSize; dp += line; } } while (0); return ret; } /// buf1,buf2数值相加平均写到dst,长度为line static void meanline(uint8_t* buf1, uint8_t* buf2, uint8_t* dst, int line) { for (int i = 0; i < line; i++) { *dst++ = uint8_t((uint32_t(*buf1++) + uint32_t(*buf2++)) / 2); } } ///叠加图片,颜色值各取1/2 int CImageBuf::overlay(CImageBuf* src, int sx, int sy, int sw, int sh, CImageBuf* dst, int dx, int dy, const char* debugstr) { int ret = 0; uint8_t* sp = src->getAddr(sx, sy); uint8_t* dp = dst->getAddr(dx, dy); int dw = dst->Width - dx; //目标缓冲区可写的宽度 int dh = dst->Height - dy; //目标缓冲区可写的高度 do { if (dw <= 0) { ret = Err_DstWidth; //dx超出了目标缓冲区的范围 break; } if (dh <= 0) { ret = Err_DstHeight; //dy超出了目标缓冲区的范围 break; } //判断宽度是否超出 if (sw > dw) { sw = dw; ret = Warn_CropWidth; } if (sh > dh) { sh = dh; ret = Warn_CropHeight; } size_t line = size_t(sw * src->BPP); // 创建临时行 uint8_t* tmpline = new uint8_t[size_t(line)]; for (int h = 0; h < sh; h++) { meanline(dp, sp, dp, int(line)); sp += src->LineSize; dp += dst->LineSize; } delete[] tmpline; } while (0); if (debugstr) { debugCopyErr(ret, debugstr); } return ret; } void CImageBuf::fill4(uint32_t val) { auto* pline = Addr(); switch (BPP) { case 1: { //一次算4个像素 val &= 0xFF; uint32_t v = val | val << 8 | val << 16 | val << 24; for (int h = 0; h < Height; h++) { auto p = (uint32_t*)pline; for (int i = 0; i < Width / 4; i++) *p++ = v; pline += LineSize; } break; } case 3: { //一次算4个像素 val &= 0xFFFFFF; uint32_t v1 = val | val << 24; uint32_t v2 = (val >> 8) | (val << 16); uint32_t v3 = (val >> 16) | (val << 8); for (int h = 0; h < Height; h++) { auto p = (uint32_t*)pline; for (int i = 0; i < Width / 4; i++) { *p++ = v1; *p++ = v2; *p++ = v3; } pline += LineSize; } break; } case 4: {//一次算1个像素 for (int h = 0; h < Height; h++) { auto p = (uint32_t*)pline; for (int i = 0; i < Width; i++) *p++ = val; pline += LineSize; } break; } } } /// 填充颜色,要求4像素对齐 void CImageBuf::fill4(uint32_t val, int x, int y, int W, int H) { auto* pline = getAddr(x, y); switch (BPP) { case 1: { //一次算4个像素 val &= 0xFF; uint32_t v = val | val << 8 | val << 16 | val << 24; for (int h = 0; h < H; h++) { auto p = (uint32_t*)pline; for (int i = 0; i < W / 4; i++) *p++ = v; pline += LineSize; } break; } case 3: { //一次算4个像素 val &= 0xFFFFFF; uint32_t v1 = val | val << 24; uint32_t v2 = (val >> 8) | (val << 16); uint32_t v3 = (val >> 16) | (val << 8); for (int h = 0; h < H; h++) { auto p = (uint32_t*)pline; for (int i = 0; i < W / 4; i++) { *p++ = v1; *p++ = v2; *p++ = v3; } pline += LineSize; } break; } case 4: {//一次算1个像素 for (int h = 0; h < H; h++) { auto p = (uint32_t*)pline; for (int i = 0; i < W; i++) *p++ = val; pline += LineSize; } break; } } } //cv::Mat toMat(const CImageBuf& img) //{ // switch (img.BytePerPix) // { // case 1: // return cv::Mat(img.Height, img.Width, CV_8UC1, img.Addr, img.LineSize); // case 2: // return cv::Mat(img.Height, img.Width, CV_8UC2, img.Addr, img.LineSize); // case 3: // return cv::Mat(img.Height, img.Width, CV_8UC3, img.Addr, img.LineSize); // case 4: // return cv::Mat(img.Height, img.Width, CV_8UC4, img.Addr, img.LineSize); // default: // return cv::Mat(); // } //}