15,440
社区成员
发帖
与我相关
我的任务
分享
VBuf *BmpHandleToPngByte(HBITMAP hBmp)
{
BITMAP bmp;
BITMAPINFO *bmi = NULL;
int palette, total_size, header_size, data_size, line_size;
HWND hWnd = ::GetDesktopWindow();
HDC hDc = NULL;
VBuf bmpVbuf;
png_struct *png = NULL;
png_info *info = NULL;
png_color_8 sbit;
png_byte **lines = NULL;
VBuf *vbuf = NULL, *ret = NULL;
if (!::GetObject(hBmp, sizeof(bmp), &bmp)) return NULL;
//if (bmp.bmBitsPixel < 24)
bmp.bmBitsPixel = 24;
line_size = bmp.bmWidth * ALIGN_SIZE(bmp.bmBitsPixel, 8) / 8;
line_size = ALIGN_SIZE(line_size, 4);
data_size = line_size * bmp.bmHeight;
palette = bmp.bmBitsPixel <= 8 ? 1 << bmp.bmBitsPixel : 0;
header_size = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * palette;
total_size = header_size + data_size;
if (!bmpVbuf.AllocBuf(total_size)) return NULL;
bmi = (BITMAPINFO *)bmpVbuf.Buf();
bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi->bmiHeader.biWidth = bmp.bmWidth;
bmi->bmiHeader.biHeight = bmp.bmHeight;
bmi->bmiHeader.biPlanes = 1;
bmi->bmiHeader.biBitCount = bmp.bmBitsPixel;
bmi->bmiHeader.biCompression = BI_RGB;
bmi->bmiHeader.biClrUsed = palette;
bmi->bmiHeader.biClrImportant = palette;
if (!(hDc = ::GetDC(hWnd)) ||
!::GetDIBits(hDc, hBmp, 0, bmp.bmHeight, (char *)bmi + header_size, bmi, DIB_RGB_COLORS)) {
goto END;
}
if (!(png = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0))) return NULL;
if (!(info = png_create_info_struct(png))) goto END;
if (!(vbuf = new VBuf(0, total_size))) goto END;
png_set_write_fn(png, (void *)vbuf, (png_rw_ptr)png_vbuf_wfunc,
(png_flush_ptr)png_vbuf_wflush);
if (palette) {
png_color png_palette[256];
for (int i=0; i < palette; i++) {
png_palette[i].red = bmi->bmiColors[i].rgbRed;
png_palette[i].green = bmi->bmiColors[i].rgbGreen;
png_palette[i].blue = bmi->bmiColors[i].rgbBlue;
}
png_set_IHDR(png, info, bmp.bmWidth, bmp.bmHeight, bmp.bmBitsPixel,
PNG_COLOR_TYPE_PALETTE,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
png_set_PLTE(png, info, png_palette, palette);
}
else {
png_set_IHDR(png, info, bmp.bmWidth, bmp.bmHeight, 8,
bmp.bmBitsPixel > 24 ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
}
sbit.red = sbit.green = sbit.blue = 8;
sbit.alpha = bmp.bmBitsPixel > 24 ? 8 : 0;
png_set_sBIT(png, info, &sbit);
if (setjmp(png_jmpbuf(png))) {
goto END;
}
else {
png_write_info(png, info);
png_set_bgr(png);
lines = (png_byte **)malloc(sizeof(png_bytep *) * bmp.bmHeight);
for (int i = 0; i < bmp.bmHeight; i++) {
lines[i] = bmpVbuf.Buf() + header_size + line_size * (bmp.bmHeight - i - 1);
}
png_write_image(png, lines);
png_write_end(png, info);
ret = vbuf;
}
END:
if (png) png_destroy_write_struct(&png, &info);
if (hDc) ::ReleaseDC(hWnd, hDc);
if (lines) free(lines);
if (!ret && vbuf) delete vbuf;
return ret;
}