void image_upsize(image_s * pdest, image_s * psrc, int32_t width, int32_t height) { int32_t vx, vy; #if !defined __i386__ && !defined __x86_64__ int32_t rx, ry; pix vcol; if((pdest == NULL) || (psrc == NULL)) return; for(vy = 0; vy < height; vy++) { for(vx = 0; vx < width; vx++) { rx = ((vx * psrc->width) / width); ry = ((vy * psrc->height) / height); vcol = get_pix(psrc, rx, ry); #else pix vcol,vcol1,vcol2,vcol3,vcol4; float rx,ry; float width_scale, height_scale; float x_dist, y_dist; width_scale = (float)psrc->width / (float)width; height_scale = (float)psrc->height / (float)height; for(vy = 0;vy < height; vy++) { for(vx = 0;vx < width; vx++) { rx = vx * width_scale; ry = vy * height_scale; vcol1 = get_pix(psrc, (int32_t)rx, (int32_t)ry); vcol2 = get_pix(psrc, ((int32_t)rx)+1, (int32_t)ry); vcol3 = get_pix(psrc, (int32_t)rx, ((int32_t)ry)+1); vcol4 = get_pix(psrc, ((int32_t)rx)+1, ((int32_t)ry)+1); x_dist = rx - ((float)((int32_t)rx)); y_dist = ry - ((float)((int32_t)ry)); vcol = COL_FULL( (uint8_t)((COL_RED(vcol1)*(1.0-x_dist) + COL_RED(vcol2)*(x_dist))*(1.0-y_dist) + (COL_RED(vcol3)*(1.0-x_dist) + COL_RED(vcol4)*(x_dist))*(y_dist)), (uint8_t)((COL_GREEN(vcol1)*(1.0-x_dist) + COL_GREEN(vcol2)*(x_dist))*(1.0-y_dist) + (COL_GREEN(vcol3)*(1.0-x_dist) + COL_GREEN(vcol4)*(x_dist))*(y_dist)), (uint8_t)((COL_BLUE(vcol1)*(1.0-x_dist) + COL_BLUE(vcol2)*(x_dist))*(1.0-y_dist) + (COL_BLUE(vcol3)*(1.0-x_dist) + COL_BLUE(vcol4)*(x_dist))*(y_dist)), (uint8_t)((COL_ALPHA(vcol1)*(1.0-x_dist) + COL_ALPHA(vcol2)*(x_dist))*(1.0-y_dist) + (COL_ALPHA(vcol3)*(1.0-x_dist) + COL_ALPHA(vcol4)*(x_dist))*(y_dist)) ); #endif put_pix_alpha_replace(pdest, vx, vy, vcol); } } } void image_downsize(image_s * pdest, image_s * psrc, int32_t width, int32_t height) { int32_t vx, vy; pix vcol; int32_t i, j; #if !defined __i386__ && !defined __x86_64__ int32_t rx, ry, rx_next, ry_next; int red, green, blue, alpha; int factor; if((pdest == NULL) || (psrc == NULL)) return; for(vy = 0; vy < height; vy++) { for(vx = 0; vx < width; vx++) { rx = ((vx * psrc->width) / width); ry = ((vy * psrc->height) / height); red = green = blue = alpha = 0; rx_next = rx + (psrc->width / width); ry_next = ry + (psrc->width / width); factor = 0; for( j = rx; j < rx_next; j++) { for( i = ry; i < ry_next; i++) { factor += 1; vcol = get_pix(psrc, j, i); red += COL_RED(vcol); green += COL_GREEN(vcol); blue += COL_BLUE(vcol); alpha += COL_ALPHA(vcol); } } red /= factor; green /= factor; blue /= factor; alpha /= factor; /* on sature les valeurs */ red = (red > 255) ? 255 : ((red < 0) ? 0 : red ); green = (green > 255) ? 255 : ((green < 0) ? 0 : green); blue = (blue > 255) ? 255 : ((blue < 0) ? 0 : blue ); alpha = (alpha > 255) ? 255 : ((alpha < 0) ? 0 : alpha); #else float rx,ry; float width_scale, height_scale; float red, green, blue, alpha; int32_t half_square_width, half_square_height; float round_width, round_height; if( (pdest == NULL) || (psrc == NULL) ) return; width_scale = (float)psrc->width / (float)width; height_scale = (float)psrc->height / (float)height; half_square_width = (int32_t)(width_scale / 2.0); half_square_height = (int32_t)(height_scale / 2.0); round_width = (width_scale / 2.0) - (float)half_square_width; round_height = (height_scale / 2.0) - (float)half_square_height; if(round_width > 0.0) half_square_width++; else round_width = 1.0; if(round_height > 0.0) half_square_height++; else round_height = 1.0; for(vy = 0;vy < height; vy++) { for(vx = 0;vx < width; vx++) { rx = vx * width_scale; ry = vy * height_scale; vcol = get_pix(psrc, (int32_t)rx, (int32_t)ry); red = green = blue = alpha = 0.0; for(j=0;j<half_square_height<<1;j++) { for(i=0;i<half_square_width<<1;i++) { vcol = get_pix(psrc, ((int32_t)rx)-half_square_width+i, ((int32_t)ry)-half_square_height+j); if(((j == 0) || (j == (half_square_height<<1)-1)) && ((i == 0) || (i == (half_square_width<<1)-1))) { red += round_width*round_height*(float)COL_RED (vcol); green += round_width*round_height*(float)COL_GREEN(vcol); blue += round_width*round_height*(float)COL_BLUE (vcol); alpha += round_width*round_height*(float)COL_ALPHA(vcol); } else if((j == 0) || (j == (half_square_height<<1)-1)) { red += round_height*(float)COL_RED (vcol); green += round_height*(float)COL_GREEN(vcol); blue += round_height*(float)COL_BLUE (vcol); alpha += round_height*(float)COL_ALPHA(vcol); } else if((i == 0) || (i == (half_square_width<<1)-1)) { red += round_width*(float)COL_RED (vcol); green += round_width*(float)COL_GREEN(vcol); blue += round_width*(float)COL_BLUE (vcol); alpha += round_width*(float)COL_ALPHA(vcol); } else { red += (float)COL_RED (vcol); green += (float)COL_GREEN(vcol); blue += (float)COL_BLUE (vcol); alpha += (float)COL_ALPHA(vcol); } } } red /= width_scale*height_scale; green /= width_scale*height_scale; blue /= width_scale*height_scale; alpha /= width_scale*height_scale; /* on sature les valeurs */ red = (red > 255.0)? 255.0 : ((red < 0.0)? 0.0:red ); green = (green > 255.0)? 255.0 : ((green < 0.0)? 0.0:green); blue = (blue > 255.0)? 255.0 : ((blue < 0.0)? 0.0:blue ); alpha = (alpha > 255.0)? 255.0 : ((alpha < 0.0)? 0.0:alpha); #endif put_pix_alpha_replace(pdest, vx, vy, COL_FULL((uint8_t)red, (uint8_t)green, (uint8_t)blue, (uint8_t)alpha)); } } } image_s * image_resize(image_s * src_image, int32_t width, int32_t height) { image_s * dst_image; dst_image = image_new(width, height); if( !dst_image ) return NULL; if( (src_image->width < width) || (src_image->height < height) ) image_upsize(dst_image, src_image, width, height); else image_downsize(dst_image, src_image, width, height); return dst_image; } unsigned char * image_save_to_jpeg_buf(image_s * pimage, int * size) { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPROW row_pointer[1]; int row_stride; char *data; int i, x; struct my_dst_mgr dst; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_memory_dest(&cinfo, &dst); cinfo.image_width = pimage->width; cinfo.image_height = pimage->height; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, JPEG_QUALITY, TRUE); jpeg_start_compress(&cinfo, TRUE); row_stride = cinfo.image_width * 3; if((data = malloc(row_stride)) == NULL) { DPRINTF(E_WARN, L_METADATA, "malloc failed\n"); if (dst.buf) free(dst.buf); jpeg_destroy_compress(&cinfo); return NULL; } i = 0; while(cinfo.next_scanline < cinfo.image_height) { for(x = 0; x < pimage->width; x++) { data[x * 3] = COL_RED(pimage->buf[i]); data[x * 3 + 1] = COL_GREEN(pimage->buf[i]); data[x * 3 + 2] = COL_BLUE(pimage->buf[i]); i++; } row_pointer[0] = (unsigned char *)data; jpeg_write_scanlines(&cinfo, row_pointer, 1); } jpeg_finish_compress(&cinfo); *size = dst.used; free(data); jpeg_destroy_compress(&cinfo); return dst.buf; } char * image_save_to_jpeg_file(image_s * pimage, char * path) { int nwritten, size = 0; unsigned char * buf; FILE * dst_file; buf = image_save_to_jpeg_buf(pimage, &size); if( !buf ) return NULL; dst_file = fopen(path, "w"); if( !dst_file ) { free(buf); return NULL; } nwritten = fwrite(buf, 1, size, dst_file); fclose(dst_file); free(buf); return (nwritten == size) ? path : NULL; }
void image_downsize_gd(image *im) { int x, y; float sy1, sy2, sx1, sx2; int dstX = 0, dstY = 0, srcX = 0, srcY = 0; float width_scale, height_scale; int dstW = im->target_width; int dstH = im->target_height; int srcW = im->width; int srcH = im->height; if (im->height_padding) { dstY = im->height_padding; dstH = im->height_inner; } if (im->width_padding) { dstX = im->width_padding; dstW = im->width_inner; } width_scale = (float)srcW / dstW; height_scale = (float)srcH / dstH; for (y = dstY; (y < dstY + dstH); y++) { sy1 = (float)(y - dstY) * height_scale; sy2 = (float)((y + 1) - dstY) * height_scale; for (x = dstX; (x < dstX + dstW); x++) { float sx, sy; float spixels = 0; float red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0; if (!im->has_alpha) alpha = 255.0; sx1 = (float)(x - dstX) * width_scale; sx2 = (float)((x + 1) - dstX) * width_scale; sy = sy1; //DEBUG_TRACE("sx1 %.2f, sx2 %.2f, sy1 %.2f, sy2 %.2f\n", sx1, sx2, sy1, sy2); do { float yportion; //DEBUG_TRACE(" yportion(sy %.2f, sy1 %.2f, sy2 %.2f) = ", sy, sy1, sy2); if (floor2(sy) == floor2(sy1)) { yportion = 1.0 - (sy - floor2(sy)); if (yportion > sy2 - sy1) { yportion = sy2 - sy1; } sy = floor2(sy); } else if (sy == floor2(sy2)) { yportion = sy2 - floor2(sy2); } else { yportion = 1.0; } //DEBUG_TRACE("%.2f\n", yportion); sx = sx1; do { float xportion = 1.0; float pcontribution; pix p; //DEBUG_TRACE(" xportion(sx %.2f, sx1 %.2f, sx2 %.2f) = ", sx, sx1, sx2); if (floor2(sx) == floor2(sx1)) { xportion = 1.0 - (sx - floor2(sx)); if (xportion > sx2 - sx1) { xportion = sx2 - sx1; } sx = floor2(sx); } else if (sx == floor2(sx2)) { xportion = sx2 - floor2(sx2); } else { xportion = 1.0; } //DEBUG_TRACE("%.2f\n", xportion); pcontribution = xportion * yportion; p = get_pix(im, (int32_t)sx + srcX, (int32_t)sy + srcY); /* DEBUG_TRACE(" merging with pix %d, %d: src %x (%d %d %d %d), pcontribution %.2f\n", (int32_t)sx + srcX, (int32_t)sy + srcY, p, COL_RED(p), COL_GREEN(p), COL_BLUE(p), COL_ALPHA(p), pcontribution); */ red += COL_RED(p) * pcontribution; green += COL_GREEN(p) * pcontribution; blue += COL_BLUE(p) * pcontribution; if (im->has_alpha) alpha += COL_ALPHA(p) * pcontribution; spixels += pcontribution; sx += 1.0; } while (sx < sx2); sy += 1.0; } while (sy < sy2); if (spixels != 0.0) { //DEBUG_TRACE(" rgba (%.2f %.2f %.2f %.2f) spixels %.2f\n", red, green, blue, alpha, spixels); spixels = 1 / spixels; red *= spixels; green *= spixels; blue *= spixels; if (im->has_alpha) alpha *= spixels; } /* Clamping to allow for rounding errors above */ if (red > 255.0) red = 255.0; if (green > 255.0) green = 255.0; if (blue > 255.0) blue = 255.0; if (im->has_alpha && alpha > 255.0) alpha = 255.0; /* DEBUG_TRACE(" -> %d, %d %x (%d %d %d %d)\n", x, y, COL_FULL((int)red, (int)green, (int)blue, (int)alpha), (int)red, (int)green, (int)blue, (int)alpha); */ if (im->orientation != ORIENTATION_NORMAL) { int ox, oy; // new destination pixel coordinates after rotating image_get_rotated_coords(im, x, y, &ox, &oy); if (im->orientation >= 5) { // 90 and 270 rotations, width/height are swapped so we have to use alternate put_pix method put_pix_rotated( im, ox, oy, im->target_height, COL_FULL(ROUND_FLOAT_TO_INT(red), ROUND_FLOAT_TO_INT(green), ROUND_FLOAT_TO_INT(blue), ROUND_FLOAT_TO_INT(alpha)) ); } else { put_pix( im, ox, oy, COL_FULL(ROUND_FLOAT_TO_INT(red), ROUND_FLOAT_TO_INT(green), ROUND_FLOAT_TO_INT(blue), ROUND_FLOAT_TO_INT(alpha)) ); } } else { put_pix( im, x, y, COL_FULL(ROUND_FLOAT_TO_INT(red), ROUND_FLOAT_TO_INT(green), ROUND_FLOAT_TO_INT(blue), ROUND_FLOAT_TO_INT(alpha)) ); } } } }
void image_downsize_gd_fixed_point(image *im) { int x, y; fixed_t sy1, sy2, sx1, sx2; int dstX = 0, dstY = 0, srcX = 0, srcY = 0; fixed_t width_scale, height_scale; int dstW = im->target_width; int dstH = im->target_height; int srcW = im->width; int srcH = im->height; if (im->height_padding) { dstY = im->height_padding; dstH = im->height_inner; } if (im->width_padding) { dstX = im->width_padding; dstW = im->width_inner; } width_scale = fixed_div(int_to_fixed(srcW), int_to_fixed(dstW)); height_scale = fixed_div(int_to_fixed(srcH), int_to_fixed(dstH)); for (y = dstY; (y < dstY + dstH); y++) { sy1 = fixed_mul(int_to_fixed(y - dstY), height_scale); sy2 = fixed_mul(int_to_fixed((y + 1) - dstY), height_scale); for (x = dstX; (x < dstX + dstW); x++) { fixed_t sx, sy; fixed_t spixels = 0; fixed_t red = 0, green = 0, blue = 0, alpha = 0; if (!im->has_alpha) alpha = FIXED_255; sx1 = fixed_mul(int_to_fixed(x - dstX), width_scale); sx2 = fixed_mul(int_to_fixed((x + 1) - dstX), width_scale); sy = sy1; /* DEBUG_TRACE("sx1 %f, sx2 %f, sy1 %f, sy2 %f\n", fixed_to_float(sx1), fixed_to_float(sx2), fixed_to_float(sy1), fixed_to_float(sy2)); */ do { fixed_t yportion; //DEBUG_TRACE(" yportion(sy %f, sy1 %f, sy2 %f) = ", fixed_to_float(sy), fixed_to_float(sy1), fixed_to_float(sy2)); if (fixed_floor(sy) == fixed_floor(sy1)) { yportion = FIXED_1 - (sy - fixed_floor(sy)); if (yportion > sy2 - sy1) { yportion = sy2 - sy1; } sy = fixed_floor(sy); } else if (sy == fixed_floor(sy2)) { yportion = sy2 - fixed_floor(sy2); } else { yportion = FIXED_1; } //DEBUG_TRACE("%f\n", fixed_to_float(yportion)); sx = sx1; do { fixed_t xportion; fixed_t pcontribution; pix p; //DEBUG_TRACE(" xportion(sx %f, sx1 %f, sx2 %f) = ", fixed_to_float(sx), fixed_to_float(sx1), fixed_to_float(sx2)); if (fixed_floor(sx) == fixed_floor(sx1)) { xportion = FIXED_1 - (sx - fixed_floor(sx)); if (xportion > sx2 - sx1) { xportion = sx2 - sx1; } sx = fixed_floor(sx); } else if (sx == fixed_floor(sx2)) { xportion = sx2 - fixed_floor(sx2); } else { xportion = FIXED_1; } //DEBUG_TRACE("%f\n", fixed_to_float(xportion)); pcontribution = fixed_mul(xportion, yportion); p = get_pix(im, fixed_to_int(sx + srcX), fixed_to_int(sy + srcY)); /* DEBUG_TRACE(" merging with pix %d, %d: src %x (%d %d %d %d), pcontribution %f\n", fixed_to_int(sx + srcX), fixed_to_int(sy + srcY), p, COL_RED(p), COL_GREEN(p), COL_BLUE(p), COL_ALPHA(p), fixed_to_float(pcontribution)); */ red += fixed_mul(int_to_fixed(COL_RED(p)), pcontribution); green += fixed_mul(int_to_fixed(COL_GREEN(p)), pcontribution); blue += fixed_mul(int_to_fixed(COL_BLUE(p)), pcontribution); if (im->has_alpha) alpha += fixed_mul(int_to_fixed(COL_ALPHA(p)), pcontribution); spixels += pcontribution; sx += FIXED_1; } while (sx < sx2); sy += FIXED_1; } while (sy < sy2); // If rgba get too large for the fixed-point representation, fallback to the floating point routine // This should only happen with very large images if (red < 0 || green < 0 || blue < 0 || alpha < 0) { warn("fixed-point overflow: %d %d %d %d\n", red, green, blue, alpha); return image_downsize_gd(im); } if (spixels != 0) { /* DEBUG_TRACE(" rgba (%f %f %f %f) spixels %f\n", fixed_to_float(red), fixed_to_float(green), fixed_to_float(blue), fixed_to_float(alpha), fixed_to_float(spixels)); */ spixels = fixed_div(FIXED_1, spixels); red = fixed_mul(red, spixels); green = fixed_mul(green, spixels); blue = fixed_mul(blue, spixels); if (im->has_alpha) alpha = fixed_mul(alpha, spixels); } /* Clamping to allow for rounding errors above */ if (red > FIXED_255) red = FIXED_255; if (green > FIXED_255) green = FIXED_255; if (blue > FIXED_255) blue = FIXED_255; if (im->has_alpha && alpha > FIXED_255) alpha = FIXED_255; /* DEBUG_TRACE(" -> %d, %d %x (%d %d %d %d)\n", x, y, COL_FULL(fixed_to_int(red), fixed_to_int(green), fixed_to_int(blue), fixed_to_int(alpha)), fixed_to_int(red), fixed_to_int(green), fixed_to_int(blue), fixed_to_int(alpha)); */ if (im->orientation != ORIENTATION_NORMAL) { int ox, oy; // new destination pixel coordinates after rotating image_get_rotated_coords(im, x, y, &ox, &oy); if (im->orientation >= 5) { // 90 and 270 rotations, width/height are swapped so we have to use alternate put_pix method put_pix_rotated( im, ox, oy, im->target_height, COL_FULL(fixed_to_int(red), fixed_to_int(green), fixed_to_int(blue), fixed_to_int(alpha)) ); } else { put_pix( im, ox, oy, COL_FULL(fixed_to_int(red), fixed_to_int(green), fixed_to_int(blue), fixed_to_int(alpha)) ); } } else { put_pix( im, x, y, COL_FULL(fixed_to_int(red), fixed_to_int(green), fixed_to_int(blue), fixed_to_int(alpha)) ); } } } }
int image_png_compress(MediaScanImage *i, MediaScanThumbSpec *spec) { int j, x, y; int color_space = PNG_COLOR_TYPE_RGB_ALPHA; volatile unsigned char *ptr = NULL; png_structp png_ptr; png_infop info_ptr; Buffer *buf; if (!i->_pixbuf_size) { LOG_WARN("PNG compression requires pixbuf data (%s)\n", i->path); return 0; } png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { FATAL("Could not initialize libpng\n"); } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, NULL); FATAL("Could not initialize libpng\n"); } // Initialize buffer for compressed data buf = (Buffer *)malloc(sizeof(Buffer)); buffer_init(buf, BUF_SIZE); i->_dbuf = (void *)buf; png_set_write_fn(png_ptr, buf, image_png_write_buf, image_png_flush_buf); if (setjmp(png_jmpbuf(png_ptr))) { if (ptr != NULL) free((void *)ptr); return 0; } // Match output color space with input file switch (i->channels) { case 4: case 3: LOG_DEBUG("PNG output color space set to RGBA\n"); color_space = PNG_COLOR_TYPE_RGB_ALPHA; break; case 2: case 1: LOG_DEBUG("PNG output color space set to gray alpha\n"); color_space = PNG_COLOR_TYPE_GRAY_ALPHA; break; } png_set_IHDR(png_ptr, info_ptr, spec->width, spec->height, 8, color_space, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_write_info(png_ptr, info_ptr); ptr = (unsigned char *)malloc(png_get_rowbytes(png_ptr, info_ptr)); j = 0; if (color_space == PNG_COLOR_TYPE_GRAY_ALPHA) { for (y = 0; y < spec->height; y++) { for (x = 0; x < spec->width; x++) { ptr[x * 2] = COL_BLUE(i->_pixbuf[j]); ptr[x * 2 + 1] = COL_ALPHA(i->_pixbuf[j]); j++; } png_write_row(png_ptr, (png_bytep) ptr); } } else { // RGB for (y = 0; y < spec->height; y++) { for (x = 0; x < spec->width; x++) { ptr[x * 4] = COL_RED(i->_pixbuf[j]); ptr[x * 4 + 1] = COL_GREEN(i->_pixbuf[j]); ptr[x * 4 + 2] = COL_BLUE(i->_pixbuf[j]); ptr[x * 4 + 3] = COL_ALPHA(i->_pixbuf[j]); j++; } png_write_row(png_ptr, (png_bytep) ptr); } } free((void *)ptr); png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); return 1; }
// Compress the data from i->_pixbuf to i->data. // Uses libjpeg-turbo if available (JCS_EXTENSIONS) for better performance int image_jpeg_compress(MediaScanImage *i, MediaScanThumbSpec *spec) { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; struct buf_dst_mgr dst; int quality = spec->jpeg_quality; int x; #ifdef JCS_EXTENSIONS JSAMPROW *data = NULL; #else volatile unsigned char *data = NULL; // volatile = won't be rolled back if longjmp is called JSAMPROW row_pointer[1]; int y, row_stride; #endif if (!i->_pixbuf_size) { LOG_WARN("JPEG compression requires pixbuf data (%s)\n", i->path); exit(-1); return 0; } if (!quality) quality = DEFAULT_JPEG_QUALITY; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); image_jpeg_buf_dest(&cinfo, &dst); cinfo.image_width = i->width; cinfo.image_height = i->height; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; // output is always RGB even if source was grayscale if (setjmp(setjmp_buffer)) { if (data != NULL) { LOG_MEM("destroy JPEG data row @ %p\n", data); free((void *)data); } return 0; } #ifdef JCS_EXTENSIONS // Use libjpeg-turbo support for direct reading from source buffer cinfo.input_components = 4; cinfo.in_color_space = JCS_EXT_XBGR; #endif jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, TRUE); jpeg_start_compress(&cinfo, TRUE); #ifdef JCS_EXTENSIONS data = (JSAMPROW *)malloc(i->height * sizeof(JSAMPROW)); LOG_MEM("new JPEG data row @ %p\n", data); for (x = 0; x < i->height; x++) data[x] = (JSAMPROW)&i->_pixbuf[x * i->width]; while (cinfo.next_scanline < cinfo.image_height) { jpeg_write_scanlines(&cinfo, &data[cinfo.next_scanline], cinfo.image_height - cinfo.next_scanline); } #else // Normal libjpeg row_stride = cinfo.image_width * 3; data = (unsigned char *)malloc(row_stride); LOG_MEM("new JPEG data row @ %p\n", data); y = 0; while (cinfo.next_scanline < cinfo.image_height) { for (x = 0; x < cinfo.image_width; x++) { data[x + x + x] = COL_RED(i->_pixbuf[y]); data[x + x + x + 1] = COL_GREEN(i->_pixbuf[y]); data[x + x + x + 2] = COL_BLUE(i->_pixbuf[y]); y++; } row_pointer[0] = (unsigned char *)data; jpeg_write_scanlines(&cinfo, row_pointer, 1); } #endif jpeg_finish_compress(&cinfo); LOG_MEM("destroy JPEG data row @ %p\n", data); free((void *)data); jpeg_destroy_compress(&cinfo); // Attach compressed buffer to image i->_dbuf = (void *)dst.dbuf; return 1; }
void write_png_file(char* file_name) { int j, x, y; int color_space = PNG_COLOR_TYPE_RGB_ALPHA; volatile unsigned char *ptr = NULL; png_structp png_ptr; png_infop info_ptr; // Buffer *buf; FILE *fp = fopen(file_name, "wb"); if (!result._thumbs[0]->_pixbuf_size) { LOG_WARN("PNG compression requires pixbuf data\n"); return; } png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { FATAL("Could not initialize libpng\n"); } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, NULL); FATAL("Could not initialize libpng\n"); } if (setjmp(png_jmpbuf(png_ptr))) { if (ptr != NULL) free((void *)ptr); return; } png_init_io(png_ptr, fp); /* write header */ if (setjmp(png_jmpbuf(png_ptr))) abort_("[write_png_file] Error during writing header"); // Match output color space with input file switch (result._thumbs[0]->channels) { case 4: case 3: LOG_DEBUG("PNG output color space set to RGBA\n"); color_space = PNG_COLOR_TYPE_RGB_ALPHA; break; case 2: case 1: LOG_DEBUG("PNG output color space set to gray alpha\n"); color_space = PNG_COLOR_TYPE_GRAY_ALPHA; break; } png_set_IHDR(png_ptr, info_ptr, result._thumbs[0]->width, result._thumbs[0]->height, 8, color_space, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_write_info(png_ptr, info_ptr); /* write bytes */ if (setjmp(png_jmpbuf(png_ptr))) abort_("[write_png_file] Error during writing bytes"); ptr = (unsigned char *)malloc(png_get_rowbytes(png_ptr, info_ptr)); j = 0; if (color_space == PNG_COLOR_TYPE_GRAY_ALPHA) { for (y = 0; y < result._thumbs[0]->height; y++) { for (x = 0; x < result._thumbs[0]->width; x++) { ptr[x * 2] = COL_BLUE(result._thumbs[0]->_pixbuf[j]); ptr[x * 2 + 1] = COL_ALPHA(result._thumbs[0]->_pixbuf[j]); j++; } png_write_row(png_ptr, (png_bytep) ptr); } } else { // RGB for (y = 0; y < result._thumbs[0]->height; y++) { for (x = 0; x < result._thumbs[0]->width; x++) { ptr[x * 4] = COL_RED(result._thumbs[0]->_pixbuf[j]); ptr[x * 4 + 1] = COL_GREEN(result._thumbs[0]->_pixbuf[j]); ptr[x * 4 + 2] = COL_BLUE(result._thumbs[0]->_pixbuf[j]); ptr[x * 4 + 3] = COL_ALPHA(result._thumbs[0]->_pixbuf[j]); j++; } png_write_row(png_ptr, (png_bytep) ptr); } } free((void *)ptr); /* end write */ if (setjmp(png_jmpbuf(png_ptr))) abort_("[write_png_file] Error during end of write"); png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); }