From ce442b5e969f1f8c89369b4c6c946040eddde047 Mon Sep 17 00:00:00 2001 From: 10km <10km0811@sohu.com> Date: Tue, 4 Sep 2018 13:40:59 +0800 Subject: [PATCH 1/2] add __mg_save_jpg function for storing MYBITMAP as JPEG file. enable application to store image as JPEG file. description: Convert all color space(RGBA,BGR,RGB565,index color256,16) to RGB ,and compress JPEG with JCS_RGB color space. Can use preprocessor _MGIMAGE_JPG_SAVE_QUALITY to define JPEG compression quality.default value 90. For RGBA color space image ,can use _MGIMAGE_JPG_RGBA_BGCOLOR define background color,default value 0XFFFFFF (white). For image with index color space(256 or 16) ,the argument 'pal' of __mg_save_jpg must be NULL. LIMIT:type of MG_RWops object must be RWAREA_TYPE_STDIO ( a file).not suport RWAREA_TYPE_MEM. --- src/include/readbmp.h | 1 + src/mybmp/jpeg.c | 264 ++++++++++++++++++++++++++++++++++++++++++ src/mybmp/mybmp.c | 4 +- 3 files changed, 267 insertions(+), 2 deletions(-) diff --git a/src/include/readbmp.h b/src/include/readbmp.h index da2a1144..b9acceed 100644 --- a/src/include/readbmp.h +++ b/src/include/readbmp.h @@ -114,6 +114,7 @@ BOOL __mg_check_gif (MG_RWops* fp); void* __mg_init_jpg (MG_RWops* fp, MYBITMAP *jpg, RGB *pal); int __mg_load_jpg (MG_RWops* fp, void* init_info, MYBITMAP *jpg, CB_ONE_SCANLINE cb, void* context); void __mg_cleanup_jpg (void* init_info); +int __mg_save_jpg (MG_RWops* fp, MYBITMAP* bmp, RGB* pal); BOOL __mg_check_jpg (MG_RWops* fp); #endif diff --git a/src/mybmp/jpeg.c b/src/mybmp/jpeg.c index 039d58bf..27570aac 100644 --- a/src/mybmp/jpeg.c +++ b/src/mybmp/jpeg.c @@ -524,5 +524,269 @@ BOOL __mg_check_jpg (MG_RWops* fp) return FALSE; /* not JPEG image*/ } +// color space conversion function type for one-row pixel of MYBITMAP +typedef BYTE* (*MYBITMAP_get_pixel_row)(unsigned int cinfo,MYBITMAP* mybmp,RGB* pal,BYTE* linebuffer); + +// convert index(16) color pixel line to RGB +static BYTE* MYBITMAP_get_pixel_row_pal16(unsigned int next_scanline, + MYBITMAP* mybmp,RGB* pal,BYTE* linebuffer) +{ + + BYTE* bits = mybmp->bits + mybmp->pitch * next_scanline; + RGB rgb; + for (int i = 0; i < mybmp->w; i++) { + + rgb = pal[ bits[i] & 0X0F ]; + + linebuffer[ i ] = rgb.r; + linebuffer[ i + 1 ] = rgb.g; + linebuffer[ i + 2 ] = rgb.b; + + } + return linebuffer; + +} +// convert index(256) color pixel line to RGB +static BYTE* MYBITMAP_get_pixel_row_pal256(unsigned int next_scanline, + MYBITMAP* mybmp,RGB* pal,BYTE* linebuffer) +{ + + BYTE* bits = mybmp->bits + mybmp->pitch * next_scanline; + RGB rgb; + for (int i = 0; i < mybmp->w; i++) { + + rgb = pal [bits[i] ]; + + linebuffer[ i ] = rgb.r; + linebuffer[ i + 1 ] = rgb.g; + linebuffer[ i + 2 ] = rgb.b; + + } + return linebuffer; + +} + +#define RGB_FROM_RGB565(pixel, r, g, b) \ +{ \ + r = (((pixel&0xF800)>>11)<<3); \ + g = (((pixel&0x07E0)>>5)<<2); \ + b = ((pixel&0x001F)<<3); \ +} + +// convert RGB565 pixel line to RGB +static BYTE* MYBITMAP_get_pixel_row_RGB565(unsigned int next_scanline, + MYBITMAP* mybmp,RGB* pal,BYTE* linebuffer) +{ + + Uint16* bits = (Uint16*)(mybmp->bits + mybmp->pitch * next_scanline); + + for (int i = 0, j = 0; i < mybmp->w; i++) { + + RGB_FROM_RGB565(bits[i], linebuffer[ j ++ ], linebuffer[ j ++ ], linebuffer[ j ++ ]) + + } + return linebuffer; + +} +// convert RGB pixel line to RGB +static BYTE* MYBITMAP_get_pixel_row_RGB(unsigned int next_scanline, + MYBITMAP* mybmp,RGB* pal,BYTE* linebuffer) +{ + return (JSAMPROW)(mybmp->bits + mybmp->pitch * next_scanline); +} + +// convert BGR pixel line to RGB +static BYTE* MYBITMAP_get_pixel_row_BGR(unsigned int next_scanline, + MYBITMAP* mybmp,RGB* pal,BYTE* linebuffer) +{ + BYTE* bits = mybmp->bits + mybmp->pitch * next_scanline; + + for (int i = 0, end_i = mybmp->w * 3; i < end_i; i += 3) { + linebuffer[ i ] = bits[ i + 2 ]; + linebuffer[ i + 1 ] = bits[ i + 1 ]; + linebuffer[ i + 2 ] = bits[ i ]; + } + return linebuffer; +} + +#ifndef _MGIMAGE_JPG_RGBA_BGCOLOR +/* background color for RGBA color space conversion,for example: 0xFF0000 is red */ +#define _MGIMAGE_JPG_RGBA_BGCOLOR 0xFFFFFF +#endif + +// convert RGBA pixel line to RGB +static BYTE* MYBITMAP_get_pixel_row_RGBA(unsigned int next_scanline, + MYBITMAP* mybmp,RGB* pal,BYTE* linebuffer) +{ + RGB* bits = (RGB*)(mybmp->bits + mybmp->pitch * next_scanline); + RGB pixel; + RGB bgcolor = { + (_MGIMAGE_JPG_RGBA_BGCOLOR >> 16) & 0xFF,/* red */ + (_MGIMAGE_JPG_RGBA_BGCOLOR >> 8) & 0xFF,/* green */ + _MGIMAGE_JPG_RGBA_BGCOLOR & 0xFF,/* blue */ + 0x00 /* alpha,no used */ + }; + for (int i = 0,j = 0; i < mybmp->w; i++, j += 3) { + pixel = bits[i]; + /* alpha composite, + * C = Cx * ALPHAx + (1 - ALPHAx) * Cbg + * see also : https://en.wikipedia.org/wiki/Alpha_compositing#Analytical_derivation_of_the_over_operator */ + linebuffer[ j ] = (JSAMPLE)((Uint32)pixel.r * pixel.a >> 8); /* red */ + linebuffer[ j + 1 ] = (JSAMPLE)((Uint32)pixel.g * pixel.a >> 8); /* green */ + linebuffer[ j + 2 ] = (JSAMPLE)((Uint32)pixel.b * pixel.a >> 8); /* blue */ + + linebuffer[ j ] += (JSAMPLE)((Uint32)bgcolor.r * (255 - pixel.a) >> 8); /* red + background color*/ + linebuffer[ j + 1 ] += (JSAMPLE)((Uint32)bgcolor.g * (255 - pixel.a) >> 8); /* green + background color */ + linebuffer[ j + 2 ] += (JSAMPLE)((Uint32)bgcolor.b * (255 - pixel.a) >> 8); /* blue + background color */ + } + return linebuffer; +} + +#ifndef _MGIMAGE_JPG_SAVE_QUALITY +#define _MGIMAGE_JPG_SAVE_QUALITY 90 +#endif + +int __fl_save_jpg (MG_RWops* fp, MYBITMAP* mybmp, RGB* pal) +{ + j_compress_ptr cinfo; + struct my_error_mgr *jerr; + JSAMPROW linebuffer = NULL; + JSAMPROW row_pointer[1]; + MYBITMAP_get_pixel_row get_row; + int retcode = ERR_BMP_CANT_SAVE; + + /* Step 1: Allocate and initialize JPEG compression object */ + cinfo = calloc (1, sizeof(struct jpeg_compress_struct)); + + if(NULL == cinfo) + { + fprintf(stderr, "__fl_save_jpg allocation error!\n"); + return ERR_BMP_MEM; + } + jpeg_create_compress(cinfo); + + /* Step 2: Allocate and initialize my_error_mgr object by jpeg_memory_mgr,and init */ + jerr = cinfo->mem->alloc_small((j_common_ptr) cinfo, JPOOL_IMAGE,sizeof(struct my_error_mgr)); + + if(NULL == jerr) + { + retcode = ERR_BMP_MEM; + goto do_finally; + } + memset(jerr,0,sizeof(struct my_error_mgr)); + + /* We set up the normal JPEG error routines first. */ + cinfo->err = jpeg_std_error (&jerr->pub); + jerr->pub.error_exit = my_error_exit; + + /* Establish the setjmp return context for my_error_exit to use. */ + if (setjmp (jerr->setjmp_buffer)) { + fprintf(stderr, "__fl_save_jpg error!\n"); + goto do_finally; + } + /* not supported RWAREA_TYPE_MEM type, + * because the MEM type object can not dynamic allocate memory,so it's not safe */ + if(RWAREA_TYPE_STDIO != fp->type ) + { + fprintf(stderr, "unsupported type of MG_RWops,only support RWAREA_TYPE_STDIO so far\n"); + longjmp (jerr->setjmp_buffer, 1); + } + /* Step 3: specify data source */ + jpeg_stdio_dest(cinfo, fp->hidden.stdio.fp); + + /* Step 4: initialize JPEG compression object */ + /* for JPEG compression, supported color space : JCS_GRAYSCALE,JCS_RGB,JCS_YCbCr,JCS_CMYK,JCS_YCCK + * in this case,MYBITMAP is base on RGB , + * we can select JCS_RGB only,so we must convert all color space (eg.RGBA,BGR,RGB565,...) to RGB + * */ + cinfo->in_color_space = JCS_RGB; + cinfo->image_width = mybmp->w; + cinfo->image_height = mybmp->h; + /* all of MYBMP_TYPE(eg.BRG,RGBA,RGB565...) will be converted to RGB,so input_components is constant 3 */ + cinfo->input_components = 3; + /* set jpeg compression parameters to default */ + jpeg_set_defaults(cinfo); + +#if _MGIMAGE_JPG_SAVE_QUALITY > 0 && _MGIMAGE_JPG_SAVE_QUALITY <= 100 + /* if _MGIMAGE_JPG_SAVE_QUALITY is valid value,use it + * otherwise use default value(75) of libjpeg, + * see also: libjpeg/jcparam.c jpeg_set_defaults function. + * */ + jpeg_set_quality(cinfo, _MGIMAGE_JPG_SAVE_QUALITY, TRUE); +#endif + + int mybmp_type = mybmp->flags & MYBMP_TYPE_MASK; + + switch(mybmp->depth) + { + case 4: + get_row = MYBITMAP_get_pixel_row_pal16; + break; + case 8: + get_row = MYBITMAP_get_pixel_row_pal256; + break; + case 16: + get_row = MYBITMAP_get_pixel_row_RGB565; + break; + case 24: + if(MYBMP_TYPE_RGB == mybmp_type) + get_row = MYBITMAP_get_pixel_row_RGB; + else + get_row = MYBITMAP_get_pixel_row_BGR; + break; + case 32: + get_row = MYBITMAP_get_pixel_row_RGBA; + break; + default: + fprintf(stderr, "invalid MYBITMAP.depth = %d\n",mybmp->depth); + longjmp (jerr->setjmp_buffer, 1); + break; + + } + + if(mybmp->depth <= 8 && NULL == pal) + { + fprintf(stderr, "the 'pal' argument must not be NULL for index color space\n"); + longjmp (jerr->setjmp_buffer, 1); + } + + if(24 == mybmp->depth && MYBMP_TYPE_RGB == mybmp_type) + { + /* + * do nothing while RGB type, + * the MYBITMAP_get_pixel_row function will return address in MYBITMAP.bits data directly, + * without using line buffer + * */ + } + else + { + /* Allocate one-row buffer for color space conversion */ + linebuffer = (JSAMPROW)cinfo->mem->alloc_large + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (cinfo->image_width * cinfo->input_components)); + if(NULL == linebuffer) + { + retcode = ERR_BMP_MEM; + fprintf(stderr, "libjpeg allocation error!\n"); + longjmp (jerr->setjmp_buffer, 1); + } + } + /* Step 5: scan and compress line data */ + jpeg_start_compress(cinfo, TRUE); + while (cinfo->next_scanline < cinfo->image_height) { + /* get one line pixel data with RGB format from MYBITMAP object */ + row_pointer[0] = get_row(cinfo->next_scanline, mybmp, pal, linebuffer); + jpeg_write_scanlines(cinfo, row_pointer, 1); + } + + jpeg_finish_compress(cinfo); + retcode = ERR_BMP_OK; +do_finally: + /* clean up the JPEG object, free the objects and return. */ + jpeg_destroy_compress (cinfo); + free (cinfo); + return retcode; +} + #endif /* _MGIMAGE_JPG */ diff --git a/src/mybmp/mybmp.c b/src/mybmp/mybmp.c index f4292ae8..82799214 100644 --- a/src/mybmp/mybmp.c +++ b/src/mybmp/mybmp.c @@ -80,8 +80,8 @@ static BITMAP_TYPE_INFO bitmap_types [MAX_BITMAP_TYPES] = { "gif", __mg_init_gif, __mg_load_gif, __mg_cleanup_gif, NULL, __mg_check_gif }, #endif #ifdef _MGIMAGE_JPG - { "jpg", __mg_init_jpg, __mg_load_jpg, __mg_cleanup_jpg, NULL, __mg_check_jpg }, - { "jpeg", __mg_init_jpg, __mg_load_jpg, __mg_cleanup_jpg, NULL, __mg_check_jpg }, + { "jpg", __mg_init_jpg, __mg_load_jpg, __mg_cleanup_jpg, __mg_save_jpg, __mg_check_jpg }, + { "jpeg", __mg_init_jpg, __mg_load_jpg, __mg_cleanup_jpg, __mg_save_jpg, __mg_check_jpg }, #endif #ifdef _MGIMAGE_PNG { "png", __mg_init_png, __mg_load_png, __mg_cleanup_png, NULL, __mg_check_png }, From faa7a2636e7a3ec41bec134fca65e78a8514913f Mon Sep 17 00:00:00 2001 From: 10km <10km0811@sohu.com> Date: Tue, 4 Sep 2018 16:06:06 +0800 Subject: [PATCH 2/2] fix bug for MYBITMAP_get_pixel_row_pal16,MYBITMAP_get_pixel_row_pal256 --- src/mybmp/jpeg.c | 333 ++++++++++++++++++++++++----------------------- 1 file changed, 168 insertions(+), 165 deletions(-) diff --git a/src/mybmp/jpeg.c b/src/mybmp/jpeg.c index 27570aac..4259b5bd 100644 --- a/src/mybmp/jpeg.c +++ b/src/mybmp/jpeg.c @@ -529,40 +529,43 @@ typedef BYTE* (*MYBITMAP_get_pixel_row)(unsigned int cinfo,MYBITMAP* mybmp,RGB* // convert index(16) color pixel line to RGB static BYTE* MYBITMAP_get_pixel_row_pal16(unsigned int next_scanline, - MYBITMAP* mybmp,RGB* pal,BYTE* linebuffer) + MYBITMAP* mybmp,RGB* pal,BYTE* linebuffer) { BYTE* bits = mybmp->bits + mybmp->pitch * next_scanline; - RGB rgb; - for (int i = 0; i < mybmp->w; i++) { + RGB rgb0,rgb1; + for (int i = 0, j = 0, end_i = (mybmp->w + 1) >> 1; i < end_i; ++i) { - rgb = pal[ bits[i] & 0X0F ]; - - linebuffer[ i ] = rgb.r; - linebuffer[ i + 1 ] = rgb.g; - linebuffer[ i + 2 ] = rgb.b; + rgb0 = pal[ (bits[ i ] & 0XF0) >> 4 ]; + rgb1 = pal[ bits[ i ] & 0X0F ]; + linebuffer[ j ++ ] = rgb0.r; + linebuffer[ j ++ ] = rgb0.g; + linebuffer[ j ++ ] = rgb0.b; + linebuffer[ j ++ ] = rgb1.r; + linebuffer[ j ++ ] = rgb1.g; + linebuffer[ j ++ ] = rgb1.b; } - return linebuffer; + return linebuffer; } // convert index(256) color pixel line to RGB static BYTE* MYBITMAP_get_pixel_row_pal256(unsigned int next_scanline, - MYBITMAP* mybmp,RGB* pal,BYTE* linebuffer) + MYBITMAP* mybmp,RGB* pal,BYTE* linebuffer) { BYTE* bits = mybmp->bits + mybmp->pitch * next_scanline; RGB rgb; - for (int i = 0; i < mybmp->w; i++) { + for (int i = 0, j = 0; i < mybmp->w; i++) { - rgb = pal [bits[i] ]; + rgb = pal [bits[i] ]; - linebuffer[ i ] = rgb.r; - linebuffer[ i + 1 ] = rgb.g; - linebuffer[ i + 2 ] = rgb.b; + linebuffer[ j++ ] = rgb.r; + linebuffer[ j++ ] = rgb.g; + linebuffer[ j++ ] = rgb.b; } - return linebuffer; + return linebuffer; } @@ -575,38 +578,38 @@ static BYTE* MYBITMAP_get_pixel_row_pal256(unsigned int next_scanline, // convert RGB565 pixel line to RGB static BYTE* MYBITMAP_get_pixel_row_RGB565(unsigned int next_scanline, - MYBITMAP* mybmp,RGB* pal,BYTE* linebuffer) + MYBITMAP* mybmp,RGB* pal,BYTE* linebuffer) { - Uint16* bits = (Uint16*)(mybmp->bits + mybmp->pitch * next_scanline); + Uint16* bits = (Uint16*)(mybmp->bits + mybmp->pitch * next_scanline); - for (int i = 0, j = 0; i < mybmp->w; i++) { + for (int i = 0, j = 0; i < mybmp->w; i++) { - RGB_FROM_RGB565(bits[i], linebuffer[ j ++ ], linebuffer[ j ++ ], linebuffer[ j ++ ]) + RGB_FROM_RGB565(bits[i], linebuffer[ j ++ ], linebuffer[ j ++ ], linebuffer[ j ++ ]) } - return linebuffer; + return linebuffer; } // convert RGB pixel line to RGB static BYTE* MYBITMAP_get_pixel_row_RGB(unsigned int next_scanline, - MYBITMAP* mybmp,RGB* pal,BYTE* linebuffer) + MYBITMAP* mybmp,RGB* pal,BYTE* linebuffer) { - return (JSAMPROW)(mybmp->bits + mybmp->pitch * next_scanline); + return (JSAMPROW)(mybmp->bits + mybmp->pitch * next_scanline); } // convert BGR pixel line to RGB static BYTE* MYBITMAP_get_pixel_row_BGR(unsigned int next_scanline, - MYBITMAP* mybmp,RGB* pal,BYTE* linebuffer) + MYBITMAP* mybmp,RGB* pal,BYTE* linebuffer) { BYTE* bits = mybmp->bits + mybmp->pitch * next_scanline; - for (int i = 0, end_i = mybmp->w * 3; i < end_i; i += 3) { - linebuffer[ i ] = bits[ i + 2 ]; - linebuffer[ i + 1 ] = bits[ i + 1 ]; - linebuffer[ i + 2 ] = bits[ i ]; - } - return linebuffer; + for (int i = 0, end_i = mybmp->w * 3; i < end_i; i += 3) { + linebuffer[ i ] = bits[ i + 2 ]; + linebuffer[ i + 1 ] = bits[ i + 1 ]; + linebuffer[ i + 2 ] = bits[ i ]; + } + return linebuffer; } #ifndef _MGIMAGE_JPG_RGBA_BGCOLOR @@ -616,64 +619,64 @@ static BYTE* MYBITMAP_get_pixel_row_BGR(unsigned int next_scanline, // convert RGBA pixel line to RGB static BYTE* MYBITMAP_get_pixel_row_RGBA(unsigned int next_scanline, - MYBITMAP* mybmp,RGB* pal,BYTE* linebuffer) + MYBITMAP* mybmp,RGB* pal,BYTE* linebuffer) { - RGB* bits = (RGB*)(mybmp->bits + mybmp->pitch * next_scanline); - RGB pixel; - RGB bgcolor = { - (_MGIMAGE_JPG_RGBA_BGCOLOR >> 16) & 0xFF,/* red */ - (_MGIMAGE_JPG_RGBA_BGCOLOR >> 8) & 0xFF,/* green */ - _MGIMAGE_JPG_RGBA_BGCOLOR & 0xFF,/* blue */ - 0x00 /* alpha,no used */ - }; - for (int i = 0,j = 0; i < mybmp->w; i++, j += 3) { - pixel = bits[i]; - /* alpha composite, - * C = Cx * ALPHAx + (1 - ALPHAx) * Cbg - * see also : https://en.wikipedia.org/wiki/Alpha_compositing#Analytical_derivation_of_the_over_operator */ - linebuffer[ j ] = (JSAMPLE)((Uint32)pixel.r * pixel.a >> 8); /* red */ - linebuffer[ j + 1 ] = (JSAMPLE)((Uint32)pixel.g * pixel.a >> 8); /* green */ - linebuffer[ j + 2 ] = (JSAMPLE)((Uint32)pixel.b * pixel.a >> 8); /* blue */ + RGB* bits = (RGB*)(mybmp->bits + mybmp->pitch * next_scanline); + RGB pixel; + RGB bgcolor = { + (_MGIMAGE_JPG_RGBA_BGCOLOR >> 16) & 0xFF,/* red */ + (_MGIMAGE_JPG_RGBA_BGCOLOR >> 8) & 0xFF,/* green */ + _MGIMAGE_JPG_RGBA_BGCOLOR & 0xFF,/* blue */ + 0x00 /* alpha,no used */ + }; + for (int i = 0,j = 0; i < mybmp->w; i++, j += 3) { + pixel = bits[i]; + /* alpha composite, + * C = Cx * ALPHAx + (1 - ALPHAx) * Cbg + * see also : https://en.wikipedia.org/wiki/Alpha_compositing#Analytical_derivation_of_the_over_operator */ + linebuffer[ j ] = (JSAMPLE)((Uint32)pixel.r * pixel.a >> 8); /* red */ + linebuffer[ j + 1 ] = (JSAMPLE)((Uint32)pixel.g * pixel.a >> 8); /* green */ + linebuffer[ j + 2 ] = (JSAMPLE)((Uint32)pixel.b * pixel.a >> 8); /* blue */ - linebuffer[ j ] += (JSAMPLE)((Uint32)bgcolor.r * (255 - pixel.a) >> 8); /* red + background color*/ - linebuffer[ j + 1 ] += (JSAMPLE)((Uint32)bgcolor.g * (255 - pixel.a) >> 8); /* green + background color */ - linebuffer[ j + 2 ] += (JSAMPLE)((Uint32)bgcolor.b * (255 - pixel.a) >> 8); /* blue + background color */ - } - return linebuffer; + linebuffer[ j ] += (JSAMPLE)((Uint32)bgcolor.r * (255 - pixel.a) >> 8); /* red + background color*/ + linebuffer[ j + 1 ] += (JSAMPLE)((Uint32)bgcolor.g * (255 - pixel.a) >> 8); /* green + background color */ + linebuffer[ j + 2 ] += (JSAMPLE)((Uint32)bgcolor.b * (255 - pixel.a) >> 8); /* blue + background color */ + } + return linebuffer; } #ifndef _MGIMAGE_JPG_SAVE_QUALITY #define _MGIMAGE_JPG_SAVE_QUALITY 90 #endif -int __fl_save_jpg (MG_RWops* fp, MYBITMAP* mybmp, RGB* pal) +int __mg_save_jpg (MG_RWops* fp, MYBITMAP* mybmp, RGB* pal) { - j_compress_ptr cinfo; - struct my_error_mgr *jerr; - JSAMPROW linebuffer = NULL; - JSAMPROW row_pointer[1]; - MYBITMAP_get_pixel_row get_row; - int retcode = ERR_BMP_CANT_SAVE; + j_compress_ptr cinfo; + struct my_error_mgr *jerr; + JSAMPROW linebuffer = NULL; + JSAMPROW row_pointer[1]; + MYBITMAP_get_pixel_row get_row; + int retcode = ERR_BMP_CANT_SAVE; - /* Step 1: Allocate and initialize JPEG compression object */ - cinfo = calloc (1, sizeof(struct jpeg_compress_struct)); + /* Step 1: Allocate and initialize JPEG compression object */ + cinfo = calloc (1, sizeof(struct jpeg_compress_struct)); - if(NULL == cinfo) - { - fprintf(stderr, "__fl_save_jpg allocation error!\n"); - return ERR_BMP_MEM; - } - jpeg_create_compress(cinfo); + if(NULL == cinfo) + { + fprintf(stderr, "__fl_save_jpg allocation error!\n"); + return ERR_BMP_MEM; + } + jpeg_create_compress(cinfo); - /* Step 2: Allocate and initialize my_error_mgr object by jpeg_memory_mgr,and init */ - jerr = cinfo->mem->alloc_small((j_common_ptr) cinfo, JPOOL_IMAGE,sizeof(struct my_error_mgr)); + /* Step 2: Allocate and initialize my_error_mgr object by jpeg_memory_mgr,and init */ + jerr = cinfo->mem->alloc_small((j_common_ptr) cinfo, JPOOL_IMAGE,sizeof(struct my_error_mgr)); - if(NULL == jerr) - { - retcode = ERR_BMP_MEM; - goto do_finally; - } - memset(jerr,0,sizeof(struct my_error_mgr)); + if(NULL == jerr) + { + retcode = ERR_BMP_MEM; + goto do_finally; + } + memset(jerr,0,sizeof(struct my_error_mgr)); /* We set up the normal JPEG error routines first. */ cinfo->err = jpeg_std_error (&jerr->pub); @@ -681,111 +684,111 @@ int __fl_save_jpg (MG_RWops* fp, MYBITMAP* mybmp, RGB* pal) /* Establish the setjmp return context for my_error_exit to use. */ if (setjmp (jerr->setjmp_buffer)) { - fprintf(stderr, "__fl_save_jpg error!\n"); + fprintf(stderr, "__fl_save_jpg error!\n"); goto do_finally; } /* not supported RWAREA_TYPE_MEM type, * because the MEM type object can not dynamic allocate memory,so it's not safe */ - if(RWAREA_TYPE_STDIO != fp->type ) - { - fprintf(stderr, "unsupported type of MG_RWops,only support RWAREA_TYPE_STDIO so far\n"); - longjmp (jerr->setjmp_buffer, 1); - } - /* Step 3: specify data source */ - jpeg_stdio_dest(cinfo, fp->hidden.stdio.fp); + if(RWAREA_TYPE_STDIO != fp->type ) + { + fprintf(stderr, "unsupported type of MG_RWops,only support RWAREA_TYPE_STDIO so far\n"); + longjmp (jerr->setjmp_buffer, 1); + } + /* Step 3: specify data source */ + jpeg_stdio_dest(cinfo, fp->hidden.stdio.fp); - /* Step 4: initialize JPEG compression object */ - /* for JPEG compression, supported color space : JCS_GRAYSCALE,JCS_RGB,JCS_YCbCr,JCS_CMYK,JCS_YCCK - * in this case,MYBITMAP is base on RGB , - * we can select JCS_RGB only,so we must convert all color space (eg.RGBA,BGR,RGB565,...) to RGB - * */ - cinfo->in_color_space = JCS_RGB; - cinfo->image_width = mybmp->w; - cinfo->image_height = mybmp->h; - /* all of MYBMP_TYPE(eg.BRG,RGBA,RGB565...) will be converted to RGB,so input_components is constant 3 */ - cinfo->input_components = 3; - /* set jpeg compression parameters to default */ - jpeg_set_defaults(cinfo); + /* Step 4: initialize JPEG compression object */ + /* for JPEG compression, supported color space : JCS_GRAYSCALE,JCS_RGB,JCS_YCbCr,JCS_CMYK,JCS_YCCK + * in this case,MYBITMAP is base on RGB , + * we can select JCS_RGB only,so we must convert all color space (eg.RGBA,BGR,RGB565,...) to RGB + * */ + cinfo->in_color_space = JCS_RGB; + cinfo->image_width = mybmp->w; + cinfo->image_height = mybmp->h; + /* all of MYBMP_TYPE(eg.BRG,RGBA,RGB565...) will be converted to RGB,so input_components is constant 3 */ + cinfo->input_components = 3; + /* set jpeg compression parameters to default */ + jpeg_set_defaults(cinfo); #if _MGIMAGE_JPG_SAVE_QUALITY > 0 && _MGIMAGE_JPG_SAVE_QUALITY <= 100 - /* if _MGIMAGE_JPG_SAVE_QUALITY is valid value,use it - * otherwise use default value(75) of libjpeg, - * see also: libjpeg/jcparam.c jpeg_set_defaults function. - * */ - jpeg_set_quality(cinfo, _MGIMAGE_JPG_SAVE_QUALITY, TRUE); + /* if _MGIMAGE_JPG_SAVE_QUALITY is valid value,use it + * otherwise use default value(75) of libjpeg, + * see also: libjpeg/jcparam.c jpeg_set_defaults function. + * */ + jpeg_set_quality(cinfo, _MGIMAGE_JPG_SAVE_QUALITY, TRUE); #endif - int mybmp_type = mybmp->flags & MYBMP_TYPE_MASK; + int mybmp_type = mybmp->flags & MYBMP_TYPE_MASK; - switch(mybmp->depth) - { - case 4: - get_row = MYBITMAP_get_pixel_row_pal16; - break; - case 8: - get_row = MYBITMAP_get_pixel_row_pal256; - break; - case 16: - get_row = MYBITMAP_get_pixel_row_RGB565; - break; - case 24: - if(MYBMP_TYPE_RGB == mybmp_type) - get_row = MYBITMAP_get_pixel_row_RGB; - else - get_row = MYBITMAP_get_pixel_row_BGR; - break; - case 32: - get_row = MYBITMAP_get_pixel_row_RGBA; - break; - default: - fprintf(stderr, "invalid MYBITMAP.depth = %d\n",mybmp->depth); - longjmp (jerr->setjmp_buffer, 1); - break; + switch(mybmp->depth) + { + case 4: + get_row = MYBITMAP_get_pixel_row_pal16; + break; + case 8: + get_row = MYBITMAP_get_pixel_row_pal256; + break; + case 16: + get_row = MYBITMAP_get_pixel_row_RGB565; + break; + case 24: + if(MYBMP_TYPE_RGB == mybmp_type) + get_row = MYBITMAP_get_pixel_row_RGB; + else + get_row = MYBITMAP_get_pixel_row_BGR; + break; + case 32: + get_row = MYBITMAP_get_pixel_row_RGBA; + break; + default: + fprintf(stderr, "invalid MYBITMAP.depth = %d\n",mybmp->depth); + longjmp (jerr->setjmp_buffer, 1); + break; - } + } - if(mybmp->depth <= 8 && NULL == pal) - { - fprintf(stderr, "the 'pal' argument must not be NULL for index color space\n"); - longjmp (jerr->setjmp_buffer, 1); - } + if(mybmp->depth <= 8 && NULL == pal) + { + fprintf(stderr, "the 'pal' argument must not be NULL for index color space\n"); + longjmp (jerr->setjmp_buffer, 1); + } - if(24 == mybmp->depth && MYBMP_TYPE_RGB == mybmp_type) - { - /* - * do nothing while RGB type, - * the MYBITMAP_get_pixel_row function will return address in MYBITMAP.bits data directly, - * without using line buffer - * */ - } - else - { - /* Allocate one-row buffer for color space conversion */ - linebuffer = (JSAMPROW)cinfo->mem->alloc_large - ((j_common_ptr) cinfo, JPOOL_IMAGE, - (cinfo->image_width * cinfo->input_components)); - if(NULL == linebuffer) - { - retcode = ERR_BMP_MEM; - fprintf(stderr, "libjpeg allocation error!\n"); - longjmp (jerr->setjmp_buffer, 1); - } - } - /* Step 5: scan and compress line data */ - jpeg_start_compress(cinfo, TRUE); - while (cinfo->next_scanline < cinfo->image_height) { - /* get one line pixel data with RGB format from MYBITMAP object */ - row_pointer[0] = get_row(cinfo->next_scanline, mybmp, pal, linebuffer); - jpeg_write_scanlines(cinfo, row_pointer, 1); - } + if(24 == mybmp->depth && MYBMP_TYPE_RGB == mybmp_type) + { + /* + * do nothing while RGB type, + * the MYBITMAP_get_pixel_row function will return address in MYBITMAP.bits data directly, + * without using line buffer + * */ + } + else + { + /* Allocate one-row buffer for color space conversion(4 byte alignment) */ + linebuffer = (JSAMPROW)cinfo->mem->alloc_large + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (((cinfo->image_width + 3) & ~3) * cinfo->input_components)); + if(NULL == linebuffer) + { + retcode = ERR_BMP_MEM; + fprintf(stderr, "libjpeg allocation error!\n"); + longjmp (jerr->setjmp_buffer, 1); + } + } + /* Step 5: scan and compress line data */ + jpeg_start_compress(cinfo, TRUE); + while (cinfo->next_scanline < cinfo->image_height) { + /* get one line pixel data with RGB format from MYBITMAP object */ + row_pointer[0] = get_row(cinfo->next_scanline, mybmp, pal, linebuffer); + jpeg_write_scanlines(cinfo, row_pointer, 1); + } - jpeg_finish_compress(cinfo); - retcode = ERR_BMP_OK; + jpeg_finish_compress(cinfo); + retcode = ERR_BMP_OK; do_finally: - /* clean up the JPEG object, free the objects and return. */ - jpeg_destroy_compress (cinfo); - free (cinfo); - return retcode; + /* clean up the JPEG object, free the objects and return. */ + jpeg_destroy_compress (cinfo); + free (cinfo); + return retcode; } #endif /* _MGIMAGE_JPG */