static void iwopt_try_gray8_binary_trns(struct iw_context *ctx, struct iw_opt_ctx *optctx) { int i,j; const unsigned char *ptr; unsigned char *ptr2; unsigned char clr_used[256]; unsigned char key_clr; unsigned char *trns_mask = NULL; if(!(ctx->output_profile&IW_PROFILE_BINARYTRNS)) return; if(!ctx->opt_binary_trns) return; memset(&clr_used,0,256*sizeof(unsigned char)); trns_mask = iw_malloc_large(ctx, optctx->width, optctx->height); if(!trns_mask) goto done; for(j=0;j<optctx->height;j++) { for(i=0;i<optctx->width;i++) { ptr = &optctx->pixelsptr[j*optctx->bpr+i*2]; if(ptr[1]==0) { // Transparent pixel trns_mask[j*optctx->width+i] = 0; continue; } else { // Nontransparent pixel trns_mask[j*optctx->width+i] = 1; } clr_used[(int)ptr[0]] = 1; } } if(!iwopt_find_unused(clr_used,256,&key_clr)) { goto done; } // Strip the alpha channel: iw_opt_copychannels_8(ctx,optctx,IW_IMGTYPE_GRAY,0,0,0); if(!optctx->tmp_pixels) goto done; // Change the color of all transparent pixels to the key color for(j=0;j<optctx->height;j++) { for(i=0;i<optctx->width;i++) { ptr2 = &optctx->tmp_pixels[j*optctx->bpr+i]; if(trns_mask[j*optctx->width+i]==0) { ptr2[0] = key_clr; } } } optctx->has_colorkey_trns = 1; optctx->colorkey_r = key_clr; optctx->colorkey_g = key_clr; optctx->colorkey_b = key_clr; done: if(trns_mask) iw_free(trns_mask); }
// Strip alpha channel if there are no actual transparent pixels, etc. void iw_optimize_image(struct iw_context *ctx) { struct iw_opt_ctx *optctx; optctx = &ctx->optctx; memset(optctx,0,sizeof(struct iw_opt_ctx)); optctx->width = ctx->img2.width; optctx->height = ctx->img2.height; optctx->imgtype = ctx->img2.imgtype; optctx->bit_depth = ctx->img2.bit_depth; optctx->bpr = ctx->img2.bpr; optctx->pixelsptr = ctx->img2.pixels; optctx->has_transparency=0; optctx->has_partial_transparency=0; optctx->has_16bit_precision=0; optctx->has_color=0; if(ctx->img2.sampletype!=IW_SAMPLETYPE_UINT) { return; } make_transparent_pixels_black(ctx,&ctx->img2); if(!iw_opt_scanpixels(ctx,optctx)) { goto noscan; } if(optctx->imgtype==IW_IMGTYPE_RGBA && optctx->bit_depth==16 && !optctx->has_16bit_precision) { iw_opt_16_to_8(ctx,optctx,4); } if(optctx->imgtype==IW_IMGTYPE_RGB && optctx->bit_depth==16 && !optctx->has_16bit_precision) { iw_opt_16_to_8(ctx,optctx,3); } if(optctx->imgtype==IW_IMGTYPE_GRAYA && optctx->bit_depth==16 && !optctx->has_16bit_precision) { iw_opt_16_to_8(ctx,optctx,2); } if(optctx->imgtype==IW_IMGTYPE_GRAY && optctx->bit_depth==16 && !optctx->has_16bit_precision) { iw_opt_16_to_8(ctx,optctx,1); } if(optctx->imgtype==IW_IMGTYPE_RGBA && optctx->bit_depth==8 && !optctx->has_transparency && ctx->opt_strip_alpha) { iw_opt_copychannels_8(ctx,optctx,IW_IMGTYPE_RGB,0,1,2); // RGBA -> RGB } if(optctx->imgtype==IW_IMGTYPE_RGBA && optctx->bit_depth==16 && !optctx->has_transparency && ctx->opt_strip_alpha) { iw_opt_copychannels_16(ctx,optctx,IW_IMGTYPE_RGB,0,1,2); // RGBA -> RGB (16) } if(optctx->imgtype==IW_IMGTYPE_GRAYA && optctx->bit_depth==16 && !optctx->has_transparency && ctx->opt_strip_alpha) { iw_opt_copychannels_16(ctx,optctx,IW_IMGTYPE_GRAY,0, 0,0); // GA -> G (16) } if(optctx->imgtype==IW_IMGTYPE_GRAYA && optctx->bit_depth==8 && !optctx->has_transparency && ctx->opt_strip_alpha) { iw_opt_copychannels_8(ctx,optctx,IW_IMGTYPE_GRAY,0, 0,0); // GA -> G } if(optctx->imgtype==IW_IMGTYPE_RGB && optctx->bit_depth==8 && !optctx->has_color && (ctx->output_profile&IW_PROFILE_GRAYSCALE) && ctx->opt_grayscale) { iw_opt_copychannels_8(ctx,optctx,IW_IMGTYPE_GRAY,0, 0,0); // RGB -> G } if(optctx->imgtype==IW_IMGTYPE_RGB && optctx->bit_depth==16 && !optctx->has_color && (ctx->output_profile&IW_PROFILE_GRAYSCALE) && ctx->opt_grayscale) { iw_opt_copychannels_16(ctx,optctx,IW_IMGTYPE_GRAY,0, 0,0); // RGB -> G (16) } if(optctx->imgtype==IW_IMGTYPE_RGBA && optctx->bit_depth==8 && !optctx->has_color && (ctx->output_profile&IW_PROFILE_GRAYSCALE) && ctx->opt_grayscale) { iw_opt_copychannels_8(ctx,optctx,IW_IMGTYPE_GRAYA,0,3, 0); // RGBA -> GA } if(optctx->imgtype==IW_IMGTYPE_RGBA && optctx->bit_depth==16 && !optctx->has_color && (ctx->output_profile&IW_PROFILE_GRAYSCALE) && ctx->opt_grayscale) { iw_opt_copychannels_16(ctx,optctx,IW_IMGTYPE_GRAYA,0,3, 0); // RGBA -> GA (16) } noscan: iwopt_try_pal_lowgray_optimization(ctx,optctx); // Try to convert an alpha channel to binary transparency. if(optctx->imgtype==IW_IMGTYPE_RGBA && optctx->bit_depth==8 && !optctx->has_partial_transparency) { iwopt_try_rgb8_binary_trns(ctx,optctx); } if(optctx->imgtype==IW_IMGTYPE_RGBA && optctx->bit_depth==16 && !optctx->has_partial_transparency) { iwopt_try_rgb16_binary_trns(ctx,optctx); } if(optctx->imgtype==IW_IMGTYPE_GRAYA && optctx->bit_depth==8 && !optctx->has_partial_transparency) { iwopt_try_gray8_binary_trns(ctx,optctx); } if(optctx->imgtype==IW_IMGTYPE_GRAYA && optctx->bit_depth==16 && !optctx->has_partial_transparency) { iwopt_try_gray16_binary_trns(ctx,optctx); } }
// Try to convert from RGBA to RGB+binary trns. // Assumes we already know there is transparency, but no partial transparency. static void iwopt_try_rgb8_binary_trns(struct iw_context *ctx, struct iw_opt_ctx *optctx) { int i,j; const unsigned char *ptr; unsigned char *ptr2; unsigned char clr_used[256]; unsigned char key_clr; // Red component of the key color unsigned char *trns_mask = NULL; if(!(ctx->output_profile&IW_PROFILE_BINARYTRNS)) return; if(!ctx->opt_binary_trns) return; // Try to find a color that's not used in the image. // Looking for all 2^24 possible colors is too much work. // We will just look for 256 predefined colors: R={0-255},G=192,B=192 memset(&clr_used,0,256*sizeof(unsigned char)); // Hard to decide how to do this. I don't want the optimization phase // to modify img2.pixels, though that would be the easiest method. // Another option would be to make a version of iw_opt_copychannels_8() // that sets the transparent pixels to a certain value, but that would // get messy. // Instead, I'll make a transparency mask, then strip the alpha // channel, then use the mask to patch up the new image. trns_mask = iw_malloc_large(ctx, optctx->width, optctx->height); if(!trns_mask) goto done; for(j=0;j<optctx->height;j++) { for(i=0;i<optctx->width;i++) { ptr = &optctx->pixelsptr[j*optctx->bpr+i*4]; if(ptr[3]==0) { // transparent pixel trns_mask[j*optctx->width+i] = 0; // Remember which pixels are transparent. continue; } else { trns_mask[j*optctx->width+i] = 1; } if(ptr[1]!=192 || ptr[2]!=192) continue; clr_used[(int)ptr[0]] = 1; } } if(!iwopt_find_unused(clr_used,256,&key_clr)) { goto done; } // Strip the alpha channel: iw_opt_copychannels_8(ctx,optctx,IW_IMGTYPE_RGB,0,1,2); if(!optctx->tmp_pixels) goto done; // Change the color of all transparent pixels to the key color for(j=0;j<optctx->height;j++) { for(i=0;i<optctx->width;i++) { ptr2 = &optctx->tmp_pixels[j*optctx->bpr+i*3]; if(trns_mask[j*optctx->width+i]==0) { ptr2[0] = key_clr; ptr2[1] = 192; ptr2[2] = 192; } } } optctx->has_colorkey_trns = 1; optctx->colorkey_r = key_clr; optctx->colorkey_g = 192; optctx->colorkey_b = 192; done: if(trns_mask) iw_free(trns_mask); }
// Strip alpha channel if there are no actual transparent pixels, etc. void iwpvt_optimize_image(struct iw_context *ctx) { struct iw_opt_ctx *optctx; int k; optctx = &ctx->optctx; //iw_zeromem(optctx,sizeof(struct iw_opt_ctx)); optctx->width = ctx->img2.width; optctx->height = ctx->img2.height; optctx->imgtype = ctx->img2.imgtype; optctx->bit_depth = ctx->img2.bit_depth; optctx->bpr = ctx->img2.bpr; optctx->pixelsptr = ctx->img2.pixels; //optctx->has_transparency=0; //optctx->has_partial_transparency=0; //optctx->has_16bit_precision=0; //optctx->has_color=0; if(ctx->img2.has_bkgdlabel) { optctx->has_bkgdlabel = ctx->img2.has_bkgdlabel; for(k=0;k<4;k++) { optctx->bkgdlabel[k] = iw_color_get_int_sample(&ctx->img2.bkgdlabel, k, ctx->img2.bit_depth==8?255:65535); } } if(ctx->img2.sampletype!=IW_SAMPLETYPE_UINT) { return; } if(ctx->reduced_output_maxcolor_flag) { return; } make_transparent_pixels_black(ctx,&ctx->img2); if(optctx->has_bkgdlabel) { // The optimization routines are responsible for ensuring that the // background color label can easily be written to the optimized image. // For example, they may have to add a color to the palette just for // the background color. // They are NOT responsible for telling the image encoder module // precisely how to write the background color. The encoder will be // given the background color in RGB format, and it will have to figure // out what to do with it. For example, it may have to search for that // color in the palette. // If the background color label exists, and is non-gray, // make sure we don't write a grayscale image // (assuming we're writing to a PNG-like format). if(optctx->bkgdlabel[0] != optctx->bkgdlabel[1] || optctx->bkgdlabel[0] != optctx->bkgdlabel[2]) { optctx->has_color = 1; } // If 16-bit precision is desired, and the background color cannot be // losslessly reduced to 8-bit precision, use 16-bit precision. if(optctx->bit_depth==16) { if(optctx->bkgdlabel[0]%257!=0 || optctx->bkgdlabel[1]%257!=0 || optctx->bkgdlabel[2]%257!=0) { optctx->has_16bit_precision=1; } } } if(!iw_opt_scanpixels(ctx,optctx)) { goto noscan; } if(optctx->imgtype==IW_IMGTYPE_RGBA && optctx->bit_depth==16 && !optctx->has_16bit_precision) { iw_opt_16_to_8(ctx,optctx,4); } if(optctx->imgtype==IW_IMGTYPE_RGB && optctx->bit_depth==16 && !optctx->has_16bit_precision) { iw_opt_16_to_8(ctx,optctx,3); } if(optctx->imgtype==IW_IMGTYPE_GRAYA && optctx->bit_depth==16 && !optctx->has_16bit_precision) { iw_opt_16_to_8(ctx,optctx,2); } if(optctx->imgtype==IW_IMGTYPE_GRAY && optctx->bit_depth==16 && !optctx->has_16bit_precision) { iw_opt_16_to_8(ctx,optctx,1); } if(optctx->imgtype==IW_IMGTYPE_RGBA && optctx->bit_depth==8 && !optctx->has_transparency && ctx->opt_strip_alpha) { iw_opt_copychannels_8(ctx,optctx,IW_IMGTYPE_RGB,0,1,2); // RGBA -> RGB } if(optctx->imgtype==IW_IMGTYPE_RGBA && optctx->bit_depth==16 && !optctx->has_transparency && ctx->opt_strip_alpha) { iw_opt_copychannels_16(ctx,optctx,IW_IMGTYPE_RGB,0,1,2); // RGBA -> RGB (16) } if(optctx->imgtype==IW_IMGTYPE_GRAYA && optctx->bit_depth==16 && !optctx->has_transparency && ctx->opt_strip_alpha) { iw_opt_copychannels_16(ctx,optctx,IW_IMGTYPE_GRAY,0, 0,0); // GA -> G (16) } if(optctx->imgtype==IW_IMGTYPE_GRAYA && optctx->bit_depth==8 && !optctx->has_transparency && ctx->opt_strip_alpha) { iw_opt_copychannels_8(ctx,optctx,IW_IMGTYPE_GRAY,0, 0,0); // GA -> G } if(optctx->imgtype==IW_IMGTYPE_RGB && optctx->bit_depth==8 && !optctx->has_color && (ctx->output_profile&IW_PROFILE_GRAYSCALE) && ctx->opt_grayscale) { iw_opt_copychannels_8(ctx,optctx,IW_IMGTYPE_GRAY,0, 0,0); // RGB -> G } if(optctx->imgtype==IW_IMGTYPE_RGB && optctx->bit_depth==16 && !optctx->has_color && (ctx->output_profile&IW_PROFILE_GRAYSCALE) && ctx->opt_grayscale) { iw_opt_copychannels_16(ctx,optctx,IW_IMGTYPE_GRAY,0, 0,0); // RGB -> G (16) } if(optctx->imgtype==IW_IMGTYPE_RGBA && optctx->bit_depth==8 && !optctx->has_color && (ctx->output_profile&IW_PROFILE_GRAYSCALE) && ctx->opt_grayscale) { iw_opt_copychannels_8(ctx,optctx,IW_IMGTYPE_GRAYA,0,3, 0); // RGBA -> GA } if(optctx->imgtype==IW_IMGTYPE_RGBA && optctx->bit_depth==16 && !optctx->has_color && (ctx->output_profile&IW_PROFILE_GRAYSCALE) && ctx->opt_grayscale) { iw_opt_copychannels_16(ctx,optctx,IW_IMGTYPE_GRAYA,0,3, 0); // RGBA -> GA (16) } noscan: iwopt_try_pal_lowgray_optimization(ctx,optctx); // Try to convert an alpha channel to binary transparency. if(optctx->imgtype==IW_IMGTYPE_RGBA && optctx->bit_depth==8 && !optctx->has_partial_transparency) { iwopt_try_rgb8_binary_trns(ctx,optctx); } if(optctx->imgtype==IW_IMGTYPE_RGBA && optctx->bit_depth==16 && !optctx->has_partial_transparency) { iwopt_try_rgb16_binary_trns(ctx,optctx); } if(optctx->imgtype==IW_IMGTYPE_GRAYA && optctx->bit_depth==8 && !optctx->has_partial_transparency) { iwopt_try_gray8_binary_trns(ctx,optctx); } if(optctx->imgtype==IW_IMGTYPE_GRAYA && optctx->bit_depth==16 && !optctx->has_partial_transparency) { iwopt_try_gray16_binary_trns(ctx,optctx); } }