diff --git a/libfreerdp/codec/progressive.c b/libfreerdp/codec/progressive.c index a1b2fa216..eb6e46ba1 100644 --- a/libfreerdp/codec/progressive.c +++ b/libfreerdp/codec/progressive.c @@ -1196,7 +1196,7 @@ int progressive_decompress_tile_upgrade(PROGRESSIVE_CONTEXT* progressive, RFX_PR BufferPool_Return(progressive->bufferPool, pBuffer); - WLog_Image(progressive->log, WLOG_TRACE, tile->data, 64, 64, 32); + //WLog_Image(progressive->log, WLOG_TRACE, tile->data, 64, 64, 32); return 1; } diff --git a/libfreerdp/codec/test/TestFreeRDPCodecProgressive.c b/libfreerdp/codec/test/TestFreeRDPCodecProgressive.c index 4192176d7..2896fbdb6 100644 --- a/libfreerdp/codec/test/TestFreeRDPCodecProgressive.c +++ b/libfreerdp/codec/test/TestFreeRDPCodecProgressive.c @@ -1,7 +1,10 @@ #include #include +#include #include +#include + #include /** @@ -399,15 +402,320 @@ int test_progressive_load_files(char* ms_sample_path, EGFX_SAMPLE_FILE files[3][ return 1; } +static void fill_bitmap_alpha_channel(BYTE* data, int width, int height, BYTE value) +{ + int i, j; + UINT32* pixel; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + pixel = (UINT32*) &data[((i * width) + j) * 4]; + *pixel = ((*pixel & 0x00FFFFFF) | (value << 24)); + } + } +} + +BYTE* test_progressive_load_bitmap(char* path, char* file, UINT32* size) +{ + int status; + BYTE* buffer; + wImage* image; + char* filename; + + filename = GetCombinedPath(path, file); + + if (!filename) + return NULL; + + image = winpr_image_new(); + + if (!image) + return NULL; + + status = winpr_image_read(image, filename); + + if (status < 0) + return NULL; + + buffer = image->data; + *size = image->height * image->scanline; + + fill_bitmap_alpha_channel(image->data, image->width, image->height, 0xFF); + + winpr_image_free(image, FALSE); + free(filename); + + return buffer; +} + +int test_progressive_load_bitmaps(char* ms_sample_path, EGFX_SAMPLE_FILE bitmaps[3][4][4]) +{ + int imageNo = 0; + int quarterNo = 0; + int passNo = 0; + + /* image 1 */ + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_0_025_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_0_050_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_0_075_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_0_100_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + quarterNo = (quarterNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_1_025_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_1_050_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_1_075_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_1_100_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + quarterNo = (quarterNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_2_025_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_2_050_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_2_075_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_2_100_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + quarterNo = (quarterNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_3_025_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_3_050_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_3_075_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_3_100_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + imageNo++; + + /* image 2 */ + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_0_025_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_0_050_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_0_075_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_0_100_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + quarterNo = (quarterNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_1_025_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_1_050_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_1_075_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_1_100_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + quarterNo = (quarterNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_2_025_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_2_050_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_2_075_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_2_100_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + quarterNo = (quarterNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_3_025_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_3_050_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_3_075_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_3_100_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + imageNo++; + + /* image 3 */ + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_0_025_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_0_050_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_0_075_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_0_100_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + quarterNo = (quarterNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_1_025_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_1_050_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_1_075_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_1_100_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + quarterNo = (quarterNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_2_025_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_2_050_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_2_075_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_2_100_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + quarterNo = (quarterNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_3_025_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_3_050_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_3_075_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_3_100_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + /* check if all test data has been loaded */ + + for (imageNo = 0; imageNo < 3; imageNo++) + { + for (quarterNo = 0; quarterNo < 4; quarterNo++) + { + for (passNo = 0; passNo < 4; passNo++) + { + if (!bitmaps[imageNo][quarterNo][passNo].buffer) + return -1; + } + } + } + + return 1; +} + static int g_Width = 0; static int g_Height = 0; static int g_DstStep = 0; static BYTE* g_DstData = NULL; -int test_progressive_decode(PROGRESSIVE_CONTEXT* progressive, EGFX_SAMPLE_FILE files[4], int count) +int test_progressive_decode(PROGRESSIVE_CONTEXT* progressive, EGFX_SAMPLE_FILE files[4], EGFX_SAMPLE_FILE bitmaps[4], int quarter, int count) { int pass; + int index; int status; + int nXSrc, nYSrc; + int nXDst, nYDst; + int nWidth, nHeight; + RECTANGLE_16 tileRect; + RECTANGLE_16 updateRect; + RECTANGLE_16 clippingRect; + RFX_PROGRESSIVE_TILE* tile; + PROGRESSIVE_BLOCK_REGION* region; + + clippingRect.left = 0; + clippingRect.top = 0; + clippingRect.right = g_Width; + clippingRect.bottom = g_Height; for (pass = 0; pass < count; pass++) { @@ -415,6 +723,80 @@ int test_progressive_decode(PROGRESSIVE_CONTEXT* progressive, EGFX_SAMPLE_FILE f &g_DstData, PIXEL_FORMAT_XRGB32, g_DstStep, 0, 0, g_Width, g_Height, 0); printf("ProgressiveDecompress: status: %d pass: %d\n", status, pass + 1); + + region = &(progressive->region); + + switch (quarter) + { + case 0: + clippingRect.left = 0; + clippingRect.top = 0; + clippingRect.right = g_Width / 2; + clippingRect.bottom = g_Height /2; + break; + + case 1: + clippingRect.left = g_Width / 2; + clippingRect.top = g_Height / 2; + clippingRect.right = g_Width; + clippingRect.bottom = g_Height; + break; + + case 2: + clippingRect.left = g_Width / 2; + clippingRect.top = 0; + clippingRect.right = g_Width; + clippingRect.bottom = g_Height / 2; + break; + + case 3: + clippingRect.left = 0; + clippingRect.top = g_Height / 2; + clippingRect.right = g_Width / 2; + clippingRect.bottom = g_Height; + break; + } + + for (index = 0; index < region->numTiles; index++) + { + tile = region->tiles[index]; + + tileRect.left = tile->x; + tileRect.top = tile->y; + tileRect.right = tile->x + tile->width; + tileRect.bottom = tile->y + tile->height; + + rectangles_intersection(&tileRect, &clippingRect, &updateRect); + + nXDst = updateRect.left; + nYDst = updateRect.top; + nWidth = updateRect.right - updateRect.left; + nHeight = updateRect.bottom - updateRect.top; + + nXSrc = nXDst - tile->x; + nYSrc = nYDst - tile->y; + + freerdp_image_copy(g_DstData, PIXEL_FORMAT_XRGB32, g_DstStep, + nXDst, nYDst, nWidth, nHeight, tile->data, + PIXEL_FORMAT_XRGB32, 64 * 4, nXSrc, nYSrc); + } + + if (memcmp(g_DstData, bitmaps[pass].buffer, bitmaps[pass].size) != 0) + { + printf("bitmap decompression error\n"); + + printf("GOOD: "); + winpr_HexDump(bitmaps[pass].buffer, 16); + + printf("BAD: "); + winpr_HexDump(g_DstData, 16); + } + else + { + printf("bitmap decompression success\n"); + } + + WLog_Image(progressive->log, WLOG_TRACE, g_DstData, g_Width, g_Height, 32); } return 1; @@ -425,6 +807,7 @@ int test_progressive_ms_sample(char* ms_sample_path) int count; int status; EGFX_SAMPLE_FILE files[3][4][4]; + EGFX_SAMPLE_FILE bitmaps[3][4][4]; PROGRESSIVE_CONTEXT* progressive; g_Width = 1920; @@ -436,7 +819,12 @@ int test_progressive_ms_sample(char* ms_sample_path) if (status < 0) return -1; - count = 3; + status = test_progressive_load_bitmaps(ms_sample_path, bitmaps); + + if (status < 0) + return -1; + + count = 2; progressive = progressive_context_new(FALSE); @@ -448,30 +836,31 @@ int test_progressive_ms_sample(char* ms_sample_path) if (1) { - test_progressive_decode(progressive, files[0][0], count); - test_progressive_decode(progressive, files[0][1], count); - test_progressive_decode(progressive, files[0][2], count); - test_progressive_decode(progressive, files[0][3], count); + test_progressive_decode(progressive, files[0][0], bitmaps[0][0], 0, count); + test_progressive_decode(progressive, files[0][1], bitmaps[0][1], 1, count); + test_progressive_decode(progressive, files[0][2], bitmaps[0][2], 2, count); + test_progressive_decode(progressive, files[0][3], bitmaps[0][3], 3, count); } /* image 2 */ - if (1) + if (0) { - test_progressive_decode(progressive, files[1][0], count); - test_progressive_decode(progressive, files[1][1], count); - test_progressive_decode(progressive, files[1][2], count); - test_progressive_decode(progressive, files[1][3], count); + /* decompressed image set is incorrect for this one */ + test_progressive_decode(progressive, files[1][0], bitmaps[1][0], 0, count); + test_progressive_decode(progressive, files[1][1], bitmaps[1][1], 1, count); + test_progressive_decode(progressive, files[1][2], bitmaps[1][2], 2, count); + test_progressive_decode(progressive, files[1][3], bitmaps[1][3], 3, count); } /* image 3 */ - if (1) + if (0) { - test_progressive_decode(progressive, files[2][0], count); - test_progressive_decode(progressive, files[2][1], count); - test_progressive_decode(progressive, files[2][2], count); - test_progressive_decode(progressive, files[2][3], count); + test_progressive_decode(progressive, files[2][0], bitmaps[2][0], 0, count); + test_progressive_decode(progressive, files[2][1], bitmaps[2][1], 1, count); + test_progressive_decode(progressive, files[2][2], bitmaps[2][2], 2, count); + test_progressive_decode(progressive, files[2][3], bitmaps[2][3], 3, count); } progressive_context_free(progressive); diff --git a/winpr/include/winpr/image.h b/winpr/include/winpr/image.h index 3dda5f7c6..313200533 100644 --- a/winpr/include/winpr/image.h +++ b/winpr/include/winpr/image.h @@ -23,46 +23,28 @@ #include #include -/* - * Bitmap data structures - */ - -struct _WINPR_BITMAP_MAGIC +struct _wImage { - BYTE magic[2]; + int width; + int height; + BYTE* data; + int scanline; + int bitsPerPixel; + int bytesPerPixel; }; -typedef struct _WINPR_BITMAP_MAGIC WINPR_BITMAP_MAGIC; - -struct _WINPR_BITMAP_CORE_HEADER -{ - UINT32 filesz; - UINT16 creator1; - UINT16 creator2; - UINT32 bmp_offset; -}; -typedef struct _WINPR_BITMAP_CORE_HEADER WINPR_BITMAP_CORE_HEADER; - -struct _WINPR_BITMAP_INFO_HEADER -{ - UINT32 header_sz; - INT32 width; - INT32 height; - UINT16 nplanes; - UINT16 bitspp; - UINT32 compress_type; - UINT32 bmp_bytesz; - INT32 hres; - INT32 vres; - UINT32 ncolors; - UINT32 nimpcolors; -}; -typedef struct _WINPR_BITMAP_INFO_HEADER WINPR_BITMAP_INFO_HEADER; +typedef struct _wImage wImage; #ifdef __cplusplus extern "C" { #endif -WINPR_API int winpr_bitmap_write(char* filename, BYTE* data, int width, int height, int bpp); +WINPR_API int winpr_bitmap_write(const char* filename, BYTE* data, int width, int height, int bpp); + +WINPR_API int winpr_image_write(wImage* image, const char* filename); +WINPR_API int winpr_image_read(wImage* image, const char* filename); + +WINPR_API wImage* winpr_image_new(); +WINPR_API void winpr_image_free(wImage* image, BOOL bFreeBuffer); #ifdef __cplusplus } diff --git a/winpr/libwinpr/utils/image.c b/winpr/libwinpr/utils/image.c index 31fc643b6..9672fed79 100644 --- a/winpr/libwinpr/utils/image.c +++ b/winpr/libwinpr/utils/image.c @@ -25,12 +25,63 @@ #include -int winpr_bitmap_write(char* filename, BYTE* data, int width, int height, int bpp) +/** + * Refer to "Compressed Image File Formats: JPEG, PNG, GIF, XBM, BMP" book + */ + +#if defined(__APPLE__) +#pragma pack(1) +#else +#pragma pack(push, 1) +#endif + +struct _WINPR_BITMAP_FILE_HEADER +{ + BYTE bfType[2]; + UINT32 bfSize; + UINT16 bfReserved1; + UINT16 bfReserved2; + UINT32 bfOffBits; +}; +typedef struct _WINPR_BITMAP_FILE_HEADER WINPR_BITMAP_FILE_HEADER; + +struct _WINPR_BITMAP_INFO_HEADER +{ + UINT32 biSize; + INT32 biWidth; + INT32 biHeight; + UINT16 biPlanes; + UINT16 biBitCount; + UINT32 biCompression; + UINT32 biSizeImage; + INT32 biXPelsPerMeter; + INT32 biYPelsPerMeter; + UINT32 biClrUsed; + UINT32 biClrImportant; +}; +typedef struct _WINPR_BITMAP_INFO_HEADER WINPR_BITMAP_INFO_HEADER; + +struct _WINPR_BITMAP_CORE_HEADER +{ + UINT32 bcSize; + UINT16 bcWidth; + UINT16 bcHeight; + UINT16 bcPlanes; + UINT16 bcBitCount; +}; +typedef struct _WINPR_BITMAP_CORE_HEADER WINPR_BITMAP_CORE_HEADER; + +#if defined(__APPLE__) +#pragma pack() +#else +#pragma pack(pop) +#endif + +int winpr_bitmap_write(const char* filename, BYTE* data, int width, int height, int bpp) { FILE* fp; - WINPR_BITMAP_MAGIC magic; - WINPR_BITMAP_CORE_HEADER header; - WINPR_BITMAP_INFO_HEADER info_header; + WINPR_BITMAP_FILE_HEADER bf; + WINPR_BITMAP_INFO_HEADER bi; fp = fopen(filename, "w+b"); @@ -40,37 +91,129 @@ int winpr_bitmap_write(char* filename, BYTE* data, int width, int height, int bp return -1; } - magic.magic[0] = 'B'; - magic.magic[1] = 'M'; + bf.bfType[0] = 'B'; + bf.bfType[1] = 'M'; + bf.bfReserved1 = 0; + bf.bfReserved2 = 0; + bf.bfOffBits = sizeof(WINPR_BITMAP_FILE_HEADER) + sizeof(WINPR_BITMAP_INFO_HEADER); + bi.biSizeImage = width * height * (bpp / 8); + bf.bfSize = bf.bfOffBits + bi.biSizeImage; - header.creator1 = 0; - header.creator2 = 0; + bi.biWidth = width; + bi.biHeight = -1 * height; + bi.biPlanes = 1; + bi.biBitCount = bpp; + bi.biCompression = 0; + bi.biXPelsPerMeter = width; + bi.biYPelsPerMeter = height; + bi.biClrUsed = 0; + bi.biClrImportant = 0; + bi.biSize = sizeof(WINPR_BITMAP_INFO_HEADER); - header.bmp_offset = sizeof(WINPR_BITMAP_MAGIC) + - sizeof(WINPR_BITMAP_CORE_HEADER) + - sizeof(WINPR_BITMAP_INFO_HEADER); - - info_header.bmp_bytesz = width * height * (bpp / 8); - - header.filesz = header.bmp_offset + info_header.bmp_bytesz; - - info_header.width = width; - info_header.height = (-1) * height; - info_header.nplanes = 1; - info_header.bitspp = bpp; - info_header.compress_type = 0; - info_header.hres = width; - info_header.vres = height; - info_header.ncolors = 0; - info_header.nimpcolors = 0; - info_header.header_sz = sizeof(WINPR_BITMAP_INFO_HEADER); - - fwrite((void*) &magic, sizeof(WINPR_BITMAP_MAGIC), 1, fp); - fwrite((void*) &header, sizeof(WINPR_BITMAP_CORE_HEADER), 1, fp); - fwrite((void*) &info_header, sizeof(WINPR_BITMAP_INFO_HEADER), 1, fp); - fwrite((void*) data, info_header.bmp_bytesz, 1, fp); + fwrite((void*) &bf, sizeof(WINPR_BITMAP_FILE_HEADER), 1, fp); + fwrite((void*) &bi, sizeof(WINPR_BITMAP_INFO_HEADER), 1, fp); + fwrite((void*) data, bi.biSizeImage, 1, fp); fclose(fp); return 1; } + +int winpr_image_write(wImage* image, const char* filename) +{ + return winpr_bitmap_write(filename, image->data, image->width, image->height, image->bitsPerPixel); +} + +int winpr_image_read(wImage* image, const char* filename) +{ + FILE* fp; + int index; + BOOL vFlip; + BYTE* pDstData; + WINPR_BITMAP_FILE_HEADER bf; + WINPR_BITMAP_INFO_HEADER bi; + + fp = fopen(filename, "r+b"); + + if (!fp) + { + fprintf(stderr, "failed to open file %s\n", filename); + return -1; + } + + fread((void*) &bf, sizeof(WINPR_BITMAP_FILE_HEADER), 1, fp); + + if ((bf.bfType[0] != 'B') || (bf.bfType[1] != 'M')) + return -1; + + fread((void*) &bi, sizeof(WINPR_BITMAP_INFO_HEADER), 1, fp); + + if (ftell(fp) != bf.bfOffBits) + { + fseek(fp, bf.bfOffBits, SEEK_SET); + } + + image->width = bi.biWidth; + + if (bi.biHeight < 0) + { + vFlip = FALSE; + image->height = -1 * bi.biHeight; + } + else + { + vFlip = TRUE; + image->height = bi.biHeight; + } + + image->bitsPerPixel = bi.biBitCount; + image->bytesPerPixel = (image->bitsPerPixel / 8); + image->scanline = (bi.biSizeImage / bi.biHeight); + + image->data = (BYTE*) malloc(bi.biSizeImage); + + if (!image->data) + return -1; + + if (!vFlip) + { + fread((void*) image->data, bi.biSizeImage, 1, fp); + } + else + { + pDstData = &(image->data[(image->height - 1) * image->scanline]); + + for (index = 0; index < image->height; index++) + { + fread((void*) pDstData, image->scanline, 1, fp); + pDstData -= image->scanline; + } + } + + fclose(fp); + + return 1; +} + +wImage* winpr_image_new() +{ + wImage* image; + + image = (wImage*) calloc(1, sizeof(wImage)); + + if (!image) + return NULL; + + return image; +} + +void winpr_image_free(wImage* image, BOOL bFreeBuffer) +{ + if (!image) + return; + + if (bFreeBuffer) + free(image->data); + + free(image); +}