void jpeg_encode (byte *image, cpoint *tile_size, byte *outbuff, int *size, int bpp, int line_bytes, int quality) { struct jpeg_compress_struct cinfo; jpeg_dest_info dest; struct my_error_mgr jerr; JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ int row_stride = line_bytes; /* physical row width in image buffer */ byte *buff, *ptr; int bytes; cinfo.err = jpeg_std_error(&jerr.mgr); jpeg_create_compress(&cinfo); cinfo.dest = &dest.pub; dest.data = outbuff; dest.size = *size; // dest.pub.next_output_byte = NULL; // dest.pub.free_in_buffer = 0; dest.pub.next_output_byte = outbuff; dest.pub.free_in_buffer = *size; dest.pub.init_destination = init_destination; dest.pub.empty_output_buffer = empty_output_buffer; dest.pub.term_destination = term_destination; // printf ("jpeg_encode: bpp=%d\n", bpp); *size = 0; buff = (byte *)malloc (row_stride); if (!buff) return; // should report error, but I suppose *size is 0 jerr.err = 0; jerr.mgr.error_exit = my_error_exit; if (!setjmp(jerr.setjmp_buffer)) { /* Step 3: set parameters for compression */ /* First we supply a description of the input image. * Four fields of the cinfo struct must be filled in: */ cinfo.image_width = tile_size->x; /* image width and height, in pixels */ cinfo.image_height = tile_size->y; cinfo.input_components = bpp == 8 ? 1 : 3; /* # of color components per pixel */ cinfo.in_color_space = bpp == 8 ? JCS_GRAYSCALE : JCS_RGB; /* colorspace of input image */ bytes = cinfo.image_width * bpp / 8; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); jpeg_start_compress(&cinfo, TRUE); while (cinfo.next_scanline < cinfo.image_height) { /* jpeg_write_scanlines expects an array of pointers to scanlines. * Here the array is only one element long, but you could pass * more than one scanline at a time if that's more convenient. */ row_pointer[0] = buff; //&image [cinfo.next_scanline * row_stride]; ptr = &image [cinfo.next_scanline * row_stride]; if (bpp == 32) { int i; u_int32_t *in; byte *out; for (i = cinfo.image_width, in = (unsigned *)ptr, out = buff; i != 0; i--, in++, out += 3) { out [2] = *in; out [1] = *in >> 8; out [0] = *in >> 16; } } else
DLLEXPORT int DLLCALL tjCompress(tjhandle h, unsigned char *srcbuf, int width, int pitch, int height, int ps, unsigned char *dstbuf, unsigned long *size, int jpegsub, int qual, int flags) { int i, retval=0; JSAMPROW *row_pointer=NULL; JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS]; JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS]; JSAMPROW *outbuf[MAX_COMPONENTS]; checkhandle(h); for(i=0; i<MAX_COMPONENTS; i++) { tmpbuf[i]=NULL; _tmpbuf[i]=NULL; tmpbuf2[i]=NULL; _tmpbuf2[i]=NULL; outbuf[i]=NULL; } if(srcbuf==NULL || width<=0 || pitch<0 || height<=0 || dstbuf==NULL || size==NULL || jpegsub<0 || jpegsub>=NUMSUBOPT || qual<0 || qual>100) _throw("Invalid argument in tjCompress()"); if(ps!=3 && ps!=4 && ps!=1) _throw("This compressor can only handle 24-bit and 32-bit RGB or 8-bit grayscale input"); if(!j->initc) _throw("Instance has not been initialized for compression"); if(pitch==0) pitch=width*ps; j->cinfo.image_width = width; j->cinfo.image_height = height; j->cinfo.input_components = ps; if(ps==1) j->cinfo.in_color_space = JCS_GRAYSCALE; #if JCS_EXTENSIONS==1 else j->cinfo.in_color_space = JCS_EXT_RGB; if(ps==3 && (flags&TJ_BGR)) j->cinfo.in_color_space = JCS_EXT_BGR; else if(ps==4 && !(flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST)) j->cinfo.in_color_space = JCS_EXT_RGBX; else if(ps==4 && (flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST)) j->cinfo.in_color_space = JCS_EXT_BGRX; else if(ps==4 && (flags&TJ_BGR) && (flags&TJ_ALPHAFIRST)) j->cinfo.in_color_space = JCS_EXT_XBGR; else if(ps==4 && !(flags&TJ_BGR) && (flags&TJ_ALPHAFIRST)) j->cinfo.in_color_space = JCS_EXT_XRGB; #else #error "TurboJPEG requires JPEG colorspace extensions" #endif if(flags&TJ_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); else if(flags&TJ_FORCESSE) putenv("JSIMD_FORCESSE=1"); else if(flags&TJ_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); if(setjmp(j->jerr.jb)) { // this will execute if LIBJPEG has an error retval=-1; goto bailout; } jpeg_set_defaults(&j->cinfo); jpeg_set_quality(&j->cinfo, qual, TRUE); if(jpegsub==TJ_GRAYSCALE) jpeg_set_colorspace(&j->cinfo, JCS_GRAYSCALE); else jpeg_set_colorspace(&j->cinfo, JCS_YCbCr); if(qual>=96) j->cinfo.dct_method=JDCT_ISLOW; else j->cinfo.dct_method=JDCT_FASTEST; j->cinfo.comp_info[0].h_samp_factor=hsampfactor[jpegsub]; j->cinfo.comp_info[1].h_samp_factor=1; j->cinfo.comp_info[2].h_samp_factor=1; j->cinfo.comp_info[0].v_samp_factor=vsampfactor[jpegsub]; j->cinfo.comp_info[1].v_samp_factor=1; j->cinfo.comp_info[2].v_samp_factor=1; j->jdms.next_output_byte = dstbuf; j->jdms.free_in_buffer = TJBUFSIZE(j->cinfo.image_width, j->cinfo.image_height); jpeg_start_compress(&j->cinfo, TRUE); if(flags&TJ_YUV) { j_compress_ptr cinfo=&j->cinfo; int row; int pw=PAD(width, cinfo->max_h_samp_factor); int ph=PAD(height, cinfo->max_v_samp_factor); int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS]; jpeg_component_info *compptr; JSAMPLE *ptr=dstbuf; unsigned long yuvsize=0; if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph))==NULL) _throw("Memory allocation failed in tjCompress()"); for(i=0; i<height; i++) { if(flags&TJ_BOTTOMUP) row_pointer[i]= &srcbuf[(height-i-1)*pitch]; else row_pointer[i]= &srcbuf[i*pitch]; } if(height<ph) for(i=height; i<ph; i++) row_pointer[i]=row_pointer[height-1]; for(i=0; i<cinfo->num_components; i++) { compptr=&cinfo->comp_info[i]; _tmpbuf[i]=(JSAMPLE *)malloc( PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE) /compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16); if(!_tmpbuf[i]) _throw("Memory allocation failure"); tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor); if(!tmpbuf[i]) _throw("Memory allocation failure"); for(row=0; row<cinfo->max_v_samp_factor; row++) { unsigned char *_tmpbuf_aligned= (unsigned char *)PAD((size_t)_tmpbuf[i], 16); tmpbuf[i][row]=&_tmpbuf_aligned[ PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE) /compptr->h_samp_factor, 16) * row]; } _tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16) * compptr->v_samp_factor + 16); if(!_tmpbuf2[i]) _throw("Memory allocation failure"); tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor); if(!tmpbuf2[i]) _throw("Memory allocation failure"); for(row=0; row<compptr->v_samp_factor; row++) { unsigned char *_tmpbuf2_aligned= (unsigned char *)PAD((size_t)_tmpbuf2[i], 16); tmpbuf2[i][row]=&_tmpbuf2_aligned[ PAD(compptr->width_in_blocks*DCTSIZE, 16) * row]; } cw[i]=pw*compptr->h_samp_factor/cinfo->max_h_samp_factor; ch[i]=ph*compptr->v_samp_factor/cinfo->max_v_samp_factor; outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]); if(!outbuf[i]) _throw("Memory allocation failure"); for(row=0; row<ch[i]; row++) { outbuf[i][row]=ptr; ptr+=PAD(cw[i], 4); } } yuvsize=(unsigned long)(ptr-dstbuf); for(row=0; row<ph; row+=cinfo->max_v_samp_factor) { (*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf, 0, cinfo->max_v_samp_factor); (cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0); for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components; i++, compptr++) jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i], row*compptr->v_samp_factor/cinfo->max_v_samp_factor, compptr->v_samp_factor, cw[i]); } *size=yuvsize; cinfo->next_scanline+=height; } else { if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL) _throw("Memory allocation failed in tjCompress()"); for(i=0; i<height; i++) { if(flags&TJ_BOTTOMUP) row_pointer[i]= &srcbuf[(height-i-1)*pitch]; else row_pointer[i]= &srcbuf[i*pitch]; } while(j->cinfo.next_scanline<j->cinfo.image_height) { jpeg_write_scanlines(&j->cinfo, &row_pointer[j->cinfo.next_scanline], j->cinfo.image_height-j->cinfo.next_scanline); } } jpeg_finish_compress(&j->cinfo); if(!(flags&TJ_YUV)) *size=TJBUFSIZE(j->cinfo.image_width, j->cinfo.image_height) -(unsigned long)(j->jdms.free_in_buffer); bailout: if(j->cinfo.global_state>CSTATE_START) jpeg_abort_compress(&j->cinfo); if(row_pointer) free(row_pointer); for(i=0; i<MAX_COMPONENTS; i++) { if(tmpbuf[i]!=NULL) free(tmpbuf[i]); if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]); if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]); if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]); if(outbuf[i]!=NULL) free(outbuf[i]); } return retval; }
bool CJpegIO::CreateThumbnailFromSurface(unsigned char* bufferin, unsigned int width, unsigned int height, unsigned int format, unsigned int pitch, const CStdString& destFile, unsigned char* &bufferout, unsigned int &bufferoutSize) { //Encode raw data from buffer, save to destbuffer struct jpeg_compress_struct cinfo; struct my_error_mgr jerr; JSAMPROW row_pointer[1]; long unsigned int outBufSize = width * height; unsigned char* src = bufferin; unsigned char* rgbbuf; if(bufferin == NULL) { CLog::Log(LOGERROR, "JpegIO::CreateThumbnailFromSurface no buffer"); return false; } m_thumbnailbuffer = (unsigned char*) malloc(outBufSize); //Initial buffer. Grows as-needed. if (m_thumbnailbuffer == NULL) { CLog::Log(LOGERROR, "JpegIO::CreateThumbnailFromSurface error allocating memory for image buffer"); return false; } if(format == XB_FMT_RGB8) { rgbbuf = bufferin; } else if(format == XB_FMT_A8R8G8B8) { // create a copy for bgra -> rgb. rgbbuf = new unsigned char [(width * height * 3)]; unsigned char* dst = rgbbuf; for (unsigned int y = 0; y < height; y++) { unsigned char* dst2 = dst; unsigned char* src2 = src; for (unsigned int x = 0; x < width; x++, src2 += 4) { *dst2++ = src2[2]; *dst2++ = src2[1]; *dst2++ = src2[0]; } dst += width * 3; src += pitch; } } else { CLog::Log(LOGWARNING, "JpegIO::CreateThumbnailFromSurface Unsupported format"); free(m_thumbnailbuffer); return false; } cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = jpeg_error_exit; jpeg_create_compress(&cinfo); if (setjmp(jerr.setjmp_buffer)) { jpeg_destroy_compress(&cinfo); free(m_thumbnailbuffer); if(format != XB_FMT_RGB8) delete [] rgbbuf; return false; } else { #if JPEG_LIB_VERSION < 80 x_jpeg_mem_dest(&cinfo, &m_thumbnailbuffer, &outBufSize); #else jpeg_mem_dest(&cinfo, &m_thumbnailbuffer, &outBufSize); #endif cinfo.image_width = width; cinfo.image_height = height; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, 90, TRUE); jpeg_start_compress(&cinfo, TRUE); while (cinfo.next_scanline < cinfo.image_height) { row_pointer[0] = &rgbbuf[cinfo.next_scanline * width * 3]; jpeg_write_scanlines(&cinfo, row_pointer, 1); } jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); } if(format != XB_FMT_RGB8) delete [] rgbbuf; bufferout = m_thumbnailbuffer; bufferoutSize = outBufSize; return true; }
/* write_JPEG_memory: store JPEG compressed image into memory. */ static bool writeJPEGFile(io::IWriteFile* file, IImage* image, u32 quality) { void (*format)(const void*, s32, void*) = 0; switch( image->getColorFormat () ) { case ECF_R8G8B8: format = CColorConverter::convert_R8G8B8toR8G8B8; break; case ECF_A8R8G8B8: format = CColorConverter::convert_A8R8G8B8toR8G8B8; break; case ECF_A1R5G5B5: format = CColorConverter::convert_A1R5G5B5toB8G8R8; break; case ECF_R5G6B5: format = CColorConverter::convert_R5G6B5toR8G8B8; break; } // couldn't find a color converter if ( 0 == format ) return false; const core::dimension2di dim = image->getDimension(); struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_file_dest(&cinfo, file); cinfo.image_width = dim.Width; cinfo.image_height = dim.Height; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); if ( 0 == quality ) quality = 75; jpeg_set_quality(&cinfo, quality, TRUE); jpeg_start_compress(&cinfo, TRUE); u8 * dest = new u8[dim.Width*3]; if (dest) { const u32 pitch = image->getPitch(); JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ row_pointer[0] = dest; u8* src = (u8*)image->lock(); while (cinfo.next_scanline < cinfo.image_height) { // convert next line format( src, dim.Width, dest ); src += pitch; jpeg_write_scanlines(&cinfo, row_pointer, 1); } image->unlock(); delete [] dest; /* Step 6: Finish compression */ jpeg_finish_compress(&cinfo); } /* Step 7: Destroy */ jpeg_destroy_compress(&cinfo); return (dest != 0); }
int jpg_save_vidframe(const struct vidframe *vf, const char *path) { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPROW row_pointer[1]; unsigned char *imgdata,*src,*dst; int row_stride,pixs; FILE * fp; char filename_buf[64]; struct vidframe *f2 = NULL; int err = 0; unsigned int width = vf->size.w & ~1; unsigned int height = vf->size.h & ~1; time_t tnow; struct tm *tmx; // 0 tnow = time(NULL); tmx = localtime(&tnow); imgdata = vf->data[0]; if (vf->fmt != VID_FMT_RGB32) { err = vidframe_alloc(&f2, VID_FMT_RGB32, &vf->size); if (err) goto out; vidconv(f2, vf, NULL); imgdata = f2->data[0]; } fp = fopen(jpg_filename(tmx, path, filename_buf, sizeof(filename_buf)), "wb"); if (fp == NULL) { err = errno; goto out; } // 32bpp -> 24bpp pixs = width*height; src = imgdata; dst = imgdata; while (pixs--) { *dst++=*src++; //R *dst++=*src++; //G *dst++=*src++; //B src++; //A } // create jpg structures cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, fp); cinfo.image_width = width; cinfo.image_height = height; cinfo.input_components = 3; // 24 bpp // I wonder if this will make double conversion. cinfo.in_color_space = JCS_EXT_BGR; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, 85 , TRUE); // quality 85% // compress jpeg_start_compress(&cinfo, TRUE); row_stride = width * cinfo.input_components; //buffer = (JSAMPARRAY) imgdata; while (cinfo.next_scanline < cinfo.image_height) { row_pointer[0] = & imgdata[cinfo.next_scanline * row_stride]; (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); } jpeg_finish_compress(&cinfo); /* Finish writing. */ out: jpeg_destroy_compress(&cinfo); mem_deref(f2); if (fp) fclose(fp); return 0; }
/*! Tries to write the image object to the given output stream. Returns true on success. */ bool JPGImageFileType::write(const ImagePtr &OSG_JPG_ARG(image), std::ostream &OSG_JPG_ARG(os), const std::string &OSG_JPG_ARG(mimetype)) { #ifdef OSG_WITH_JPG if ((image->getBpp() != 1 && image->getBpp() != 3) || image->getDepth() != 1) { SWARNING << getMimeType() << " JPEG write only works for 2D 1 or 3 bpp images " << std::endl; return false; } struct osg_jpeg_error_mgr jerr; struct jpeg_compress_struct cinfo; cinfo.err = jpeg_std_error(&jerr.pub); if (setjmp(jerr.setjmp_buffer)) return false; cinfo.err->error_exit = osg_jpeg_error_exit; cinfo.err->output_message = osg_jpeg_output_message; jpeg_create_compress(&cinfo); DestinationManager *destinationManager = new ((*cinfo.mem->alloc_small)(reinterpret_cast<j_common_ptr>(&cinfo), JPOOL_IMAGE, sizeof(DestinationManager))) DestinationManager(&cinfo, os); cinfo.dest = reinterpret_cast<jpeg_destination_mgr*>(destinationManager); cinfo.image_width = image->getWidth(); cinfo.image_height = image->getHeight(); cinfo.input_components = image->getBpp(); cinfo.in_color_space = (image->getBpp() == 1) ? JCS_GRAYSCALE : JCS_RGB; jpeg_set_defaults(&cinfo); int quality = _quality; const std::string *qualityAttr = image->findAttachmentField(_qualityKey); if (qualityAttr != 0) sscanf(qualityAttr->c_str(), "%i", &quality); jpeg_set_quality(&cinfo, quality, TRUE); cinfo.density_unit = 1; // dpi cinfo.X_density = UInt16(image->getResX() < 0.0f ? image->getResX() - 0.5f : image->getResX() + 0.5f); cinfo.Y_density = UInt16(image->getResY() < 0.0f ? image->getResY() - 0.5f : image->getResY() + 0.5f); jpeg_start_compress(&cinfo, TRUE); const unsigned char *srcData = image->getData() + image->getSize(); int row_stride = cinfo.image_width * cinfo.input_components; while (cinfo.next_scanline < cinfo.image_height) { srcData -= row_stride; jpeg_write_scanlines(&cinfo, const_cast<unsigned char **>(&srcData), 1); } jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); return true; #else SWARNING << getMimeType() << " write is not compiled into the current binary " << std::endl; return false; #endif }
int ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) { JPEGENCODERSTATE* context = (JPEGENCODERSTATE*) state->context; int ok; if (setjmp(context->error.setjmp_buffer)) { /* JPEG error handler */ jpeg_destroy_compress(&context->cinfo); state->errcode = IMAGING_CODEC_BROKEN; return -1; } if (!state->state) { /* Setup compression context (very similar to the decoder) */ context->cinfo.err = jpeg_std_error(&context->error.pub); context->error.pub.error_exit = error; jpeg_create_compress(&context->cinfo); jpeg_buffer_dest(&context->cinfo, &context->destination); context->extra_offset = 0; /* Ready to encode */ state->state = 1; } /* Load the destination buffer */ context->destination.pub.next_output_byte = buf; context->destination.pub.free_in_buffer = bytes; switch (state->state) { case 1: context->cinfo.image_width = state->xsize; context->cinfo.image_height = state->ysize; switch (state->bits) { case 8: context->cinfo.input_components = 1; context->cinfo.in_color_space = JCS_GRAYSCALE; break; case 24: context->cinfo.input_components = 3; if (strcmp(im->mode, "YCbCr") == 0) context->cinfo.in_color_space = JCS_YCbCr; else context->cinfo.in_color_space = JCS_RGB; break; case 32: context->cinfo.input_components = 4; context->cinfo.in_color_space = JCS_CMYK; break; default: state->errcode = IMAGING_CODEC_CONFIG; return -1; } /* Compressor configuration */ jpeg_set_defaults(&context->cinfo); /* Use custom quantization tables */ if (context->qtables) { int i; int quality = 100; int last_q = 0; if (context->quality > 0) { quality = context->quality; } for (i = 0; i < context->qtablesLen; i++) { // TODO: Should add support for none baseline jpeg_add_quant_table(&context->cinfo, i, &context->qtables[i * DCTSIZE2], quality, TRUE); context->cinfo.comp_info[i].quant_tbl_no = i; last_q = i; } if (context->qtablesLen == 1) { // jpeg_set_defaults created two qtables internally, but we only wanted one. jpeg_add_quant_table(&context->cinfo, 1, &context->qtables[0], quality, TRUE); } for (i = last_q; i < context->cinfo.num_components; i++) { context->cinfo.comp_info[i].quant_tbl_no = last_q; } } else if (context->quality > 0) { jpeg_set_quality(&context->cinfo, context->quality, 1); } /* Set subsampling options */ switch (context->subsampling) { case 0: /* 1x1 1x1 1x1 (4:4:4) : None */ { context->cinfo.comp_info[0].h_samp_factor = 1; context->cinfo.comp_info[0].v_samp_factor = 1; context->cinfo.comp_info[1].h_samp_factor = 1; context->cinfo.comp_info[1].v_samp_factor = 1; context->cinfo.comp_info[2].h_samp_factor = 1; context->cinfo.comp_info[2].v_samp_factor = 1; break; } case 1: /* 2x1, 1x1, 1x1 (4:2:2) : Medium */ { context->cinfo.comp_info[0].h_samp_factor = 2; context->cinfo.comp_info[0].v_samp_factor = 1; context->cinfo.comp_info[1].h_samp_factor = 1; context->cinfo.comp_info[1].v_samp_factor = 1; context->cinfo.comp_info[2].h_samp_factor = 1; context->cinfo.comp_info[2].v_samp_factor = 1; break; } case 2: /* 2x2, 1x1, 1x1 (4:1:1) : High */ { context->cinfo.comp_info[0].h_samp_factor = 2; context->cinfo.comp_info[0].v_samp_factor = 2; context->cinfo.comp_info[1].h_samp_factor = 1; context->cinfo.comp_info[1].v_samp_factor = 1; context->cinfo.comp_info[2].h_samp_factor = 1; context->cinfo.comp_info[2].v_samp_factor = 1; break; } default: { /* Use the lib's default */ break; } } if (context->progressive) jpeg_simple_progression(&context->cinfo); context->cinfo.smoothing_factor = context->smooth; context->cinfo.optimize_coding = (boolean) context->optimize; if (context->xdpi > 0 && context->ydpi > 0) { context->cinfo.density_unit = 1; /* dots per inch */ context->cinfo.X_density = context->xdpi; context->cinfo.Y_density = context->ydpi; } switch (context->streamtype) { case 1: /* tables only -- not yet implemented */ state->errcode = IMAGING_CODEC_CONFIG; return -1; case 2: /* image only */ jpeg_suppress_tables(&context->cinfo, TRUE); jpeg_start_compress(&context->cinfo, FALSE); /* suppress extra section */ context->extra_offset = context->extra_size; break; default: /* interchange stream */ jpeg_start_compress(&context->cinfo, TRUE); break; } state->state++; /* fall through */ case 2: // check for exif len + 'APP1' header bytes if (context->rawExifLen + 5 > context->destination.pub.free_in_buffer){ break; } //add exif header if (context->rawExifLen > 0){ jpeg_write_marker(&context->cinfo, JPEG_APP0+1, (unsigned char*)context->rawExif, context->rawExifLen); } state->state++; /* fall through */ case 3: if (context->extra) { /* copy extra buffer to output buffer */ unsigned int n = context->extra_size - context->extra_offset; if (n > context->destination.pub.free_in_buffer) n = context->destination.pub.free_in_buffer; memcpy(context->destination.pub.next_output_byte, context->extra + context->extra_offset, n); context->destination.pub.next_output_byte += n; context->destination.pub.free_in_buffer -= n; context->extra_offset += n; if (context->extra_offset >= context->extra_size) state->state++; else break; } else state->state++; case 4: if (1024 > context->destination.pub.free_in_buffer){ break; } ok = 1; while (state->y < state->ysize) { state->shuffle(state->buffer, (UINT8*) im->image[state->y + state->yoff] + state->xoff * im->pixelsize, state->xsize); ok = jpeg_write_scanlines(&context->cinfo, &state->buffer, 1); if (ok != 1) break; state->y++; } if (ok != 1) break; state->state++; /* fall through */ case 5: /* Finish compression */ if (context->destination.pub.free_in_buffer < 100) break; jpeg_finish_compress(&context->cinfo); /* Clean up */ if (context->extra) { free(context->extra); context->extra = NULL; } if (context->rawExif) { free(context->rawExif); context->rawExif = NULL; } if (context->qtables) { free(context->qtables); context->qtables = NULL; } jpeg_destroy_compress(&context->cinfo); /* if (jerr.pub.num_warnings) return BROKEN; */ state->errcode = IMAGING_CODEC_END; break; } /* Return number of bytes in output buffer */ return context->destination.pub.next_output_byte - buf; }
/* Callback function for the render out button. */ void AnimatedSGWindow::renderCB(Fl_Widget *w, void *data) { VOID_TO_ASGWIN(data); std::cout << "Rendering out animation to local directory." << std::endl; aSGWin->timeline->value(0); AnimatedSGWindow::timelineCB(aSGWin->timeline, data); Fl::flush(); for (int count = 0; count <= aSGWin->timeline->maximum(); count++) { ////////////////////////////////////////////////////////// // Code for outputing FL_GL_Window to a jpeg file!!! std::string s; std::stringstream out; // a stream for outputing to a string out << count; // make the current count into a string s = out.str(); std::string filename = "anim\\testing_" + s + ".jpg"; // compose the file name // Make the BYTE array, factor of 3 because it's RBG. int width = aSGWin->glWin->w(); int height = aSGWin->glWin->h(); BYTE* pixels = new BYTE[3 * width * height]; glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels); struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; /* this is a pointer to one row of image data */ JSAMPROW row_pointer[1]; FILE *outfile = NULL; fopen_s(&outfile, filename.c_str(), "wb"); if (!outfile) { std::cout << "Error opening output jpeg file:" << filename << std::endl; return; } cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, outfile); /* Setting the parameters of the output file here */ cinfo.image_width = width; cinfo.image_height = height; cinfo.input_components = 3; // bytes_per_pixel; cinfo.in_color_space = JCS_RGB; // color_space; /* default compression parameters, we shouldn't be worried about these */ jpeg_set_defaults(&cinfo); /* Now do the compression .. */ jpeg_start_compress(&cinfo, TRUE); /* like reading a file, this time write one row at a time */ std::list<JDIMENSION> lines; // switch the image to right side up unsigned int cnt = 0; while (cnt < cinfo.image_height) { lines.push_front(cnt); cnt++; } std::list<JDIMENSION>::iterator it; for (it = lines.begin(); it != lines.end(); ++it){ row_pointer[0] = &pixels[(*it) * cinfo.image_width * cinfo.input_components]; jpeg_write_scanlines(&cinfo, row_pointer, 1); } /* similar to read file, clean up after we're done compressing */ jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); fclose(outfile); delete[] pixels; ///////////////////////////////////////////////////////////////////// /* Move the animation forwards */ AnimatedSGWindow::forwardCB(aSGWin->forwardB, data); /* Forces out the redraw */ Fl::flush(); } aSGWin->timeline->value(0); AnimatedSGWindow::timelineCB(aSGWin->timeline, data); std::cout << "Rendering out complete." << std::endl; }
static int jpeg_image_control(ErlDrvData handle, unsigned int command, char* buf, int count, char** res, int res_size) { JSAMPROW row; ErlDrvBinary* bin = 0; switch (command) { case 0: { /* Read */ struct jpeg_decompress_struct cinfo; int row_stride; /* physical row width in output buffer */ unsigned char* rbuf; struct my_error_mgr jerr; 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)) { /* If we get here, the JPEG code has signaled an error. * We need to clean up the JPEG object, close the input file, and return. */ char buffer[JMSG_LENGTH_MAX]; /* Create the message */ (cinfo.err->format_message)((j_common_ptr) &cinfo, buffer); jpeg_destroy_decompress(&cinfo); bin = driver_alloc_binary(4+strlen(buffer)); rbuf = bin->orig_bytes; ((unsigned *)rbuf)[0] = 0; rbuf += 4; memcpy(rbuf, buffer, strlen(buffer)); *res = (void *) bin; return 0; } jpeg_create_decompress(&cinfo); jpeg_buffer_src(&cinfo, buf, count); (void) jpeg_read_header(&cinfo, TRUE); (void) jpeg_start_decompress(&cinfo); row_stride = cinfo.output_width * cinfo.output_components; res_size = row_stride * cinfo.output_height; bin = driver_alloc_binary(res_size+12); rbuf = bin->orig_bytes; ((unsigned *)rbuf)[0] = cinfo.output_width; ((unsigned *)rbuf)[1] = cinfo.output_height; ((unsigned *)rbuf)[2] = cinfo.output_components; rbuf += 12; while (cinfo.output_scanline < cinfo.output_height) { row = (JSAMPROW) rbuf; (void) jpeg_read_scanlines(&cinfo, &row, 1); rbuf += row_stride; } (void) jpeg_finish_decompress(&cinfo); *res = (void *) bin; return 0; } case 1: { /* Write */ struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; int row_stride; /* physical row width */ bin = driver_alloc_binary(count); cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_buffer_dest(&cinfo, bin); cinfo.image_width = ((unsigned *)buf)[0]; cinfo.image_height = ((unsigned *)buf)[1]; cinfo.input_components = ((unsigned *)buf)[2]; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); buf += 12; count -= 12; jpeg_start_compress(&cinfo, TRUE); row_stride = cinfo.input_components * cinfo.image_width; while (cinfo.next_scanline < cinfo.image_height) { row = (JSAMPROW) buf; (void) jpeg_write_scanlines(&cinfo, &row, 1); buf += row_stride; } jpeg_finish_compress(&cinfo); bin = jpeg_buffer_dest_get_bin(&cinfo); jpeg_destroy_compress(&cinfo); *res = (void *) bin; return 0; } default: return -1; /* Error return, throws exception in erlang */ } }
LOGICAL JpgImageFile( Image image, uint8_t **buf, size_t *size, int Q ) { /* This struct contains the JPEG compression parameters and pointers to * working space (which is allocated as needed by the JPEG library). * It is possible to have several such structures, representing multiple * compression/decompression processes, in existence at once. We refer * to any one struct (and its associated working data) as a "JPEG object". */ struct jpeg_compress_struct cinfo; /* This struct represents a JPEG error handler. It is declared separately * because applications often want to supply a specialized error handler * (see the second half of this file for an example). But here we just * take the easy way out and use the standard error handler, which will * print a message on stderr and call exit() if compression fails. * Note that this struct must live as long as the main JPEG parameter * struct, to avoid dangling-pointer problems. */ struct jpeg_error_mgr jerr; unsigned char *outbuf; unsigned long outsize; /* More stuff */ uint8_t* tmpbuf = NewArray( uint8_t, image->width * image->height * 3 ); JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ int row_stride; /* physical row width in image buffer */ { int n; int m = image->pwidth * image->height; uint8_t* in = (uint8_t*)image->image; uint8_t* out = tmpbuf; for( n = 0; n < m; n++ ) { if( bGLColorMode ) { out[0] = (*in++); out[1] = (*in++); out[2] = (*in++); } else { out[2] = (*in++); out[1] = (*in++); out[0] = (*in++); } (*in++); out += 3; } } /* Step 1: allocate and initialize JPEG compression object */ /* We have to set up the error handler first, in case the initialization * step fails. (Unlikely, but it could happen if you are out of memory.) * This routine fills in the contents of struct jerr, and returns jerr's * address which we place into the link field in cinfo. */ cinfo.err = jpeg_std_error(&jerr); /* Now we can initialize the JPEG compression object. */ jpeg_create_compress(&cinfo); /* Step 2: specify data destination (eg, a file) */ /* Note: steps 2 and 3 can be done in either order. */ /* Here we use the library-supplied code to send compressed data to a * stdio stream. You can also write your own code to do something else. * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that * requires it in order to write binary files. */ //jpeg_stdio_dest(&cinfo, outfile); outbuf = NULL; outsize = 0; jpeg_mem_dest( &cinfo, &outbuf, &outsize ); /* Step 3: set parameters for compression */ /* First we supply a description of the input image. * Four fields of the cinfo struct must be filled in: */ cinfo.image_width = image->width; /* image width and height, in pixels */ cinfo.image_height = image->height; cinfo.input_components = 3; /* # of color components per pixel */ cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ /* Now use the library's routine to set default compression parameters. * (You must set at least cinfo.in_color_space before calling this, * since the defaults depend on the source color space.) */ jpeg_set_defaults(&cinfo); /* Now you can set any non-default parameters you wish to. * Here we just illustrate the use of quality (quantization table) scaling: */ jpeg_set_quality(&cinfo, Q, TRUE /* limit to baseline-JPEG values */); /* Step 4: Start compressor */ /* TRUE ensures that we will write a complete interchange-JPEG file. * Pass TRUE unless you are very sure of what you're doing. */ jpeg_start_compress(&cinfo, TRUE); /* Step 5: while (scan lines remain to be written) */ /* jpeg_write_scanlines(...); */ /* Here we use the library's state variable cinfo.next_scanline as the * loop counter, so that we don't have to keep track ourselves. * To keep things simple, we pass one scanline per call; you can pass * more if you wish, though. */ row_stride = image->pwidth * 3; /* JSAMPLEs per row in image_buffer */ while (cinfo.next_scanline < cinfo.image_height) { /* jpeg_write_scanlines expects an array of pointers to scanlines. * Here the array is only one element long, but you could pass * more than one scanline at a time if that's more convenient. */ row_pointer[0] = & tmpbuf[cinfo.next_scanline * row_stride]; (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); } /* Step 6: Finish compression */ jpeg_finish_compress(&cinfo); /* After finish_compress, we can close the output file. */ //fclose(outfile); Deallocate( uint8_t*, tmpbuf ); /* Step 7: release JPEG compression object */ (*buf) = outbuf; (*size) = outsize; /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_compress(&cinfo); return TRUE; /* And we're done! */ }
int write_image(dt_imageio_module_data_t *jpg_tmp, const char *filename, const void *in_tmp, void *exif, int exif_len, int imgid) { dt_imageio_jpeg_t *jpg = (dt_imageio_jpeg_t *)jpg_tmp; const uint8_t *in = (const uint8_t *)in_tmp; struct dt_imageio_jpeg_error_mgr jerr; jpg->cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = dt_imageio_jpeg_error_exit; if(setjmp(jerr.setjmp_buffer)) { jpeg_destroy_compress(&(jpg->cinfo)); return 1; } jpeg_create_compress(&(jpg->cinfo)); FILE *f = fopen(filename, "wb"); if(!f) return 1; jpeg_stdio_dest(&(jpg->cinfo), f); jpg->cinfo.image_width = jpg->width; jpg->cinfo.image_height = jpg->height; jpg->cinfo.input_components = 3; jpg->cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&(jpg->cinfo)); jpeg_set_quality(&(jpg->cinfo), jpg->quality, TRUE); if(jpg->quality > 90) jpg->cinfo.comp_info[0].v_samp_factor = 1; if(jpg->quality > 92) jpg->cinfo.comp_info[0].h_samp_factor = 1; if(jpg->quality > 95) jpg->cinfo.dct_method = JDCT_FLOAT; if(jpg->quality < 50) jpg->cinfo.dct_method = JDCT_IFAST; if(jpg->quality < 80) jpg->cinfo.smoothing_factor = 20; if(jpg->quality < 60) jpg->cinfo.smoothing_factor = 40; if(jpg->quality < 40) jpg->cinfo.smoothing_factor = 60; jpg->cinfo.optimize_coding = 1; // according to specs density_unit = 0, X_density = 1, Y_density = 1 should be fine and valid since it // describes an image with unknown unit and square pixels. // however, some applications (like the Telekom cloud thingy) seem to be confused by that, so let's set // these calues to the same as stored in exiv :/ int resolution = dt_conf_get_int("metadata/resolution"); if(resolution > 0) { jpg->cinfo.density_unit = 1; jpg->cinfo.X_density = resolution; jpg->cinfo.Y_density = resolution; } else { jpg->cinfo.density_unit = 0; jpg->cinfo.X_density = 1; jpg->cinfo.Y_density = 1; } jpeg_start_compress(&(jpg->cinfo), TRUE); if(imgid > 0) { cmsHPROFILE out_profile = dt_colorspaces_create_output_profile(imgid); uint32_t len = 0; cmsSaveProfileToMem(out_profile, 0, &len); if(len > 0) { unsigned char buf[len]; cmsSaveProfileToMem(out_profile, buf, &len); write_icc_profile(&(jpg->cinfo), buf, len); } dt_colorspaces_cleanup_profile(out_profile); } if(exif && exif_len > 0 && exif_len < 65534) jpeg_write_marker(&(jpg->cinfo), JPEG_APP0 + 1, exif, exif_len); uint8_t row[3 * jpg->width]; const uint8_t *buf; while(jpg->cinfo.next_scanline < jpg->cinfo.image_height) { JSAMPROW tmp[1]; buf = in + (size_t)jpg->cinfo.next_scanline * jpg->cinfo.image_width * 4; for(int i = 0; i < jpg->width; i++) for(int k = 0; k < 3; k++) row[3 * i + k] = buf[4 * i + k]; tmp[0] = row; jpeg_write_scanlines(&(jpg->cinfo), tmp, 1); } jpeg_finish_compress(&(jpg->cinfo)); jpeg_destroy_compress(&(jpg->cinfo)); fclose(f); return 0; }
/* ================= SaveJPGToBuffer Encodes JPEG from image in image_buffer and writes to buffer. Expects RGB input data ================= */ size_t RE_SaveJPGToBuffer(byte *buffer, size_t bufSize, int quality, int image_width, int image_height, byte *image_buffer, int padding) { struct jpeg_compress_struct cinfo; q_jpeg_error_mgr_t jerr; JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ my_dest_ptr dest; int row_stride; /* physical row width in image buffer */ size_t outcount; /* Step 1: allocate and initialize JPEG compression object */ cinfo.err = jpeg_std_error(&jerr.pub); cinfo.err->error_exit = R_JPGErrorExit; cinfo.err->output_message = R_JPGOutputMessage; /* Establish the setjmp return context for R_JPGErrorExit to use. */ if (setjmp(jerr.setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error. * We need to clean up the JPEG object and return. */ jpeg_destroy_compress(&cinfo); ri.Printf(PRINT_ALL, "\n"); return 0; } /* Now we can initialize the JPEG compression object. */ jpeg_create_compress(&cinfo); /* Step 2: specify data destination (eg, a file) */ /* Note: steps 2 and 3 can be done in either order. */ jpegDest(&cinfo, buffer, bufSize); /* Step 3: set parameters for compression */ cinfo.image_width = image_width; /* image width and height, in pixels */ cinfo.image_height = image_height; cinfo.input_components = 3; /* # of color components per pixel */ cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); /* If quality is set high, disable chroma subsampling */ if (quality >= 85) { cinfo.comp_info[0].h_samp_factor = 1; cinfo.comp_info[0].v_samp_factor = 1; } /* Step 4: Start compressor */ jpeg_start_compress(&cinfo, TRUE); /* Step 5: while (scan lines remain to be written) */ /* jpeg_write_scanlines(...); */ row_stride = image_width * cinfo.input_components + padding; /* JSAMPLEs per row in image_buffer */ while (cinfo.next_scanline < cinfo.image_height) { /* jpeg_write_scanlines expects an array of pointers to scanlines. * Here the array is only one element long, but you could pass * more than one scanline at a time if that's more convenient. */ row_pointer[0] = &image_buffer[((cinfo.image_height-1)*row_stride)-cinfo.next_scanline * row_stride]; (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); } /* Step 6: Finish compression */ jpeg_finish_compress(&cinfo); dest = (my_dest_ptr) cinfo.dest; outcount = dest->size - dest->pub.free_in_buffer; /* Step 7: release JPEG compression object */ jpeg_destroy_compress(&cinfo); /* And we're done! */ return outcount; }
static gboolean real_save_jpeg (GdkPixbuf *pixbuf, gchar **keys, gchar **values, GError **error, gboolean to_callback, FILE *f, GdkPixbufSaveFunc save_func, gpointer user_data) { /* FIXME error handling is broken */ struct jpeg_compress_struct cinfo; guchar *buf = NULL; guchar *ptr; guchar *pixels = NULL; JSAMPROW *jbuf; int y = 0; volatile int quality = 75; /* default; must be between 0 and 100 */ int i, j; int w, h = 0; int rowstride = 0; int n_channels; struct error_handler_data jerr; ToFunctionDestinationManager to_callback_destmgr; gchar *icc_profile = NULL; gchar *data; gint retval = TRUE; gsize icc_profile_size = 0; to_callback_destmgr.buffer = NULL; if (keys && *keys) { gchar **kiter = keys; gchar **viter = values; while (*kiter) { if (strcmp (*kiter, "quality") == 0) { char *endptr = NULL; quality = strtol (*viter, &endptr, 10); if (endptr == *viter) { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_BAD_OPTION, _("JPEG quality must be a value between 0 and 100; value '%s' could not be parsed."), *viter); retval = FALSE; goto cleanup; } if (quality < 0 || quality > 100) { /* This is a user-visible error; * lets people skip the range-checking * in their app. */ g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_BAD_OPTION, _("JPEG quality must be a value between 0 and 100; value '%d' is not allowed."), quality); retval = FALSE; goto cleanup; } } else if (strcmp (*kiter, "icc-profile") == 0) { /* decode from base64 */ icc_profile = (gchar*) g_base64_decode (*viter, &icc_profile_size); if (icc_profile_size < 127) { /* This is a user-visible error */ g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_BAD_OPTION, _("Color profile has invalid length '%u'."), (guint) icc_profile_size); retval = FALSE; goto cleanup; } } else { g_warning ("Unrecognized parameter (%s) passed to JPEG saver.", *kiter); } ++kiter; ++viter; } } rowstride = gdk_pixbuf_get_rowstride (pixbuf); n_channels = gdk_pixbuf_get_n_channels (pixbuf); w = gdk_pixbuf_get_width (pixbuf); h = gdk_pixbuf_get_height (pixbuf); pixels = gdk_pixbuf_get_pixels (pixbuf); /* Allocate a small buffer to convert image data, * and a larger buffer if doing to_callback save. */ buf = g_try_malloc (w * 3 * sizeof (guchar)); if (!buf) { g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Couldn't allocate memory for loading JPEG file")); retval = FALSE; goto cleanup; } if (to_callback) { to_callback_destmgr.buffer = g_try_malloc (TO_FUNCTION_BUF_SIZE); if (!to_callback_destmgr.buffer) { g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Couldn't allocate memory for loading JPEG file")); retval = FALSE; goto cleanup; } } /* set up error handling */ cinfo.err = jpeg_std_error (&(jerr.pub)); jerr.pub.error_exit = fatal_error_handler; jerr.pub.output_message = output_message_handler; jerr.error = error; if (sigsetjmp (jerr.setjmp_buffer, 1)) { jpeg_destroy_compress (&cinfo); retval = FALSE; goto cleanup; } /* setup compress params */ jpeg_create_compress (&cinfo); if (to_callback) { to_callback_destmgr.pub.init_destination = to_callback_init; to_callback_destmgr.pub.empty_output_buffer = to_callback_empty_output_buffer; to_callback_destmgr.pub.term_destination = to_callback_terminate; to_callback_destmgr.error = error; to_callback_destmgr.save_func = save_func; to_callback_destmgr.user_data = user_data; cinfo.dest = (struct jpeg_destination_mgr*) &to_callback_destmgr; } else { jpeg_stdio_dest (&cinfo, f); } cinfo.image_width = w; cinfo.image_height = h; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; /* set up jepg compression parameters */ jpeg_set_defaults (&cinfo); jpeg_set_quality (&cinfo, quality, TRUE); jpeg_start_compress (&cinfo, TRUE); /* write ICC profile data */ if (icc_profile != NULL) { /* optimise for the common case where only one APP2 segment is required */ if (icc_profile_size < 0xffef) { data = g_new (gchar, icc_profile_size + 14); memcpy (data, "ICC_PROFILE\000\001\001", 14); memcpy (data + 14, icc_profile, icc_profile_size); jpeg_write_marker (&cinfo, JPEG_APP0+2, (const JOCTET *) data, icc_profile_size + 14); g_free (data); } else { guint segments; guint size = 0xffef; guint offset; segments = (guint) ceilf ((gfloat) icc_profile_size / (gfloat) 0xffef); data = g_new (gchar, 0xffff); memcpy (data, "ICC_PROFILE\000", 12); data[13] = segments; for (i=0; i<=segments; i++) { data[12] = i; offset = 0xffef * i; /* last segment */ if (i == segments) size = icc_profile_size % 0xffef; memcpy (data + 14, icc_profile + offset, size); jpeg_write_marker (&cinfo, JPEG_APP0+2, (const JOCTET *) data, size + 14); } g_free (data); } } /* get the start pointer */ ptr = pixels; /* go one scanline at a time... and save */ i = 0; while (cinfo.next_scanline < cinfo.image_height) { /* convert scanline from ARGB to RGB packed */ for (j = 0; j < w; j++) memcpy (&(buf[j*3]), &(ptr[i*rowstride + j*n_channels]), 3); /* write scanline */ jbuf = (JSAMPROW *)(&buf); jpeg_write_scanlines (&cinfo, jbuf, 1); i++; y++; } /* finish off */ jpeg_finish_compress (&cinfo); jpeg_destroy_compress(&cinfo); cleanup: g_free (buf); g_free (to_callback_destmgr.buffer); g_free (icc_profile); return retval; }
void GL_ScreenShot_JPG (byte *buffer) { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPROW s[1]; FILE *f; char picname[80], checkname[MAX_OSPATH]; int i, offset, w3; // create the scrnshots directory if it doesn't exist Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot/", ri.FS_Gamedir()); FS_CreatePath (checkname); for (i = 0; i < 999; i++) { sprintf (picname, "%s/scrnshot/quake%.3d.jpg", ri.FS_Gamedir(), i); f = fopen (picname, "rb"); if (!f) break; fclose (f); } f = fopen (picname, "wb"); if (!f) { ri.Con_Printf (PRINT_ALL, "Couldn't open %s for writing.\n", picname); return; } // Initialise the JPEG compression object cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, f); // Setup JPEG Parameters cinfo.image_width = vid.width; cinfo.image_height = vid.height; cinfo.in_color_space = JCS_RGB; cinfo.input_components = 3; jpeg_set_defaults(&cinfo); // Niceass: 85 is the quality. 0-100 jpeg_set_quality(&cinfo, Q_ftol(gl_jpg_quality->value), TRUE); // Start Compression jpeg_start_compress(&cinfo, true); // Feed scanline data w3 = cinfo.image_width * 3; offset = w3 * cinfo.image_height - w3; while (cinfo.next_scanline < cinfo.image_height) { s[0] = &buffer[offset - cinfo.next_scanline * w3]; jpeg_write_scanlines(&cinfo, s, 1); } // Finish Compression jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); fclose(f); free(buffer); ri.Con_Printf (PRINT_ALL, "Wrote %s\n", picname); }
parse_switches (j_compress_ptr cinfo, int argc, char **argv, int last_file_arg_seen, boolean for_real) /* Parse optional switches. * Returns argv[] index of first file-name argument (== argc if none). * Any file names with indexes <= last_file_arg_seen are ignored; * they have presumably been processed in a previous iteration. * (Pass 0 for last_file_arg_seen on the first or only iteration.) * for_real is FALSE on the first (dummy) pass; we may skip any expensive * processing. */ { int argn; char * arg; boolean force_baseline; boolean simple_progressive; char * qualityarg = NULL; /* saves -quality parm if any */ char * qtablefile = NULL; /* saves -qtables filename if any */ char * qslotsarg = NULL; /* saves -qslots parm if any */ char * samplearg = NULL; /* saves -sample parm if any */ char * scansarg = NULL; /* saves -scans parm if any */ /* Set up default JPEG parameters. */ force_baseline = FALSE; /* by default, allow 16-bit quantizers */ #ifdef C_PROGRESSIVE_SUPPORTED simple_progressive = cinfo->num_scans == 0 ? FALSE : TRUE; #else simple_progressive = FALSE; #endif is_targa = FALSE; outfilename = NULL; memdst = FALSE; cinfo->err->trace_level = 0; /* Scan command line options, adjust parameters */ for (argn = 1; argn < argc; argn++) { arg = argv[argn]; if (*arg != '-') { /* Not a switch, must be a file name argument */ if (argn <= last_file_arg_seen) { outfilename = NULL; /* -outfile applies to just one input file */ continue; /* ignore this name if previously processed */ } break; /* else done parsing switches */ } arg++; /* advance past switch marker character */ if (keymatch(arg, "arithmetic", 1)) { /* Use arithmetic coding. */ #ifdef C_ARITH_CODING_SUPPORTED cinfo->arith_code = TRUE; #else fprintf(stderr, "%s: sorry, arithmetic coding not supported\n", progname); exit(EXIT_FAILURE); #endif } else if (keymatch(arg, "baseline", 1)) { /* Force baseline-compatible output (8-bit quantizer values). */ force_baseline = TRUE; /* Disable multiple scans */ simple_progressive = FALSE; cinfo->num_scans = 0; cinfo->scan_info = NULL; } else if (keymatch(arg, "dct", 2)) { /* Select DCT algorithm. */ if (++argn >= argc) { /* advance to next argument */ fprintf(stderr, "%s: missing argument for dct\n", progname); usage(); } if (keymatch(argv[argn], "int", 1)) { cinfo->dct_method = JDCT_ISLOW; } else if (keymatch(argv[argn], "fast", 2)) { cinfo->dct_method = JDCT_IFAST; } else if (keymatch(argv[argn], "float", 2)) { cinfo->dct_method = JDCT_FLOAT; } else fprintf(stderr, "%s: invalid argument for dct\n", progname); usage(); } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) { /* Enable debug printouts. */ /* On first -d, print version identification */ static boolean printed_version = FALSE; if (! printed_version) { fprintf(stderr, "%s version %s (build %s)\n", PACKAGE_NAME, VERSION, BUILD); fprintf(stderr, "%s\n\n", JCOPYRIGHT); fprintf(stderr, "Emulating The Independent JPEG Group's software, version %s\n\n", JVERSION); printed_version = TRUE; } cinfo->err->trace_level++; } else if (keymatch(arg, "fastcrush", 4)) { cinfo->optimize_scans = FALSE; } else if (keymatch(arg, "flat", 4)) { cinfo->use_flat_quant_tbl = TRUE; jpeg_set_quality(cinfo, 75, TRUE); } else if (keymatch(arg, "grayscale", 2) || keymatch(arg, "greyscale",2)) { /* Force a monochrome JPEG file to be generated. */ jpeg_set_colorspace(cinfo, JCS_GRAYSCALE); } else if (keymatch(arg, "rgb", 3)) { /* Force an RGB JPEG file to be generated. */ jpeg_set_colorspace(cinfo, JCS_RGB); } else if (keymatch(arg, "lambda1", 7)) { if (++argn >= argc) /* advance to next argument */ usage(); cinfo->lambda_log_scale1 = atof(argv[argn]); } else if (keymatch(arg, "lambda2", 7)) { if (++argn >= argc) /* advance to next argument */ usage(); cinfo->lambda_log_scale2 = atof(argv[argn]); } else if (keymatch(arg, "maxmemory", 3)) { /* Maximum memory in Kb (or Mb with 'm'). */ long lval; char ch = 'x'; if (++argn >= argc) /* advance to next argument */ usage(); if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1) usage(); if (ch == 'm' || ch == 'M') lval *= 1000L; cinfo->mem->max_memory_to_use = lval * 1000L; } else if (keymatch(arg, "opt-dc-scan", 6)) { cinfo->one_dc_scan = FALSE; } else if (keymatch(arg, "optimize", 1) || keymatch(arg, "optimise", 1)) { /* Enable entropy parm optimization. */ #ifdef ENTROPY_OPT_SUPPORTED cinfo->optimize_coding = TRUE; #else fprintf(stderr, "%s: sorry, entropy optimization was not compiled in\n", progname); exit(EXIT_FAILURE); #endif } else if (keymatch(arg, "outfile", 4)) { /* Set output file name. */ if (++argn >= argc) { /* advance to next argument */ fprintf(stderr, "%s: missing argument for outfile\n", progname); usage(); } outfilename = argv[argn]; /* save it away for later use */ } else if (keymatch(arg, "progressive", 1)) { /* Select simple progressive mode. */ #ifdef C_PROGRESSIVE_SUPPORTED simple_progressive = TRUE; /* We must postpone execution until num_components is known. */ #else fprintf(stderr, "%s: sorry, progressive output was not compiled in\n", progname); exit(EXIT_FAILURE); #endif } else if (keymatch(arg, "memdst", 2)) { /* Use in-memory destination manager */ #if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED) memdst = TRUE; #else fprintf(stderr, "%s: sorry, in-memory destination manager was not compiled in\n", progname); exit(EXIT_FAILURE); #endif } else if (keymatch(arg, "quality", 1)) { /* Quality ratings (quantization table scaling factors). */ if (++argn >= argc) { /* advance to next argument */ fprintf(stderr, "%s: missing argument for quality\n", progname); usage(); } qualityarg = argv[argn]; } else if (keymatch(arg, "qslots", 2)) { /* Quantization table slot numbers. */ if (++argn >= argc) /* advance to next argument */ usage(); qslotsarg = argv[argn]; /* Must delay setting qslots until after we have processed any * colorspace-determining switches, since jpeg_set_colorspace sets * default quant table numbers. */ } else if (keymatch(arg, "qtables", 2)) { /* Quantization tables fetched from file. */ if (++argn >= argc) /* advance to next argument */ usage(); qtablefile = argv[argn]; /* We postpone actually reading the file in case -quality comes later. */ } else if (keymatch(arg, "restart", 1)) { /* Restart interval in MCU rows (or in MCUs with 'b'). */ long lval; char ch = 'x'; if (++argn >= argc) /* advance to next argument */ usage(); if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1) usage(); if (lval < 0 || lval > 65535L) usage(); if (ch == 'b' || ch == 'B') { cinfo->restart_interval = (unsigned int) lval; cinfo->restart_in_rows = 0; /* else prior '-restart n' overrides me */ } else { cinfo->restart_in_rows = (int) lval; /* restart_interval will be computed during startup */ } } else if (keymatch(arg, "revert", 3)) { /* revert to old JPEG default */ cinfo->use_moz_defaults = FALSE; jpeg_set_defaults(cinfo); } else if (keymatch(arg, "sample", 2)) { /* Set sampling factors. */ if (++argn >= argc) /* advance to next argument */ usage(); samplearg = argv[argn]; /* Must delay setting sample factors until after we have processed any * colorspace-determining switches, since jpeg_set_colorspace sets * default sampling factors. */ } else if (keymatch(arg, "scans", 4)) { /* Set scan script. */ #ifdef C_MULTISCAN_FILES_SUPPORTED if (++argn >= argc) /* advance to next argument */ usage(); scansarg = argv[argn]; /* We must postpone reading the file in case -progressive appears. */ #else fprintf(stderr, "%s: sorry, multi-scan output was not compiled in\n", progname); exit(EXIT_FAILURE); #endif } else if (keymatch(arg, "smooth", 2)) { /* Set input smoothing factor. */ int val; if (++argn >= argc) /* advance to next argument */ usage(); if (sscanf(argv[argn], "%d", &val) != 1) usage(); if (val < 0 || val > 100) usage(); cinfo->smoothing_factor = val; } else if (keymatch(arg, "split-dc-scans", 3)) { cinfo->one_dc_scan = FALSE; cinfo->sep_dc_scan = TRUE; } else if (keymatch(arg, "targa", 1)) { /* Input file is Targa format. */ is_targa = TRUE; } else if (keymatch(arg, "notrellis-dc", 11)) { /* disable trellis quantization */ cinfo->trellis_quant_dc = FALSE; } else if (keymatch(arg, "notrellis", 1)) { /* disable trellis quantization */ cinfo->trellis_quant = FALSE; } else if (keymatch(arg, "trellis-dc", 9)) { /* enable DC trellis quantization */ cinfo->trellis_quant_dc = TRUE; } else if (keymatch(arg, "tune-psnr", 6)) { cinfo->use_flat_quant_tbl = TRUE; cinfo->lambda_log_scale1 = 9.0; cinfo->lambda_log_scale2 = 0.0; cinfo->use_lambda_weight_tbl = FALSE; jpeg_set_quality(cinfo, 75, TRUE); } else if (keymatch(arg, "tune-ssim", 6)) { cinfo->use_flat_quant_tbl = TRUE; cinfo->lambda_log_scale1 = 12.0; cinfo->lambda_log_scale2 = 13.5; cinfo->use_lambda_weight_tbl = FALSE; jpeg_set_quality(cinfo, 75, TRUE); } else if (keymatch(arg, "tune-ms-ssim", 6)) { cinfo->use_flat_quant_tbl = FALSE; cinfo->lambda_log_scale1 = 14.25; cinfo->lambda_log_scale2 = 12.75; cinfo->use_lambda_weight_tbl = TRUE; jpeg_set_quality(cinfo, 75, TRUE); } else if (keymatch(arg, "tune-hvs-psnr", 6)) { cinfo->use_flat_quant_tbl = FALSE; cinfo->lambda_log_scale1 = 16.0; cinfo->lambda_log_scale2 = 15.5; cinfo->use_lambda_weight_tbl = TRUE; jpeg_set_quality(cinfo, 75, TRUE); } else { fprintf(stderr, "%s: unknown option '%s'\n", progname, arg); usage(); /* bogus switch */ } } /* Post-switch-scanning cleanup */ if (for_real) { /* Set quantization tables for selected quality. */ /* Some or all may be overridden if -qtables is present. */ if (qualityarg != NULL) /* process -quality if it was present */ if (! set_quality_ratings(cinfo, qualityarg, force_baseline)) { fprintf(stderr, "%s: can't set quality ratings\n", progname); usage(); } if (qtablefile != NULL) /* process -qtables if it was present */ if (! read_quant_tables(cinfo, qtablefile, force_baseline)) { fprintf(stderr, "%s: can't read qtable file\n", progname); usage(); } if (qslotsarg != NULL) /* process -qslots if it was present */ if (! set_quant_slots(cinfo, qslotsarg)) usage(); if (samplearg != NULL) /* process -sample if it was present */ if (! set_sample_factors(cinfo, samplearg)) { fprintf(stderr, "%s: can't set sample factors\n", progname); usage(); } #ifdef C_PROGRESSIVE_SUPPORTED if (simple_progressive) /* process -progressive; -scans can override */ jpeg_simple_progression(cinfo); #endif #ifdef C_MULTISCAN_FILES_SUPPORTED if (scansarg != NULL) /* process -scans if it was present */ if (! read_scan_script(cinfo, scansarg)) usage(); #endif } return argn; /* return index of next arg (file name) */ }
static uint32_t jpeg_write(const char * name, uint8_t * buffer) { FILE *outfile; struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPROW row_pointer[1]; int row_stride; if ( !buffer ) return 1; if ( (outfile = fopen(name, "wb") ) == NULL ) { mp_msg(MSGT_VO, MSGL_ERR, "\n%s: %s\n", info.short_name, MSGTR_VO_CantCreateFile); mp_msg(MSGT_VO, MSGL_ERR, "%s: %s: %s\n", info.short_name, MSGTR_VO_GenericError, strerror(errno) ); exit_player(EXIT_ERROR); } cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, outfile); cinfo.image_width = image_width; cinfo.image_height = image_height; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); /* Important: Header info must be set AFTER jpeg_set_defaults() */ cinfo.write_JFIF_header = TRUE; cinfo.JFIF_major_version = 1; cinfo.JFIF_minor_version = 2; cinfo.density_unit = 1; /* 0=unknown, 1=dpi, 2=dpcm */ /* Image DPI is determined by Y_density, so we leave that at jpeg_dpi if possible and crunch X_density instead (PAR > 1) */ cinfo.X_density = jpeg_dpi*image_width/image_d_width; cinfo.Y_density = jpeg_dpi*image_height/image_d_height; cinfo.write_Adobe_marker = TRUE; jpeg_set_quality(&cinfo,jpeg_quality, jpeg_baseline); cinfo.optimize_coding = jpeg_optimize; cinfo.smoothing_factor = jpeg_smooth; if ( jpeg_progressive_mode ) { jpeg_simple_progression(&cinfo); } jpeg_start_compress(&cinfo, TRUE); row_stride = image_width * 3; while (cinfo.next_scanline < cinfo.image_height) { row_pointer[0] = &buffer[cinfo.next_scanline * row_stride]; (void)jpeg_write_scanlines(&cinfo, row_pointer,1); } jpeg_finish_compress(&cinfo); fclose(outfile); jpeg_destroy_compress(&cinfo); return 0; }
static bool write_jpeg_image(const QImage &image, QIODevice *device, int sourceQuality) { bool success = false; const QVector<QRgb> cmap = image.colorTable(); struct jpeg_compress_struct cinfo; JSAMPROW row_pointer[1]; row_pointer[0] = 0; struct my_jpeg_destination_mgr *iod_dest = new my_jpeg_destination_mgr(device); struct my_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jerr.error_exit = my_error_exit; if (!setjmp(jerr.setjmp_buffer)) { // WARNING: // this if loop is inside a setjmp/longjmp branch // do not create C++ temporaries here because the destructor may never be called // if you allocate memory, make sure that you can free it (row_pointer[0]) jpeg_create_compress(&cinfo); cinfo.dest = iod_dest; cinfo.image_width = image.width(); cinfo.image_height = image.height(); bool gray=false; switch (image.format()) { case QImage::Format_Mono: case QImage::Format_MonoLSB: case QImage::Format_Indexed8: gray = true; for (int i = image.colorCount(); gray && i--;) { gray = gray & (qRed(cmap[i]) == qGreen(cmap[i]) && qRed(cmap[i]) == qBlue(cmap[i])); } cinfo.input_components = gray ? 1 : 3; cinfo.in_color_space = gray ? JCS_GRAYSCALE : JCS_RGB; break; default: cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; } jpeg_set_defaults(&cinfo); qreal diffInch = qAbs(image.dotsPerMeterX()*2.54/100. - qRound(image.dotsPerMeterX()*2.54/100.)) + qAbs(image.dotsPerMeterY()*2.54/100. - qRound(image.dotsPerMeterY()*2.54/100.)); qreal diffCm = (qAbs(image.dotsPerMeterX()/100. - qRound(image.dotsPerMeterX()/100.)) + qAbs(image.dotsPerMeterY()/100. - qRound(image.dotsPerMeterY()/100.)))*2.54; if (diffInch < diffCm) { cinfo.density_unit = 1; // dots/inch cinfo.X_density = qRound(image.dotsPerMeterX()*2.54/100.); cinfo.Y_density = qRound(image.dotsPerMeterY()*2.54/100.); } else { cinfo.density_unit = 2; // dots/cm cinfo.X_density = (image.dotsPerMeterX()+50) / 100; cinfo.Y_density = (image.dotsPerMeterY()+50) / 100; } int quality = sourceQuality >= 0 ? qMin(sourceQuality,100) : 75; #if defined(Q_OS_UNIXWARE) jpeg_set_quality(&cinfo, quality, B_TRUE /* limit to baseline-JPEG values */); jpeg_start_compress(&cinfo, B_TRUE); #else jpeg_set_quality(&cinfo, quality, true /* limit to baseline-JPEG values */); jpeg_start_compress(&cinfo, true); #endif row_pointer[0] = new uchar[cinfo.image_width*cinfo.input_components]; int w = cinfo.image_width; while (cinfo.next_scanline < cinfo.image_height) { uchar *row = row_pointer[0]; switch (image.format()) { case QImage::Format_Mono: case QImage::Format_MonoLSB: if (gray) { const uchar* data = image.constScanLine(cinfo.next_scanline); if (image.format() == QImage::Format_MonoLSB) { for (int i=0; i<w; i++) { bool bit = !!(*(data + (i >> 3)) & (1 << (i & 7))); row[i] = qRed(cmap[bit]); } } else { for (int i=0; i<w; i++) { bool bit = !!(*(data + (i >> 3)) & (1 << (7 -(i & 7)))); row[i] = qRed(cmap[bit]); } } } else { const uchar* data = image.constScanLine(cinfo.next_scanline); if (image.format() == QImage::Format_MonoLSB) { for (int i=0; i<w; i++) { bool bit = !!(*(data + (i >> 3)) & (1 << (i & 7))); *row++ = qRed(cmap[bit]); *row++ = qGreen(cmap[bit]); *row++ = qBlue(cmap[bit]); } } else { for (int i=0; i<w; i++) { bool bit = !!(*(data + (i >> 3)) & (1 << (7 -(i & 7)))); *row++ = qRed(cmap[bit]); *row++ = qGreen(cmap[bit]); *row++ = qBlue(cmap[bit]); } } }
int main(int argc, char *argv[]) { int quality = 75; if (argc == 2) { quality = atoi(argv[1]); if (quality < 10 || quality > 100) { fprintf(stderr, "invalid quality. must be between 10 and 100\n"); return 1; } } bcm_host_init(); uint32_t screen = 0; DISPMANX_DISPLAY_HANDLE_T display = vc_dispmanx_display_open(screen); DISPMANX_MODEINFO_T info; int ret = vc_dispmanx_display_get_info(display, &info); assert(ret == 0); /* DispmanX expects buffer rows to be aligned to a 32 bit boundary */ int pitch = ALIGN_UP(2 * info.width, 32); uint32_t vc_image_ptr; VC_IMAGE_TYPE_T type = VC_IMAGE_RGB565; DISPMANX_RESOURCE_HANDLE_T resource = vc_dispmanx_resource_create( type, info.width, info.height, &vc_image_ptr ); VC_IMAGE_TRANSFORM_T transform = 0; vc_dispmanx_snapshot(display, resource, transform); VC_RECT_T rect; vc_dispmanx_rect_set(&rect, 0, 0, info.width, info.height); unsigned char *image = malloc(pitch * info.height); assert(image); vc_dispmanx_resource_read_data(resource, &rect, image, info.width * 2); ret = vc_dispmanx_resource_delete(resource); assert(ret == 0); ret = vc_dispmanx_display_close(display); assert(ret == 0); struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPROW row_pointer[1]; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, stdout); cinfo.image_width = info.width; cinfo.image_height = info.height; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, TRUE); jpeg_start_compress(&cinfo, TRUE); int row_stride = cinfo.image_width * 3; while (cinfo.next_scanline < cinfo.image_height) { unsigned char row[row_stride]; unsigned char *dst = &row[0]; uint16_t *src = (uint16_t*)(image + pitch * cinfo.next_scanline); for (int x = 0; x < cinfo.image_width; x++, src++) { *dst++ = ((*src & 0xf800) >> 11) << 3; *dst++ = ((*src & 0x07e0) >> 5) << 2; *dst++ = ((*src & 0x001f) >> 0) << 3; } row_pointer[0] = row; jpeg_write_scanlines(&cinfo, row_pointer, 1); } jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); return 0; }
/*! Tries to restore the image data from the given memblock. Returns the amount of data read. */ UInt64 JPGImageFileType::storeData(const ImagePtr &OSG_JPG_ARG(image ), UChar8 *OSG_JPG_ARG(buffer ), Int32 OSG_JPG_ARG(memSize)) { #ifdef OSG_WITH_JPG if((image->getBpp() != 1 && image->getBpp() != 3) || image->getDepth() != 1) { SWARNING << getMimeType() << " JPEG storeData only works for 2D 1 or 3 bpp images " << std::endl; return 0; } struct local_error_mgr { struct jpeg_error_mgr pub; jmp_buf setjmp_buffer; }; typedef struct local_error_mgr *local_error_ptr; struct local_error_mgr jerr; struct jpeg_compress_struct cinfo; JSAMPARRAY imagebuffer; const UChar8 *data; cinfo.err = jpeg_std_error(&jerr.pub); if(setjmp(jerr.setjmp_buffer)) { jpeg_destroy_compress(&cinfo); return 0; } jpeg_create_compress(&cinfo); jpeg_memory_dest(&cinfo, buffer, memSize); cinfo.image_width = image->getWidth(); cinfo.image_height = image->getHeight(); cinfo.input_components = image->getBpp(); cinfo.in_color_space = (image->getBpp() == 1) ? JCS_GRAYSCALE : JCS_RGB; jpeg_set_defaults(&cinfo); int quality = _quality; const std::string *qualityAttr = image->findAttachmentField(_qualityKey); if (qualityAttr != 0) sscanf(qualityAttr->c_str(), "%i", &quality); jpeg_set_quality(&cinfo, quality, TRUE); jpeg_start_compress(&cinfo, TRUE); imagebuffer = const_cast<UChar8 **>(&data); while(cinfo.next_scanline < cinfo.image_height) { data = image->getData() + (image->getHeight() - 1 - cinfo.next_scanline) * image->getWidth() * image->getBpp(); jpeg_write_scanlines(&cinfo, imagebuffer, 1); } jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); return jpeg_mem.dataSize; #else SWARNING << getMimeType() << " write is not compiled into the current binary " << std::endl; return 0; #endif }
void serializeImage(const ImageData &im, file::buffer &bf, const char *format) { #ifdef OX_HAVE_LIBJPEG char *filename = (char *)"test_jpeg.jpg"; int quality = 50; struct jpeg_compress_struct cinfo; // basic info for JPEG properties struct jpeg_error_mgr jerr; // in case of error FILE * outfile = 0; // target file JSAMPROW row_pointer[1]; // pointer to JSAMPLE row[s] int row_stride; // physical row width in image buffer //## ALLOCATE AND INITIALIZE JPEG COMPRESSION OBJECT cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); //## OPEN FILE FOR DATA DESTINATION: /* if ((outfile = fopen(filename, "wb")) == NULL) { fprintf(stderr, "ERROR: can't open %s\n", filename); exit(1); } */ cinfo.dest = 0; //## SET PARAMETERS FOR COMPRESSION: cinfo.image_width = 20; // |-- image width and height in pixels cinfo.image_height = 20; // | cinfo.input_components = 3; // number of color components per pixel cinfo.in_color_space = JCS_RGB; // colorspace of input image as RGB jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, TRUE); //## CREATE IMAGE BUFFER TO WRITE FROM AND MODIFY THE IMAGE TO LOOK LIKE CHECKERBOARD: unsigned char *image_buffer = NULL; image_buffer = (unsigned char*)malloc( cinfo.image_width*cinfo.image_height*cinfo.num_components ); for(size_t y=0;y<cinfo.image_height; y++) for(size_t x=0;x<cinfo.image_width; x++) { unsigned int pixelIdx = ((y*cinfo.image_height)+x) * cinfo.input_components; if(x%2==y%2) { image_buffer[pixelIdx+0] = 255; // r |-- set r,g,b components to image_buffer[pixelIdx+1] = 0; // g | make this pixel red image_buffer[pixelIdx+2] = 0; // b | (255,0,0) } else { image_buffer[pixelIdx+0] = 255; // r |-- set r,g,b components to image_buffer[pixelIdx+1] = 255; // g | make this pixel white image_buffer[pixelIdx+2] = 255; // b | (255,255,255) } } //## START COMPRESSION: jpeg_start_compress(&cinfo, TRUE); row_stride = cinfo.image_width * 3; // JSAMPLEs per row in image_buffer while (cinfo.next_scanline < cinfo.image_height) { row_pointer[0] = &image_buffer[cinfo.next_scanline * row_stride]; (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); } // NOTE: jpeg_write_scanlines expects an array of pointers to scanlines. // Here the array is only one element long, but you could pass // more than one scanline at a time if that's more convenient. //## FINISH COMPRESSION AND CLOSE FILE: jpeg_finish_compress(&cinfo); fclose(outfile); jpeg_destroy_compress(&cinfo); printf("SUCCESS\n"); #endif }
BOOL RGBToJpegFile(LPSTR fileName,BYTE *dataBuf,UINT widthPix,UINT height,BOOL bRGB,int quality) { if (dataBuf==NULL) return FALSE; if (widthPix==0) return FALSE; if (height==0) return FALSE; LPBYTE tmp; if (!bRGB) { tmp = (BYTE*)new BYTE[widthPix*height]; if (tmp==NULL) { //MessageBox(GetFocus(),"内存不足","错误",MB_OK|MB_ICONWARNING); return FALSE; } UINT row,col; for (row=0;row<height;row++) { for (col=0;col<widthPix;col++) { LPBYTE pRed, pGrn, pBlu; pRed = dataBuf + row * widthPix * 3 + col * 3; pGrn = dataBuf + row * widthPix * 3 + col * 3 + 1; pBlu = dataBuf + row * widthPix * 3 + col * 3 + 2; // luminance int lum = (int)(.299 * (double)(*pRed) + .587 * (double)(*pGrn) + .114 * (double)(*pBlu)); LPBYTE pGray; pGray = tmp + row * widthPix + col; *pGray = (BYTE)lum; } } } struct jpeg_compress_struct cinfo; /* More stuff */ FILE * outfile=NULL; /* target file */ int row_stride; /* physical row widthPix in image buffer */ struct my_error_mgr jerr; /* Step 1: allocate and initialize JPEG compression object */ 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)) { /* If we get here, the JPEG code has signaled an error. * We need to clean up the JPEG object, close the input file, and return. */ jpeg_destroy_compress(&cinfo); if (outfile!=NULL) fclose(outfile); if (!bRGB) { delete [] tmp; } return FALSE; } /* Now we can initialize the JPEG compression object. */ jpeg_create_compress(&cinfo); /* Step 2: specify data destination (eg, a file) */ /* Note: steps 2 and 3 can be done in either order. */ if ((outfile = fopen(fileName, "wb")) == NULL) { //char buf[300]; //wsprintf(buf, "错误:不能打开文件\"%s\"", fileName); //MessageBox(GetFocus(),buf,"错误",MB_OK|MB_ICONWARNING); return FALSE; } jpeg_stdio_dest(&cinfo, outfile); /* Step 3: set parameters for compression */ /* First we supply a description of the input image. * Four fields of the cinfo struct must be filled in: */ cinfo.image_width = widthPix; /* image widthPix and height, in pixels */ cinfo.image_height = height; if (bRGB) { cinfo.input_components = 3; /* # of color components per pixel */ cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ } else { cinfo.input_components = 1; /* # of color components per pixel */ cinfo.in_color_space = JCS_GRAYSCALE; /* colorspace of input image */ } /* Now use the library's routine to set default compression parameters. * (You must set at least cinfo.in_color_space before calling this, * since the defaults depend on the source color space.) */ jpeg_set_defaults(&cinfo); /* Now you can set any non-default parameters you wish to. * Here we just illustrate the use of quality (quantization table) scaling: */ jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); /* Step 4: Start compressor */ /* TRUE ensures that we will write a complete interchange-JPEG file. * Pass TRUE unless you are very sure of what you're doing. */ jpeg_start_compress(&cinfo, TRUE); /* Step 5: while (scan lines remain to be written) */ /* jpeg_write_scanlines(...); */ /* Here we use the library's state variable cinfo.next_scanline as the * loop counter, so that we don't have to keep track ourselves. * To keep things simple, we pass one scanline per call; you can pass * more if you wish, though. */ row_stride = widthPix * 3; /* JSAMPLEs per row in image_buffer */ while (cinfo.next_scanline < cinfo.image_height) { /* jpeg_write_scanlines expects an array of pointers to scanlines. * Here the array is only one element long, but you could pass * more than one scanline at a time if that's more convenient. */ LPBYTE outRow; if (bRGB) { outRow = dataBuf + (cinfo.next_scanline * widthPix * 3); } else { outRow = tmp + (cinfo.next_scanline * widthPix); } (void) jpeg_write_scanlines(&cinfo, &outRow, 1); } /* Step 6: Finish compression */ jpeg_finish_compress(&cinfo); /* After finish_compress, we can close the output file. */ fclose(outfile); /* Step 7: release JPEG compression object */ /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_compress(&cinfo); if (!bRGB) delete [] tmp; /* And we're done! */ return TRUE; }
static void save_jpg_entry_helper(ALLEGRO_FILE *fp, ALLEGRO_BITMAP *bmp, struct save_jpg_entry_helper_data *data) { struct jpeg_compress_struct cinfo; struct my_err_mgr jerr; ALLEGRO_LOCKED_REGION *lock; data->error = false; cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; if (setjmp(jerr.jmpenv)) { /* Longjmp'd. */ data->error = true; goto longjmp_error; } data->buffer = al_malloc(BUFFER_SIZE); if (!data->buffer) { data->error = true; goto error; } jpeg_create_compress(&cinfo); jpeg_packfile_dest(&cinfo, fp, data->buffer); cinfo.image_width = al_get_bitmap_width(bmp); cinfo.image_height = al_get_bitmap_height(bmp); cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); jpeg_start_compress(&cinfo, 1); /* See comment in load_jpg_entry_helper. */ #ifdef ALLEGRO_BIG_ENDIAN lock = al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_RGB_888, ALLEGRO_LOCK_READONLY); #else lock = al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_BGR_888, ALLEGRO_LOCK_READONLY); #endif while (cinfo.next_scanline < cinfo.image_height) { unsigned char *row[1]; row[0] = ((unsigned char *)lock->data) + (signed)cinfo.next_scanline * lock->pitch; jpeg_write_scanlines(&cinfo, (void *)row, 1); } error: jpeg_finish_compress(&cinfo); longjmp_error: jpeg_destroy_compress(&cinfo); if (al_is_bitmap_locked(bmp)) { al_unlock_bitmap(bmp); } al_free(data->buffer); }
/* * zoom out picture. the factor should between 0.5 and 1.0. It can be 0.5, but can not be 1.0. * (双线性插值算法缩小图片,缩放比例(0.5-1.0),貌似缩放后图片会有明显的模糊) */ int zoomOutJpegFile(char *inFileName, char *outFileName, float factor) { if (factor > 1 || factor < 0.5f) { printf("the zoom factor is error, should between 0.5f and 1.0f. (0.5f<=factor<1.0f)"); return -1; } // init decompress struct struct jpeg_decompress_struct in; struct jpeg_error_mgr jInErr; JSAMPROW inRowPointer[1]; FILE *inFile = fopen(inFileName, "rb"); if (!inFile) { printf("Error opening jpeg file %s\n!", inFileName); return -1; } in.err = jpeg_std_error(&jInErr); jpeg_create_decompress(&in); jpeg_stdio_src(&in, inFile); jpeg_read_header(&in, TRUE); jpeg_start_decompress(&in); // init compress struct struct jpeg_compress_struct out; struct jpeg_error_mgr jOutErr; JSAMPROW outRowPointer[1]; FILE *outFile = fopen(outFileName, "wb"); if (!outFile) { printf("Error opening file %s\n", outFileName); return -1; } out.err = jpeg_std_error( &jOutErr); jpeg_create_compress(&out); jpeg_stdio_dest(&out, outFile); int width = in.output_width; int height = in.output_height; int bytesPerPixel = in.num_components; int destWidth = (int) (width * factor); int destHeight = (int) (height * factor); out.image_width = destWidth; out.image_height = destHeight; out.input_components = bytesPerPixel; out.in_color_space = JCS_RGB; jpeg_set_defaults(&out); jpeg_start_compress(&out, TRUE); // Process RGB data. int outRowStride = destWidth * bytesPerPixel; int inRowStride = width * bytesPerPixel; outRowPointer[0] = (unsigned char *) malloc(outRowStride); inRowPointer[0] = (unsigned char *) malloc(inRowStride); JSAMPROW baseInRowPointer[1]; baseInRowPointer[0] = (unsigned char *) malloc(inRowStride); unsigned char bUpLeft, bUpRight, bDownLeft, bDownRight; unsigned char gUpLeft, gUpRight, gDownLeft, gDownRight; unsigned char rUpLeft, rUpRight, rDownLeft, rDownRight; unsigned char b, g, r; float fX, fY; int iX, iY; int i, j; int currentBaseLocation = -1; int count = 0; // Process the first line. jpeg_read_scanlines(&in, inRowPointer, 1); for (j = 0; j < destWidth; j++) { fX = ((float) j) / factor; iX = (int) fX; bUpLeft = inRowPointer[0][iX * 3 + 0]; bUpRight = inRowPointer[0][(iX + 1) * 3 + 0]; gUpLeft = inRowPointer[0][iX * 3 + 1]; gUpRight = inRowPointer[0][(iX + 1) * 3 + 1]; rUpLeft = inRowPointer[0][iX * 3 + 2]; rUpRight = inRowPointer[0][(iX + 1) * 3 + 2]; b = bUpLeft * (iX + 1 - fX) + bUpRight * (fX - iX); g = gUpLeft * (iX + 1 - fX) + gUpRight * (fX - iX); r = rUpLeft * (iX + 1 - fX) + rUpRight * (fX - iX); outRowPointer[0][j * 3 + 0] = b; outRowPointer[0][j * 3 + 1] = g; outRowPointer[0][j * 3 + 2] = r; } jpeg_write_scanlines(&out, outRowPointer, 1); currentBaseLocation = 0; // Process the other lines between the first and last. for (i = 1; i < destHeight - 1; i++) { fY = ((float) i) / factor; iY = (int) fY; if (iY == currentBaseLocation) { in.output_scanline = iY; swapJsampRow(inRowPointer[0], baseInRowPointer[0]); jpeg_read_scanlines(&in, baseInRowPointer, 1); } else { in.output_scanline = iY - 1; jpeg_read_scanlines(&in, inRowPointer, 1); jpeg_read_scanlines(&in, baseInRowPointer, 1); } currentBaseLocation = iY + 1; for (j = 0; j < destWidth; j++) { fX = ((float) j) / factor; iX = (int) fX; bUpLeft = inRowPointer[0][iX * 3 + 0]; bUpRight = inRowPointer[0][(iX + 1) * 3 + 0]; bDownLeft = baseInRowPointer[0][iX * 3 + 0]; bDownRight = baseInRowPointer[0][(iX + 1) * 3 + 0]; gUpLeft = inRowPointer[0][iX * 3 + 1]; gUpRight = inRowPointer[0][(iX + 1) * 3 + 1]; gDownLeft = baseInRowPointer[0][iX * 3 + 1]; gDownRight = baseInRowPointer[0][(iX + 1) * 3 + 1]; rUpLeft = inRowPointer[0][iX * 3 + 2]; rUpRight = inRowPointer[0][(iX + 1) * 3 + 2]; rDownLeft = baseInRowPointer[0][iX * 3 + 2]; rDownRight = baseInRowPointer[0][(iX + 1) * 3 + 2]; b = bUpLeft * (iX + 1 - fX) * (iY + 1 - fY) + bUpRight * (fX - iX) * (iY + 1 - fY) + bDownLeft * (iX + 1 - fX) * (fY - iY) + bDownRight * (fX - iX) * (fY - iY); g = gUpLeft * (iX + 1 - fX) * (iY + 1 - fY) + gUpRight * (fX - iX) * (iY + 1 - fY) + gDownLeft * (iX + 1 - fX) * (fY - iY) + gDownRight * (fX - iX) * (fY - iY); r = rUpLeft * (iX + 1 - fX) * (iY + 1 - fY) + rUpRight * (fX - iX) * (iY + 1 - fY) + rDownLeft * (iX + 1 - fX) * (fY - iY) + rDownRight * (fX - iX) * (fY - iY); outRowPointer[0][j * 3 + 0] = b; outRowPointer[0][j * 3 + 1] = g; outRowPointer[0][j * 3 + 2] = r; } jpeg_write_scanlines(&out, outRowPointer, 1); } //Process the last line. in.output_scanline = height - 1; jpeg_read_scanlines(&in, inRowPointer, 1); for (j = 0; j < destWidth; j++) { fX = ((float) j) / factor; iX = (int) fX; bUpLeft = inRowPointer[0][iX * 3 + 0]; bUpRight = inRowPointer[0][(iX + 1) * 3 + 0]; gUpLeft = inRowPointer[0][iX * 3 + 1]; gUpRight = inRowPointer[0][(iX + 1) * 3 + 1]; rUpLeft = inRowPointer[0][iX * 3 + 2]; rUpRight = inRowPointer[0][(iX + 1) * 3 + 2]; b = bUpLeft * (iX + 1 - fX) + bUpRight * (fX - iX); g = gUpLeft * (iX + 1 - fX) + gUpRight * (fX - iX); r = rUpLeft * (iX + 1 - fX) + rUpRight * (fX - iX); outRowPointer[0][j * 3 + 0] = b; outRowPointer[0][j * 3 + 1] = g; outRowPointer[0][j * 3 + 2] = r; } jpeg_write_scanlines(&out, outRowPointer, 1); //free memory free(inRowPointer[0]); free(baseInRowPointer[0]); free(outRowPointer[0]); // close resource jpeg_finish_decompress(&in); jpeg_destroy_decompress(&in); fclose(inFile); jpeg_finish_compress(&out); jpeg_destroy_compress(&out); fclose(outFile); return 1; }
static gboolean _gdk_pixbuf_save_as_jpeg (GdkPixbuf *pixbuf, const char *filename, char **keys, char **values, GError **error) { struct jpeg_compress_struct cinfo; struct error_handler_data jerr; FILE *file; guchar *buf = NULL; guchar *ptr; guchar *pixels = NULL; volatile int quality = 85; /* default; must be between 0 and 100 */ volatile int smoothing = 0; volatile gboolean optimize = FALSE; volatile gboolean progressive = FALSE; int i, j; int w, h = 0; int rowstride = 0; volatile int bpp; if (keys && *keys) { char **kiter = keys; char **viter = values; while (*kiter) { if (strcmp (*kiter, "quality") == 0) { char *endptr = NULL; quality = strtol (*viter, &endptr, 10); if (endptr == *viter) { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_BAD_OPTION, "JPEG quality must be a value between 0 and 100; value '%s' could not be parsed.", *viter); return FALSE; } if (quality < 0 || quality > 100) { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_BAD_OPTION, "JPEG quality must be a value between 0 and 100; value '%d' is not allowed.", quality); return FALSE; } } else if (strcmp (*kiter, "smooth") == 0) { char *endptr = NULL; smoothing = strtol (*viter, &endptr, 10); if (endptr == *viter) { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_BAD_OPTION, "JPEG smoothing must be a value between 0 and 100; value '%s' could not be parsed.", *viter); return FALSE; } if (smoothing < 0 || smoothing > 100) { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_BAD_OPTION, "JPEG smoothing must be a value between 0 and 100; value '%d' is not allowed.", smoothing); return FALSE; } } else if (strcmp (*kiter, "optimize") == 0) { if (strcmp (*viter, "yes") == 0) optimize = TRUE; else if (strcmp (*viter, "no") == 0) optimize = FALSE; else { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_BAD_OPTION, "JPEG optimize option must be 'yes' or 'no', value is: %s", *viter); return FALSE; } } else if (strcmp (*kiter, "progressive") == 0) { if (strcmp (*viter, "yes") == 0) progressive = TRUE; else if (strcmp (*viter, "no") == 0) progressive = FALSE; else { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_BAD_OPTION, "JPEG progressive option must be 'yes' or 'no', value is: %s", *viter); return FALSE; } } else { g_warning ("Bad option name '%s' passed to JPEG saver", *kiter); return FALSE; } ++kiter; ++viter; } } file = fopen (filename, "wb"); if (file == NULL) { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, "Can't write image to file '%s'", filename); return FALSE; } rowstride = gdk_pixbuf_get_rowstride (pixbuf); w = gdk_pixbuf_get_width (pixbuf); h = gdk_pixbuf_get_height (pixbuf); if (gdk_pixbuf_get_has_alpha (pixbuf)) bpp = 4; else bpp = 3; /* no image data? abort */ pixels = gdk_pixbuf_get_pixels (pixbuf); g_return_val_if_fail (pixels != NULL, FALSE); /* allocate a small buffer to convert image data */ buf = g_try_malloc (w * bpp * sizeof (guchar)); if (! buf) { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, "Couldn't allocate memory for loading JPEG file"); return FALSE; } /* set up error handling */ cinfo.err = jpeg_std_error (&(jerr.pub)); jerr.pub.error_exit = fatal_error_handler; jerr.pub.output_message = output_message_handler; jerr.error = error; if (sigsetjmp (jerr.setjmp_buffer, 1)) { jpeg_destroy_compress (&cinfo); g_free (buf); return FALSE; } /* setup compress params */ jpeg_create_compress (&cinfo); jpeg_stdio_dest (&cinfo, file); cinfo.image_width = w; cinfo.image_height = h; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; /* set up jepg compression parameters */ jpeg_set_defaults (&cinfo); jpeg_set_quality (&cinfo, quality, TRUE); cinfo.smoothing_factor = smoothing; cinfo.optimize_coding = optimize; #ifdef HAVE_PROGRESSIVE_JPEG if (progressive) jpeg_simple_progression (&cinfo); #endif /* HAVE_PROGRESSIVE_JPEG */ jpeg_start_compress (&cinfo, TRUE); /* get the start pointer */ ptr = pixels; /* go one scanline at a time... and save */ i = 0; while (cinfo.next_scanline < cinfo.image_height) { JSAMPROW *jbuf; /* convert scanline from ARGB to RGB packed */ for (j = 0; j < w; j++) memcpy (&(buf[j * 3]), &(ptr[i * rowstride + j * bpp]), 3); /* write scanline */ jbuf = (JSAMPROW *)(&buf); jpeg_write_scanlines (&cinfo, jbuf, 1); i++; } /* finish off */ jpeg_finish_compress (&cinfo); fclose (file); jpeg_destroy_compress(&cinfo); g_free (buf); return TRUE; }
bool JPEG::Encode (ImageBuffer *imageBuffer, ByteArray *bytes, int quality) { struct jpeg_compress_struct cinfo; struct ErrorData jpegError; cinfo.err = jpeg_std_error (&jpegError.base); jpegError.base.error_exit = OnError; jpegError.base.output_message = OnOutput; MyDestManager dest; int w = imageBuffer->width; int h = imageBuffer->height; QuickVec<uint8> row_buf (w * 3); jpeg_create_compress (&cinfo); if (setjmp (jpegError.on_error)) { jpeg_destroy_compress (&cinfo); return false; } cinfo.dest = (jpeg_destination_mgr *)&dest; cinfo.image_width = w; cinfo.image_height = h; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults (&cinfo); jpeg_set_quality (&cinfo, quality, true); jpeg_start_compress (&cinfo, true); JSAMPROW row_pointer = &row_buf[0]; unsigned char* imageData = imageBuffer->data->Bytes(); int stride = w * imageBuffer->bpp; while (cinfo.next_scanline < cinfo.image_height) { const uint8 *src = (const uint8 *)(imageData + (stride * cinfo.next_scanline)); uint8 *dest = &row_buf[0]; for(int x = 0; x < w; x++) { dest[0] = src[0]; dest[1] = src[1]; dest[2] = src[2]; dest += 3; src += 4; } jpeg_write_scanlines (&cinfo, &row_pointer, 1); } jpeg_finish_compress (&cinfo); *bytes = ByteArray (dest.mOutput); return true; }
static BOOL DLL_CALLCONV Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) { if ((dib) && (handle)) { try { // Check dib format const char *sError = "only 24-bit highcolor or 8-bit greyscale/palette bitmaps can be saved as JPEG"; FREE_IMAGE_COLOR_TYPE color_type = FreeImage_GetColorType(dib); WORD bpp = (WORD)FreeImage_GetBPP(dib); if ((bpp != 24) && (bpp != 8)) throw sError; if(bpp == 8) { // allow grey, reverse grey and palette if ((color_type != FIC_MINISBLACK) && (color_type != FIC_MINISWHITE) && (color_type != FIC_PALETTE)) throw sError; } struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; // Step 1: allocate and initialize JPEG compression object cinfo.err = jpeg_std_error(&jerr); jerr.error_exit = jpeg_error_exit; jerr.output_message = jpeg_output_message; // Now we can initialize the JPEG compression object jpeg_create_compress(&cinfo); // Step 2: specify data destination (eg, a file) jpeg_freeimage_dst(&cinfo, handle, io); // Step 3: set parameters for compression cinfo.image_width = FreeImage_GetWidth(dib); cinfo.image_height = FreeImage_GetHeight(dib); switch(color_type) { case FIC_MINISBLACK : case FIC_MINISWHITE : cinfo.in_color_space = JCS_GRAYSCALE; cinfo.input_components = 1; break; default : cinfo.in_color_space = JCS_RGB; cinfo.input_components = 3; break; } jpeg_set_defaults(&cinfo); // progressive-JPEG support if((flags & JPEG_PROGRESSIVE) == JPEG_PROGRESSIVE) { jpeg_simple_progression(&cinfo); } // Set JFIF density parameters from the DIB data cinfo.X_density = (UINT16) (0.5 + 0.0254 * FreeImage_GetDotsPerMeterX(dib)); cinfo.Y_density = (UINT16) (0.5 + 0.0254 * FreeImage_GetDotsPerMeterY(dib)); cinfo.density_unit = 1; // dots / inch // set subsampling options if required if(cinfo.in_color_space == JCS_RGB) { if((flags & JPEG_SUBSAMPLING_411) == JPEG_SUBSAMPLING_411) { // 4:1:1 (4x1 1x1 1x1) - CrH 25% - CbH 25% - CrV 100% - CbV 100% // the horizontal color resolution is quartered cinfo.comp_info[0].h_samp_factor = 4; // Y cinfo.comp_info[0].v_samp_factor = 1; cinfo.comp_info[1].h_samp_factor = 1; // Cb cinfo.comp_info[1].v_samp_factor = 1; cinfo.comp_info[2].h_samp_factor = 1; // Cr cinfo.comp_info[2].v_samp_factor = 1; } else if((flags & JPEG_SUBSAMPLING_420) == JPEG_SUBSAMPLING_420) { // 4:2:0 (2x2 1x1 1x1) - CrH 50% - CbH 50% - CrV 50% - CbV 50% // the chrominance resolution in both the horizontal and vertical directions is cut in half cinfo.comp_info[0].h_samp_factor = 2; // Y cinfo.comp_info[0].v_samp_factor = 2; cinfo.comp_info[1].h_samp_factor = 1; // Cb cinfo.comp_info[1].v_samp_factor = 1; cinfo.comp_info[2].h_samp_factor = 1; // Cr cinfo.comp_info[2].v_samp_factor = 1; } else if((flags & JPEG_SUBSAMPLING_422) == JPEG_SUBSAMPLING_422){ //2x1 (low) // 4:2:2 (2x1 1x1 1x1) - CrH 50% - CbH 50% - CrV 100% - CbV 100% // half of the horizontal resolution in the chrominance is dropped (Cb & Cr), // while the full resolution is retained in the vertical direction, with respect to the luminance cinfo.comp_info[0].h_samp_factor = 2; // Y cinfo.comp_info[0].v_samp_factor = 1; cinfo.comp_info[1].h_samp_factor = 1; // Cb cinfo.comp_info[1].v_samp_factor = 1; cinfo.comp_info[2].h_samp_factor = 1; // Cr cinfo.comp_info[2].v_samp_factor = 1; } else if((flags & JPEG_SUBSAMPLING_444) == JPEG_SUBSAMPLING_444){ //1x1 (no subsampling) // 4:4:4 (1x1 1x1 1x1) - CrH 100% - CbH 100% - CrV 100% - CbV 100% // the resolution of chrominance information (Cb & Cr) is preserved // at the same rate as the luminance (Y) information cinfo.comp_info[0].h_samp_factor = 1; // Y cinfo.comp_info[0].v_samp_factor = 1; cinfo.comp_info[1].h_samp_factor = 1; // Cb cinfo.comp_info[1].v_samp_factor = 1; cinfo.comp_info[2].h_samp_factor = 1; // Cr cinfo.comp_info[2].v_samp_factor = 1; } } // Step 4: set quality // the first 7 bits are reserved for low level quality settings // the other bits are high level (i.e. enum-ish) int quality; if ((flags & JPEG_QUALITYBAD) == JPEG_QUALITYBAD) { quality = 10; } else if ((flags & JPEG_QUALITYAVERAGE) == JPEG_QUALITYAVERAGE) { quality = 25; } else if ((flags & JPEG_QUALITYNORMAL) == JPEG_QUALITYNORMAL) { quality = 50; } else if ((flags & JPEG_QUALITYGOOD) == JPEG_QUALITYGOOD) { quality = 75; } else if ((flags & JPEG_QUALITYSUPERB) == JPEG_QUALITYSUPERB) { quality = 100; } else { if ((flags & 0x7F) == 0) { quality = 75; } else { quality = flags & 0x7F; } } jpeg_set_quality(&cinfo, quality, TRUE); /* limit to baseline-JPEG values */ // Step 5: Start compressor jpeg_start_compress(&cinfo, TRUE); // Step 6: Write special markers write_markers(&cinfo, dib); // Step 7: while (scan lines remain to be written) if(color_type == FIC_RGB) { // 24-bit RGB image : need to swap red and blue channels unsigned pitch = FreeImage_GetPitch(dib); BYTE *target = (BYTE*)malloc(pitch * sizeof(BYTE)); if (target == NULL) { throw FI_MSG_ERROR_MEMORY; } while (cinfo.next_scanline < cinfo.image_height) { // get a copy of the scanline memcpy(target, FreeImage_GetScanLine(dib, FreeImage_GetHeight(dib) - cinfo.next_scanline - 1), pitch); #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR // swap R and B channels BYTE *target_p = target; for(unsigned x = 0; x < cinfo.image_width; x++) { INPLACESWAP(target_p[0], target_p[2]); target_p += 3; } #endif // write the scanline jpeg_write_scanlines(&cinfo, &target, 1); } free(target); } else if(color_type == FIC_MINISBLACK) { // 8-bit standard greyscale images while (cinfo.next_scanline < cinfo.image_height) { JSAMPROW b = FreeImage_GetScanLine(dib, FreeImage_GetHeight(dib) - cinfo.next_scanline - 1); jpeg_write_scanlines(&cinfo, &b, 1); } } else if(color_type == FIC_PALETTE) { // 8-bit palettized images are converted to 24-bit images RGBQUAD *palette = FreeImage_GetPalette(dib); BYTE *target = (BYTE*)malloc(cinfo.image_width * 3); if (target == NULL) { throw FI_MSG_ERROR_MEMORY; } while (cinfo.next_scanline < cinfo.image_height) { BYTE *source = FreeImage_GetScanLine(dib, FreeImage_GetHeight(dib) - cinfo.next_scanline - 1); FreeImage_ConvertLine8To24(target, source, cinfo.image_width, palette); #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR // swap R and B channels BYTE *target_p = target; for(unsigned x = 0; x < cinfo.image_width; x++) { INPLACESWAP(target_p[0], target_p[2]); target_p += 3; } #endif jpeg_write_scanlines(&cinfo, &target, 1); } free(target); } else if(color_type == FIC_MINISWHITE) { // reverse 8-bit greyscale image, so reverse grey value on the fly unsigned i; BYTE reverse[256]; BYTE *target = (BYTE *)malloc(cinfo.image_width); if (target == NULL) { throw FI_MSG_ERROR_MEMORY; } for(i = 0; i < 256; i++) { reverse[i] = (BYTE)(255 - i); } while(cinfo.next_scanline < cinfo.image_height) { BYTE *source = FreeImage_GetScanLine(dib, FreeImage_GetHeight(dib) - cinfo.next_scanline - 1); for(i = 0; i < cinfo.image_width; i++) { target[i] = reverse[ source[i] ]; } jpeg_write_scanlines(&cinfo, &target, 1); } free(target); } // Step 8: Finish compression jpeg_finish_compress(&cinfo); // Step 9: release JPEG compression object jpeg_destroy_compress(&cinfo); return TRUE; } catch (const char *text) { FreeImage_OutputMessageProc(s_format_id, text); return FALSE; } catch (FREE_IMAGE_FORMAT) { return FALSE; } } return FALSE; }
jpeg_copy_critical_parameters (j_decompress_ptr srcinfo, j_compress_ptr dstinfo) { JQUANT_TBL ** qtblptr; jpeg_component_info *incomp, *outcomp; JQUANT_TBL *c_quant, *slot_quant; int tblno, ci, coefi; /* Safety check to ensure start_compress not called yet. */ if (dstinfo->global_state != CSTATE_START) ERREXIT1(dstinfo, JERR_BAD_STATE, dstinfo->global_state); /* Copy fundamental image dimensions */ dstinfo->image_width = srcinfo->image_width; dstinfo->image_height = srcinfo->image_height; dstinfo->input_components = srcinfo->num_components; dstinfo->in_color_space = srcinfo->jpeg_color_space; /* Initialize all parameters to default values */ jpeg_set_defaults(dstinfo); /* jpeg_set_defaults may choose wrong colorspace, eg YCbCr if input is RGB. * Fix it to get the right header markers for the image colorspace. */ jpeg_set_colorspace(dstinfo, srcinfo->jpeg_color_space); dstinfo->data_precision = srcinfo->data_precision; dstinfo->CCIR601_sampling = srcinfo->CCIR601_sampling; /* Copy the source's quantization tables. */ for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) { if (srcinfo->quant_tbl_ptrs[tblno] != NULL) { qtblptr = & dstinfo->quant_tbl_ptrs[tblno]; if (*qtblptr == NULL) *qtblptr = jpeg_alloc_quant_table((j_common_ptr) dstinfo); MEMCOPY((*qtblptr)->quantval, srcinfo->quant_tbl_ptrs[tblno]->quantval, SIZEOF((*qtblptr)->quantval)); (*qtblptr)->sent_table = FALSE; } } /* Copy the source's per-component info. * Note we assume jpeg_set_defaults has allocated the dest comp_info array. */ dstinfo->num_components = srcinfo->num_components; if (dstinfo->num_components < 1 || dstinfo->num_components > MAX_COMPONENTS) ERREXIT2(dstinfo, JERR_COMPONENT_COUNT, dstinfo->num_components, MAX_COMPONENTS); for (ci = 0, incomp = srcinfo->comp_info, outcomp = dstinfo->comp_info; ci < dstinfo->num_components; ci++, incomp++, outcomp++) { outcomp->component_id = incomp->component_id; outcomp->h_samp_factor = incomp->h_samp_factor; outcomp->v_samp_factor = incomp->v_samp_factor; outcomp->quant_tbl_no = incomp->quant_tbl_no; /* Make sure saved quantization table for component matches the qtable * slot. If not, the input file re-used this qtable slot. * IJG encoder currently cannot duplicate this. */ tblno = outcomp->quant_tbl_no; if (tblno < 0 || tblno >= NUM_QUANT_TBLS || srcinfo->quant_tbl_ptrs[tblno] == NULL) ERREXIT1(dstinfo, JERR_NO_QUANT_TABLE, tblno); slot_quant = srcinfo->quant_tbl_ptrs[tblno]; c_quant = incomp->quant_table; if (c_quant != NULL) { for (coefi = 0; coefi < DCTSIZE2; coefi++) { if (c_quant->quantval[coefi] != slot_quant->quantval[coefi]) ERREXIT1(dstinfo, JERR_MISMATCHED_QUANT_TABLE, tblno); } } /* Note: we do not copy the source's Huffman table assignments; * instead we rely on jpeg_set_colorspace to have made a suitable choice. */ } /* Also copy JFIF version and resolution information, if available. * Strictly speaking this isn't "critical" info, but it's nearly * always appropriate to copy it if available. In particular, * if the application chooses to copy JFIF 1.02 extension markers from * the source file, we need to copy the version to make sure we don't * emit a file that has 1.02 extensions but a claimed version of 1.01. * We will *not*, however, copy version info from mislabeled "2.01" files. */ if (srcinfo->saw_JFIF_marker) { if (srcinfo->JFIF_major_version == 1) { dstinfo->JFIF_major_version = srcinfo->JFIF_major_version; dstinfo->JFIF_minor_version = srcinfo->JFIF_minor_version; } dstinfo->density_unit = srcinfo->density_unit; dstinfo->X_density = srcinfo->X_density; dstinfo->Y_density = srcinfo->Y_density; } }
void write_jpeg(FILE *file, unsigned char *image, int width, int height, flam3_img_comments *fpc) { struct jpeg_compress_struct info; struct jpeg_error_mgr jerr; size_t i; char *nick = getenv("nick"); char *url = getenv("url"); char *id = getenv("id"); char *ai; /* For argi */ int jpegcom_enable = argi("enable_jpeg_comments",1); char nick_string[64], url_string[128], id_string[128]; char bv_string[64],ni_string[64],rt_string[64]; char genome_string[65536], ver_string[64]; /* Create the mandatory comment strings */ snprintf(genome_string,65536,"flam3_genome: %s",fpc->genome); snprintf(bv_string,64,"flam3_error_rate: %s",fpc->badvals); snprintf(ni_string,64,"flam3_samples: %s",fpc->numiters); snprintf(rt_string,64,"flam3_time: %s",fpc->rtime); snprintf(ver_string,64,"flam3_version: %s",flam3_version()); info.err = jpeg_std_error(&jerr); jpeg_create_compress(&info); jpeg_stdio_dest(&info, file); info.in_color_space = JCS_RGB; info.input_components = 3; info.image_width = width; info.image_height = height; jpeg_set_defaults(&info); if (getenv("jpeg")) { int quality = atoi(getenv("jpeg")); jpeg_set_quality(&info, quality, TRUE); } jpeg_start_compress(&info, TRUE); /* Write comments to jpeg */ if (jpegcom_enable==1) { jpeg_write_marker(&info, JPEG_COM, (unsigned char *)ver_string, (int)strlen(ver_string)); if (0 != nick) { snprintf(nick_string,64,"flam3_nickname: %s",nick); jpeg_write_marker(&info, JPEG_COM, (unsigned char *)nick_string, (int)strlen(nick_string)); } if (0 != url) { snprintf(url_string,128,"flam3_url: %s",url); jpeg_write_marker(&info, JPEG_COM, (unsigned char *)url_string, (int)strlen(url_string)); } if (0 != id) { snprintf(id_string,128,"flam3_id: %s",id); jpeg_write_marker(&info, JPEG_COM, (unsigned char *)id_string, (int)strlen(id_string)); } jpeg_write_marker(&info, JPEG_COM, (unsigned char *)bv_string, (int)strlen(bv_string)); jpeg_write_marker(&info, JPEG_COM, (unsigned char *)ni_string, (int)strlen(ni_string)); jpeg_write_marker(&info, JPEG_COM, (unsigned char *)rt_string, (int)strlen(rt_string)); jpeg_write_marker(&info, JPEG_COM, (unsigned char *)genome_string, (int)strlen(genome_string)); } for (i = 0; i < height; i++) { JSAMPROW row_pointer[1]; row_pointer[0] = (unsigned char *) image + (3 * width * i); jpeg_write_scanlines(&info, row_pointer, 1); } jpeg_finish_compress(&info); jpeg_destroy_compress(&info); }
int main (int argc, char **argv) { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; #ifdef PROGRESS_REPORT struct cdjpeg_progress_mgr progress; #endif int file_index; cjpeg_source_ptr src_mgr; FILE * input_file; FILE * output_file = NULL; unsigned char *outbuffer = NULL; unsigned long outsize = 0; JDIMENSION num_scanlines; /* On Mac, fetch a command line. */ #ifdef USE_CCOMMAND argc = ccommand(&argv); #endif progname = argv[0]; if (progname == NULL || progname[0] == 0) progname = "cjpeg"; /* in case C library doesn't provide it */ /* Initialize the JPEG compression object with default error handling. */ cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); /* Add some application-specific error messages (from cderror.h) */ jerr.addon_message_table = cdjpeg_message_table; jerr.first_addon_message = JMSG_FIRSTADDONCODE; jerr.last_addon_message = JMSG_LASTADDONCODE; /* Initialize JPEG parameters. * Much of this may be overridden later. * In particular, we don't yet know the input file's color space, * but we need to provide some value for jpeg_set_defaults() to work. */ cinfo.in_color_space = JCS_RGB; /* arbitrary guess */ jpeg_set_defaults(&cinfo); /* Scan command line to find file names. * It is convenient to use just one switch-parsing routine, but the switch * values read here are ignored; we will rescan the switches after opening * the input file. */ file_index = parse_switches(&cinfo, argc, argv, 0, FALSE); #ifdef TWO_FILE_COMMANDLINE if (!memdst) { /* Must have either -outfile switch or explicit output file name */ if (outfilename == NULL) { if (file_index != argc-2) { fprintf(stderr, "%s: must name one input and one output file\n", progname); usage(); } outfilename = argv[file_index+1]; } else { if (file_index != argc-1) { fprintf(stderr, "%s: must name one input and one output file\n", progname); usage(); } } } #else /* Unix style: expect zero or one file name */ if (file_index < argc-1) { fprintf(stderr, "%s: only one input file\n", progname); usage(); } #endif /* TWO_FILE_COMMANDLINE */ /* Open the input file. */ if (file_index < argc) { if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) { fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]); exit(EXIT_FAILURE); } } else { /* default input file is stdin */ input_file = read_stdin(); } /* Open the output file. */ if (outfilename != NULL) { if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) { fprintf(stderr, "%s: can't open %s\n", progname, outfilename); exit(EXIT_FAILURE); } } else if (!memdst) { /* default output file is stdout */ output_file = write_stdout(); } #ifdef PROGRESS_REPORT start_progress_monitor((j_common_ptr) &cinfo, &progress); #endif /* Figure out the input file format, and set up to read it. */ src_mgr = select_file_type(&cinfo, input_file); src_mgr->input_file = input_file; /* Read the input file header to obtain file size & colorspace. */ (*src_mgr->start_input) (&cinfo, src_mgr); /* Now that we know input colorspace, fix colorspace-dependent defaults */ jpeg_default_colorspace(&cinfo); /* Adjust default compression parameters by re-parsing the options */ file_index = parse_switches(&cinfo, argc, argv, 0, TRUE); /* Specify data destination for compression */ #if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED) if (memdst) jpeg_mem_dest(&cinfo, &outbuffer, &outsize); else #endif jpeg_stdio_dest(&cinfo, output_file); /* Start compressor */ jpeg_start_compress(&cinfo, TRUE); /* Process data */ while (cinfo.next_scanline < cinfo.image_height) { num_scanlines = (*src_mgr->get_pixel_rows) (&cinfo, src_mgr); (void) jpeg_write_scanlines(&cinfo, src_mgr->buffer, num_scanlines); } /* Finish compression and release memory */ (*src_mgr->finish_input) (&cinfo, src_mgr); jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); /* Close files, if we opened them */ if (input_file != stdin) fclose(input_file); if (output_file != stdout && output_file != NULL) fclose(output_file); #ifdef PROGRESS_REPORT end_progress_monitor((j_common_ptr) &cinfo); #endif if (memdst) { fprintf(stderr, "Compressed size: %lu bytes\n", outsize); if (outbuffer != NULL) free(outbuffer); } /* All done. */ exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS); return 0; /* suppress no-return-value warnings */ }
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"); 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; } int image_save_to_jpeg_file(image_s * pimage, const char * path) { int nwritten, size = 0; unsigned char * buf; FILE * dst_file; buf = image_save_to_jpeg_buf(pimage, &size); if( !buf ) return -1; dst_file = fopen(path, "w"); if( !dst_file ) { free(buf); return -1; } nwritten = fwrite(buf, 1, size, dst_file); fclose(dst_file); free(buf); return (nwritten==size ? 0 : 1); }