/**************************************************************************
压缩图像到jpeg格式,如果压缩前的图像不是24位图,则强行转换为24位图后压缩
**************************************************************************/
void bmptojpg24(const char *strSourceFileName, const char *strDestFileName)
{
	BITMAPFILEHEADER bfh;		// bmp文件头
	BITMAPINFOHEADER bih;		// bmp头信息
	RGBQUAD rq[256];			// 调色板
	int i=0;

	BYTE *data= NULL;//new BYTE[bih.biWidth*bih.biHeight];
	BYTE *pData24 = NULL;//new BYTE[bih.biWidth*bih.biHeight];
	int nComponent = 0;

	// 打开图像文件
	FILE *f = fopen(strSourceFileName,"rb");
	if (f==NULL)
	{
		printf("Open file error!\n");
		return;
	}
	// 读取文件头
	fread(&bfh,sizeof(bfh),1,f);
	// 读取图像信息
	fread(&bih,sizeof(bih),1,f);
	// 为了简单,在本例中,只演示8位索引图像
	switch (bih.biBitCount) 
	{
	case 8:
		if (bfh.bfOffBits-1024<54) 
		{
			fclose(f);
			return;
		}
		data= new BYTE[bih.biWidth*bih.biHeight];
		pData24 = new BYTE[bih.biWidth*bih.biHeight*3];

		// 定位调色板,并读取调色板
		fseek(f,bfh.bfOffBits-1024,SEEK_SET);	
		fread(rq,sizeof(RGBQUAD),256,f);
		// 读取位图
		fread(data,bih.biWidth*bih.biHeight,1,f);
		fclose(f);
		nComponent = 3;
		for (i=0;i<bih.biWidth * bih.biHeight ;i++)
		{
			pData24[i*3] = rq[data[i]].rgbRed;
			pData24[i*3+1] = rq[data[i]].rgbGreen;
			pData24[i*3+2] = rq[data[i]].rgbBlue;
		}
		break;
	case 24:
		{
		data= new BYTE[bih.biWidth*bih.biHeight*3];
		pData24 = new BYTE[bih.biWidth*bih.biHeight*3];
		fseek(f,bfh.bfOffBits,SEEK_SET);	
		fread(data,bih.biWidth*bih.biHeight*3,1,f);
		fclose(f);
		for (i = 0;i<bih.biWidth*bih.biHeight;i++)
		{
			pData24[i*3] = data[i*3+2];
			pData24[i*3+1] = data[i*3+1];
			pData24[i*3+2] = data[i*3];
		}
		nComponent = 3;
		break;
		}
	default:
		fclose(f);
		return;
	}

	// 以上图像读取完毕

	struct jpeg_compress_struct jcs;
	struct jpeg_error_mgr jem;
	jcs.err = jpeg_std_error(&jem);

	jpeg_create_compress(&jcs);

	f=fopen(strDestFileName,"wb");
	if (f==NULL) 
	{
		delete [] data;
		//delete [] pDataConv;
		return;
	}
	jpeg_stdio_dest(&jcs, f);
	jcs.image_width = bih.biWidth; 			// 为图的宽和高,单位为像素 
	jcs.image_height = bih.biHeight;
	jcs.input_components = nComponent;			// 1,表示灰度图, 如果是彩色位图,则为3 
	if (nComponent==1)
		jcs.in_color_space = JCS_GRAYSCALE; //JCS_GRAYSCALE表示灰度图,JCS_RGB表示彩色图像 
	else 
		jcs.in_color_space = JCS_RGB;

	jpeg_set_defaults(&jcs);	
	jpeg_set_quality (&jcs, 60, true);

	jpeg_start_compress(&jcs, TRUE);

	JSAMPROW row_pointer[1];			// 一行位图
	int row_stride;						// 每一行的字节数 

	row_stride = jcs.image_width*nComponent;		// 如果不是索引图,此处需要乘以3

	// 对每一行进行压缩
	while (jcs.next_scanline < jcs.image_height) {
	    row_pointer[0] = & pData24[(jcs.image_height-jcs.next_scanline-1) * row_stride];
	    jpeg_write_scanlines(&jcs, row_pointer, 1);
	}

	jpeg_finish_compress(&jcs);

	jpeg_destroy_compress(&jcs);

	fclose(f);
	delete [] data;
	delete [] pData24;

}
Ejemplo n.º 2
0
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;
  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;

  /* Now safe to enable signal catcher. */
#ifdef NEED_SIGNAL_CATCHER
  enable_signal_catcher((j_common_ptr) &cinfo);
#endif

  /* 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
  /* 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 {
    /* 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 */
  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)
    fclose(output_file);

#ifdef PROGRESS_REPORT
  end_progress_monitor((j_common_ptr) &cinfo);
#endif

  /* All done. */
  exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS);
  return 0;			/* suppress no-return-value warnings */
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 4
0
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");
		free(dst.buf);
		jpeg_destroy_compress(&cinfo);
		return NULL;
	}
	i = 0;
	while(cinfo.next_scanline < cinfo.image_height)
	{
		for(x = 0; x < pimage->width; x++)
		{
			data[x * 3]     = COL_RED(pimage->buf[i]);
			data[x * 3 + 1] = COL_GREEN(pimage->buf[i]);
			data[x * 3 + 2] = COL_BLUE(pimage->buf[i]);
			i++;
		}
		row_pointer[0] = (unsigned char *)data;
		jpeg_write_scanlines(&cinfo, row_pointer, 1);
	}
	jpeg_finish_compress(&cinfo);
	*size = dst.used;
	free(data);
	jpeg_destroy_compress(&cinfo);

	return dst.buf;
}

char *
image_save_to_jpeg_file(image_s * pimage, char * path)
{
	int nwritten, size = 0;
	unsigned char * buf;
	FILE * dst_file;

	buf = image_save_to_jpeg_buf(pimage, &size);
	if( !buf )
		return NULL;
	dst_file = fopen(path, "w");
	if( !dst_file )
	{
		free(buf);
		return NULL;
	}
	nwritten = fwrite(buf, 1, size, dst_file);
	fclose(dst_file);
	free(buf);

	return (nwritten == size) ? path : NULL;
}
Ejemplo n.º 5
0
/*!
 * \brief   pixWriteStreamJpeg()
 *
 * \param[in]    fp file stream
 * \param[in]    pixs  any depth; cmap is OK
 * \param[in]    quality  1 - 100; 75 is default value; 0 is also default
 * \param[in]    progressive 0 for baseline sequential; 1 for progressive
 * \return  0 if OK, 1 on error
 *
 * <pre>
 * Notes:
 *      (1) Progressive encoding gives better compression, at the
 *          expense of slower encoding and decoding.
 *      (2) Standard chroma subsampling is 2x2 on both the U and V
 *          channels.  For highest quality, use no subsampling; this
 *          option is set by pixSetChromaSampling(pix, 0).
 *      (3) The only valid pixel depths in leptonica are 1, 2, 4, 8, 16
 *          and 32 bpp.  However, it is possible, and in some cases desirable,
 *          to write out a jpeg file using an rgb pix that has 24 bpp.
 *          This can be created by appending the raster data for a 24 bpp
 *          image (with proper scanline padding) directly to a 24 bpp
 *          pix that was created without a data array.
 *      (4) There are two compression paths in this function:
 *          * Grayscale image, no colormap: compress as 8 bpp image.
 *          * rgb full color image: copy each line into the color
 *            line buffer, and compress as three 8 bpp images.
 *      (5) Under the covers, the jpeg library transforms rgb to a
 *          luminance-chromaticity triple, each component of which is
 *          also 8 bits, and compresses that.  It uses 2 Huffman tables,
 *          a higher resolution one (with more quantization levels)
 *          for luminosity and a lower resolution one for the chromas.
 * </pre>
 */
l_int32
pixWriteStreamJpeg(FILE    *fp,
                   PIX     *pixs,
                   l_int32  quality,
                   l_int32  progressive)
{
l_int32                      xres, yres;
l_int32                      i, j, k;
l_int32                      w, h, d, wpl, spp, colorflag, rowsamples;
l_uint32                    *ppixel, *line, *data;
JSAMPROW                     rowbuffer;
PIX                         *pix;
struct jpeg_compress_struct  cinfo;
struct jpeg_error_mgr        jerr;
const char                  *text;
jmp_buf                      jmpbuf;  /* must be local to the function */

    PROCNAME("pixWriteStreamJpeg");

    if (!fp)
        return ERROR_INT("stream not open", procName, 1);
    if (!pixs)
        return ERROR_INT("pixs not defined", procName, 1);
    if (quality <= 0)
        quality = 75;  /* default */

        /* If necessary, convert the pix so that it can be jpeg compressed.
         * The colormap is removed based on the source, so if the colormap
         * has only gray colors, the image will be compressed with spp = 1. */
    pixGetDimensions(pixs, &w, &h, &d);
    pix = NULL;
    if (pixGetColormap(pixs) != NULL) {
        L_INFO("removing colormap; may be better to compress losslessly\n",
               procName);
        pix = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
    } else if (d >= 8 && d != 16) {  /* normal case; no rewrite */
        pix = pixClone(pixs);
    } else if (d < 8 || d == 16) {
        L_INFO("converting from %d to 8 bpp\n", procName, d);
        pix = pixConvertTo8(pixs, 0);  /* 8 bpp, no cmap */
    } else {
        L_ERROR("unknown pix type with d = %d and no cmap\n", procName, d);
        return 1;
    }
    if (!pix)
        return ERROR_INT("pix not made", procName, 1);

    rewind(fp);
    rowbuffer = NULL;

        /* Modify the jpeg error handling to catch fatal errors  */
    cinfo.err = jpeg_std_error(&jerr);
    cinfo.client_data = (void *)&jmpbuf;
    jerr.error_exit = jpeg_error_catch_all_1;
    if (setjmp(jmpbuf)) {
        LEPT_FREE(rowbuffer);
        pixDestroy(&pix);
        return ERROR_INT("internal jpeg error", procName, 1);
    }

        /* Initialize the jpeg structs for compression */
    jpeg_create_compress(&cinfo);
    jpeg_stdio_dest(&cinfo, fp);
    cinfo.image_width  = w;
    cinfo.image_height = h;

        /* Set the color space and number of components */
    d = pixGetDepth(pix);
    if (d == 8) {
        colorflag = 0;    /* 8 bpp grayscale; no cmap */
        cinfo.input_components = 1;
        cinfo.in_color_space = JCS_GRAYSCALE;
    } else {  /* d == 32 || d == 24 */
        colorflag = 1;    /* rgb */
        cinfo.input_components = 3;
        cinfo.in_color_space = JCS_RGB;
    }

    jpeg_set_defaults(&cinfo);

        /* Setting optimize_coding to TRUE seems to improve compression
         * by approx 2-4 percent, and increases comp time by approx 20%. */
    cinfo.optimize_coding = FALSE;

        /* Set resolution in pixels/in (density_unit: 1 = in, 2 = cm) */
    xres = pixGetXRes(pix);
    yres = pixGetYRes(pix);
    if ((xres != 0) && (yres != 0)) {
        cinfo.density_unit = 1;  /* designates pixels per inch */
        cinfo.X_density = xres;
        cinfo.Y_density = yres;
    }

        /* Set the quality and progressive parameters */
    jpeg_set_quality(&cinfo, quality, TRUE);
    if (progressive)
        jpeg_simple_progression(&cinfo);

        /* Set the chroma subsampling parameters.  This is done in
         * YUV color space.  The Y (intensity) channel is never subsampled.
         * The standard subsampling is 2x2 on both the U and V channels.
         * Notation on this is confusing.  For a nice illustrations, see
         *   http://en.wikipedia.org/wiki/Chroma_subsampling
         * The standard subsampling is written as 4:2:0.
         * We allow high quality where there is no subsampling on the
         * chroma channels: denoted as 4:4:4.  */
    if (pixs->special == L_NO_CHROMA_SAMPLING_JPEG) {
        cinfo.comp_info[0].h_samp_factor = 1;
        cinfo.comp_info[0].v_samp_factor = 1;
        cinfo.comp_info[1].h_samp_factor = 1;
        cinfo.comp_info[1].v_samp_factor = 1;
        cinfo.comp_info[2].h_samp_factor = 1;
        cinfo.comp_info[2].v_samp_factor = 1;
    }

    jpeg_start_compress(&cinfo, TRUE);

    if ((text = pixGetText(pix)))
        jpeg_write_marker(&cinfo, JPEG_COM, (const JOCTET *)text, strlen(text));

        /* Allocate row buffer */
    spp = cinfo.input_components;
    rowsamples = spp * w;
    if ((rowbuffer = (JSAMPROW)LEPT_CALLOC(sizeof(JSAMPLE), rowsamples))
        == NULL) {
        pixDestroy(&pix);
        return ERROR_INT("calloc fail for rowbuffer", procName, 1);
    }

    data = pixGetData(pix);
    wpl  = pixGetWpl(pix);
    for (i = 0; i < h; i++) {
        line = data + i * wpl;
        if (colorflag == 0) {        /* 8 bpp gray */
            for (j = 0; j < w; j++)
                rowbuffer[j] = GET_DATA_BYTE(line, j);
        } else {  /* colorflag == 1 */
            if (d == 24) {  /* See note 3 above; special case of 24 bpp rgb */
                jpeg_write_scanlines(&cinfo, (JSAMPROW *)&line, 1);
            } else {  /* standard 32 bpp rgb */
                ppixel = line;
                for (j = k = 0; j < w; j++) {
                    rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_RED);
                    rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_GREEN);
                    rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_BLUE);
                    ppixel++;
                }
            }
        }
        if (d != 24)
            jpeg_write_scanlines(&cinfo, &rowbuffer, 1);
    }
    jpeg_finish_compress(&cinfo);

    pixDestroy(&pix);
    LEPT_FREE(rowbuffer);
    jpeg_destroy_compress(&cinfo);
    return 0;
}
Ejemplo n.º 6
0
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);
}
Ejemplo n.º 7
0
/**
 * write_jpeg_file Writes the raw image data stored in the raw_image buffer
 * to a jpeg image with default compression and smoothing options in the file
 * specified by *filename.
 *
 * \returns positive integer if successful, -1 otherwise
 * \param *filename char string specifying the file name to save to
 *
 */
int WriteJPEGInternal( char *filename,struct Image * pic,char *mem,unsigned long * mem_size)
{
    fprintf(stderr,"WriteJPEG(%s,%p,%p,%p); called \n",filename,pic,mem,mem_size);

    if (pic==0) { fprintf(stderr,"WriteJPEG called with an incorrect image structure \n "); return 0; }

	unsigned char * raw_image = (unsigned char * ) pic->pixels;
	if (raw_image==0) { fprintf(stderr,"WriteJPEG called with a problematic raw image..\n "); return 0; }



	struct jpeg_compress_struct cinfo; memset(&cinfo,0,sizeof(struct jpeg_compress_struct));
	struct jpeg_error_mgr jerr; memset(&jerr,0,sizeof(struct jpeg_error_mgr));
    struct jpeg_destination_mgr dmgr; memset(&dmgr,0,sizeof(struct jpeg_destination_mgr));
    unsigned long initial_mem_size = 0; //*mem_size; can crash with a zero mem_size because it tries for the value of a zero pointer..

    FILE *outfile =0;

	/* this is a pointer to one row of image data */
	JSAMPROW row_pointer[1];

	cinfo.err = jpeg_std_error( &jerr );
	jpeg_create_compress(&cinfo);

	/* Setting the parameters of the output file here */

    if ( (mem!=0) && (mem_size!=0) )
	 {
	   //We want destination to be our buffer..!
       dmgr.init_destination    = init_buffer;
	   dmgr.empty_output_buffer = empty_buffer;
	   dmgr.term_destination    = term_buffer;
	   dmgr.next_output_byte    = (JOCTET*) mem;
	   dmgr.free_in_buffer      = *mem_size;
       initial_mem_size = *mem_size;

	   cinfo.dest = &dmgr;
	 } else
	 {
	    outfile = fopen( filename, "wb" );
        if ( !outfile )
	     {
	    	printf("Error opening output jpeg file %s\n!", filename );
		    return 0;
	     }



	   jpeg_stdio_dest(&cinfo, outfile);
	 }

	cinfo.image_width = pic->width;
	cinfo.image_height = pic->height;
	cinfo.input_components = 3;//pic.depth bytes_per_pixel;
    int JPEGcolor_space = JCS_RGB; /* or JCS_GRAYSCALE for grayscale images */
	cinfo.in_color_space = (J_COLOR_SPACE) JPEGcolor_space;
    /* default compression parameters, we shouldn't be worried about these */
	jpeg_set_defaults( &cinfo );
	jpeg_set_quality (&cinfo, 75,1/*TRUE*/);
	/* Now do the compression .. */
	jpeg_start_compress( &cinfo, 1/*TRUE*/ );
	/* like reading a file, this time write one row at a time */

     while( cinfo.next_scanline < cinfo.image_height )
	   {
		row_pointer[0] = &raw_image[ cinfo.next_scanline * cinfo.image_width *  cinfo.input_components];
		jpeg_write_scanlines( &cinfo, row_pointer, 1 );
       }

    jpeg_finish_compress( &cinfo );
    jpeg_destroy_compress( &cinfo );

	 if ( (mem!=0) && (mem_size!=0) )
	 {
	   //Write back the file size of the compressed image
       *mem_size = initial_mem_size-cinfo.dest->free_in_buffer;
	 } else
	 {
	   /* similar to read file, clean up after we're done compressing */
	   fclose( outfile );
	 }
	/* success code is 1! */
	return 1;
}
Ejemplo n.º 8
0
bool wxJPEGHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose )
{
    struct jpeg_compress_struct cinfo;
    wx_error_mgr jerr;
    JSAMPROW row_pointer[1];    /* pointer to JSAMPLE row[s] */
    JSAMPLE *image_buffer;
    int stride;                /* physical row width in image buffer */

    cinfo.err = jpeg_std_error(&jerr);
    jerr.error_exit = wx_error_exit;

    if (!verbose)
        cinfo.err->output_message = wx_ignore_message;

    /* Establish the setjmp return context for wx_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.
         */
         if (verbose)
         {
            wxLogError(_("JPEG: Couldn't save image."));
         }
         jpeg_destroy_compress(&cinfo);
         return false;
    }

    jpeg_create_compress(&cinfo);
    wx_jpeg_io_dest(&cinfo, stream);

    cinfo.image_width = image->GetWidth();
    cinfo.image_height = image->GetHeight();
    cinfo.input_components = 3;
    cinfo.in_color_space = JCS_RGB;
    jpeg_set_defaults(&cinfo);

    // TODO: 3rd parameter is force_baseline, what value should this be?
    // Code says: "If force_baseline is TRUE, the computed quantization table entries
    // are limited to 1..255 for JPEG baseline compatibility."
    // 'Quality' is a number between 0 (terrible) and 100 (very good).
    // The default (in jcparam.c, jpeg_set_defaults) is 75,
    // and force_baseline is TRUE.
    if (image->HasOption(wxIMAGE_OPTION_QUALITY))
        jpeg_set_quality(&cinfo, image->GetOptionInt(wxIMAGE_OPTION_QUALITY), TRUE);

    // set the resolution fields in the output file
    int resX, resY;
    wxImageResolution res = GetResolutionFromOptions(*image, &resX, &resY);
    if ( res != wxIMAGE_RESOLUTION_NONE )
    {
        cinfo.X_density = resX;
        cinfo.Y_density = resY;

        // it so happens that wxIMAGE_RESOLUTION_INCHES/CM values are the same
        // ones as used by libjpeg, so we can assign them directly
        cinfo.density_unit = res;
    }

    jpeg_start_compress(&cinfo, TRUE);

    stride = cinfo.image_width * 3;    /* JSAMPLEs per row in image_buffer */
    image_buffer = image->GetData();
    while (cinfo.next_scanline < cinfo.image_height) {
        row_pointer[0] = &image_buffer[cinfo.next_scanline * stride];
        jpeg_write_scanlines( &cinfo, row_pointer, 1 );
    }
    jpeg_finish_compress(&cinfo);
    jpeg_destroy_compress(&cinfo);

    return true;
}
Ejemplo n.º 9
0
int
main (int argc, char **argv)
{
	struct jpeg_decompress_struct srcinfo;
	struct jpeg_compress_struct dstinfo;
	struct jpeg_error_mgr jsrcerr, jdsterr;
#ifdef PROGRESS_REPORT
	struct cdjpeg_progress_mgr progress;
#endif
	jvirt_barray_ptr * src_coef_arrays;
	jvirt_barray_ptr * dst_coef_arrays;
	int file_index;
	/* We assume all-in-memory processing and can therefore use only a
	* single file pointer for sequential input and output operation.
	*/
	FILE * fp;

	/* On Mac, fetch a command line. */
#ifdef USE_CCOMMAND
	argc = ccommand(&argv);
#endif

	progname = argv[0];
	if (progname == NULL || progname[0] == 0)
	progname = "jpegtran";  /* in case C library doesn't provide it */

	/* Initialize the JPEG decompression object with default error handling. */
	srcinfo.err = jpeg_std_error(&jsrcerr);
	jpeg_create_decompress(&srcinfo);
	/* Initialize the JPEG compression object with default error handling. */
	dstinfo.err = jpeg_std_error(&jdsterr);
	jpeg_create_compress(&dstinfo);

	/* Now safe to enable signal catcher.
	* Note: we assume only the decompression object will have virtual arrays.
	*/
#ifdef NEED_SIGNAL_CATCHER
	enable_signal_catcher((j_common_ptr) &srcinfo);
#endif

	/* Scan command line to find file names.
	* It is convenient to use just one switch-parsing routine, but the switch
	* values read here are mostly ignored; we will rescan the switches after
	* opening the input file.  Also note that most of the switches affect the
	* destination JPEG object, so we parse into that and then copy over what
	* needs to affects the source too.
	*/

	file_index = parse_switches(&dstinfo, argc, argv, 0, FALSE);
	jsrcerr.trace_level = jdsterr.trace_level;
	srcinfo.mem->max_memory_to_use = dstinfo.mem->max_memory_to_use;

#ifdef TWO_FILE_COMMANDLINE
	/* 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 ((fp = fopen(argv[file_index], READ_BINARY)) == NULL) {
		fprintf(stderr, "%s: can't open %s for reading\n", progname, argv[file_index]);
		exit(EXIT_FAILURE);
	}
	} else {
	/* default input file is stdin */
	fp = read_stdin();
	}

#ifdef PROGRESS_REPORT
	start_progress_monitor((j_common_ptr) &dstinfo, &progress);
#endif

	/* Specify data source for decompression */
	jpeg_stdio_src(&srcinfo, fp);

	/* Enable saving of extra markers that we want to copy */
	jcopy_markers_setup(&srcinfo, copyoption);

	/* Read file header */
	(void) jpeg_read_header(&srcinfo, TRUE);

	/* Adjust default decompression parameters */
	if (scaleoption != NULL)
	if (sscanf(scaleoption, "%d/%d",
	&srcinfo.scale_num, &srcinfo.scale_denom) < 1)
		usage();

	/* Any space needed by a transform option must be requested before
	* jpeg_read_coefficients so that memory allocation will be done right.
	*/
#if TRANSFORMS_SUPPORTED
	/* Fail right away if -perfect is given and transformation is not perfect.
	*/
	if (!jtransform_request_workspace(&srcinfo, &transformoption)) {
	fprintf(stderr, "%s: transformation is not perfect\n", progname);
	exit(EXIT_FAILURE);
	}
#endif

	/* Read source file as DCT coefficients */
	src_coef_arrays = jpeg_read_coefficients(&srcinfo);

	/* Initialize destination compression parameters from source values */
	jpeg_copy_critical_parameters(&srcinfo, &dstinfo);

	/* Adjust destination parameters if required by transform options;
	* also find out which set of coefficient arrays will hold the output.
	*/
#if TRANSFORMS_SUPPORTED
	dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo,
							src_coef_arrays,
							&transformoption);
#else
	dst_coef_arrays = src_coef_arrays;
#endif

	/* Close input file, if we opened it.
	* Note: we assume that jpeg_read_coefficients consumed all input
	* until JPEG_REACHED_EOI, and that jpeg_finish_decompress will
	* only consume more while (! cinfo->inputctl->eoi_reached).
	* We cannot call jpeg_finish_decompress here since we still need the
	* virtual arrays allocated from the source object for processing.
	*/
	if (fp != stdin)
	fclose(fp);

	/* Open the output file. */
	if (outfilename != NULL) {
	if ((fp = fopen(outfilename, WRITE_BINARY)) == NULL) {
		fprintf(stderr, "%s: can't open %s for writing\n", progname, outfilename);
		exit(EXIT_FAILURE);
	}
	} else {
	/* default output file is stdout */
	fp = write_stdout();
	}

	/* Adjust default compression parameters by re-parsing the options */
	file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE);

	/* Specify data destination for compression */
	jpeg_stdio_dest(&dstinfo, fp);

	/* Start compressor (note no image data is actually written here) */
	jpeg_write_coefficients(&dstinfo, dst_coef_arrays);

	/* Copy to the output file any extra markers that we want to preserve */
	jcopy_markers_execute(&srcinfo, &dstinfo, copyoption);

	/* Execute image transformation, if any */
#if TRANSFORMS_SUPPORTED
	jtransform_execute_transformation(&srcinfo, &dstinfo,
					src_coef_arrays,
					&transformoption);
#endif

	/* Finish compression and release memory */
	jpeg_finish_compress(&dstinfo);
	jpeg_destroy_compress(&dstinfo);
	(void) jpeg_finish_decompress(&srcinfo);
	jpeg_destroy_decompress(&srcinfo);

	/* Close output file, if we opened it */
	if (fp != stdout)
	fclose(fp);

#ifdef PROGRESS_REPORT
	end_progress_monitor((j_common_ptr) &dstinfo);
#endif

	/* All done. */
	exit(jsrcerr.num_warnings + jdsterr.num_warnings ?EXIT_WARNING:EXIT_SUCCESS);
	return 0;           /* suppress no-return-value warnings */
}
static int
ngx_http_video_thumbextractor_get_thumb(ngx_http_video_thumbextractor_loc_conf_t *cf, ngx_http_video_thumbextractor_file_info_t *info, int64_t second, ngx_uint_t width, ngx_uint_t height, caddr_t *out_buffer, size_t *out_len, ngx_pool_t *temp_pool, ngx_log_t *log)
{
    int              rc, videoStream, frameFinished = 0, frameDecoded = 0;
    unsigned int     i;
    AVFormatContext *pFormatCtx = NULL;
    AVCodecContext  *pCodecCtx = NULL;
    AVCodec         *pCodec = NULL;
    AVFrame         *pFrame = NULL, *pFrameRGB = NULL;
    uint8_t         *buffer = NULL;
    AVPacket         packet;
    size_t           uncompressed_size;
    float            scale = 0.0, new_scale = 0.0, scale_sws = 0.0, scale_w = 0.0, scale_h = 0.0;
    int              sws_width = 0, sws_height = 0;
    ngx_flag_t       needs_crop = 0;
    MagickWand      *m_wand = NULL;
    MagickBooleanType mrc;
    unsigned char   *bufferAVIO = NULL;
    AVIOContext     *pAVIOCtx = NULL;
    char            *filename = (char *) info->filename->data;

    // Open video file
    if ((info->fd = fopen(filename, "rb")) == NULL) {
        ngx_log_error(NGX_LOG_ERR, log, 0, "video thumb extractor module: Couldn't open file %s", filename);
        rc = EXIT_FAILURE;
        goto exit;
    }

    // Get file size
    fseek(info->fd, 0, SEEK_END);
    info->size = ftell(info->fd) - info->offset;
    fseek(info->fd, 0, SEEK_SET);

    pFormatCtx = avformat_alloc_context();
    bufferAVIO = (unsigned char *) av_malloc(NGX_HTTP_VIDEO_THUMBEXTRACTOR_BUFFER_SIZE * sizeof(unsigned char));
    if ((pFormatCtx == NULL) || (bufferAVIO == NULL)) {
        ngx_log_error(NGX_LOG_ERR, log, 0, "video thumb extractor module: Couldn't alloc AVIO buffer");
        rc = NGX_ERROR;
        goto exit;
    }

    pAVIOCtx = avio_alloc_context(bufferAVIO, NGX_HTTP_VIDEO_THUMBEXTRACTOR_BUFFER_SIZE, 0, info, ngx_http_video_thumbextractor_read_data_from_file, NULL, ngx_http_video_thumbextractor_seek_data_from_file);
    if (pAVIOCtx == NULL) {
        ngx_log_error(NGX_LOG_ERR, log, 0, "video thumb extractor module: Couldn't alloc AVIO context");
        rc = NGX_ERROR;
        goto exit;
    }

    pFormatCtx->pb = pAVIOCtx;

    // Open video file
    if ((rc = avformat_open_input(&pFormatCtx, filename, NULL, NULL)) != 0) {
        ngx_log_error(NGX_LOG_ERR, log, 0, "video thumb extractor module: Couldn't open file %s, error: %d", filename, rc);
        rc = (rc == AVERROR(NGX_ENOENT)) ? NGX_HTTP_VIDEO_THUMBEXTRACTOR_FILE_NOT_FOUND : NGX_ERROR;
        goto exit;
    }

    // Retrieve stream information
#if LIBAVFORMAT_VERSION_INT <= AV_VERSION_INT(53, 5, 0)
    if (av_find_stream_info(pFormatCtx) < 0) {
#else
    if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
#endif
        ngx_log_error(NGX_LOG_ERR, log, 0, "video thumb extractor module: Couldn't find stream information");
        rc = NGX_ERROR;
        goto exit;
    }

    if ((pFormatCtx->duration > 0) && ((((float_t) pFormatCtx->duration / AV_TIME_BASE) - second)) < 0.1) {
        ngx_log_error(NGX_LOG_WARN, log, 0, "video thumb extractor module: seconds greater than duration");
        rc = NGX_HTTP_VIDEO_THUMBEXTRACTOR_SECOND_NOT_FOUND;
        goto exit;
    }

    // Find the first video stream
    videoStream = -1;
    for (i = 0; i < pFormatCtx->nb_streams; i++) {
        if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
            videoStream = i;
            break;
        }
    }

    if (videoStream == -1) {
        ngx_log_error(NGX_LOG_ERR, log, 0, "video thumb extractor module: Didn't find a video stream");
        rc = NGX_ERROR;
        goto exit;
    }

    // Get a pointer to the codec context for the video stream
    pCodecCtx = pFormatCtx->streams[videoStream]->codec;

    // Find the decoder for the video stream
    if ((pCodec = avcodec_find_decoder(pCodecCtx->codec_id)) == NULL) {
        ngx_log_error(NGX_LOG_ERR, log, 0, "video thumb extractor module: Codec %d not found", pCodecCtx->codec_id);
        rc = NGX_ERROR;
        goto exit;
    }

    // Open codec
#if LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(53, 8, 0)
    if ((rc = avcodec_open(pCodecCtx, pCodec)) < 0) {
#else
    if ((rc = avcodec_open2(pCodecCtx, pCodec, NULL)) < 0) {
#endif
        ngx_log_error(NGX_LOG_ERR, log, 0, "video thumb extractor module: Could not open codec, error %d", rc);
        rc = NGX_ERROR;
        goto exit;
    }

    if (height == 0) {
        // keep original format
        width = pCodecCtx->width;
        height = pCodecCtx->height;
    } else if (width == 0) {
        // calculate width related with original aspect
        width = height * pCodecCtx->width / pCodecCtx->height;
    }

    if ((width < 16) || (height < 16)) {
        ngx_log_error(NGX_LOG_ERR, log, 0, "video thumb extractor module: Very small size requested, %d x %d", width, height);
        rc = NGX_ERROR;
        goto exit;
    }

    scale     = (float) pCodecCtx->width / pCodecCtx->height;
    new_scale = (float) width / height;

    sws_width = width;
    sws_height = height;

    if (scale != new_scale) {
        scale_w = (float) width / pCodecCtx->width;
        scale_h = (float) height / pCodecCtx->height;
        scale_sws = (scale_w > scale_h) ? scale_w : scale_h;

        sws_width = pCodecCtx->width * scale_sws + 0.5;
        sws_height = pCodecCtx->height * scale_sws + 0.5;

        needs_crop = 1;
    }


    // Allocate video frame
    pFrame = avcodec_alloc_frame();

    // Allocate an AVFrame structure
    pFrameRGB = avcodec_alloc_frame();
    if ((pFrame == NULL) || (pFrameRGB == NULL)) {
        ngx_log_error(NGX_LOG_ERR, log, 0, "video thumb extractor module: Could not alloc frame memory");
        rc = NGX_ERROR;
        goto exit;
    }

    // Determine required buffer size and allocate buffer
    uncompressed_size = avpicture_get_size(PIX_FMT_RGB24, sws_width, sws_height) * sizeof(uint8_t);
    buffer = (uint8_t *) av_malloc(uncompressed_size);

    // Assign appropriate parts of buffer to image planes in pFrameRGB
    // Note that pFrameRGB is an AVFrame, but AVFrame is a superset of AVPicture
    avpicture_fill((AVPicture *) pFrameRGB, buffer, PIX_FMT_RGB24, sws_width, sws_height);

    if ((rc = av_seek_frame(pFormatCtx, -1, second * AV_TIME_BASE, cf->next_time ? 0 : AVSEEK_FLAG_BACKWARD)) < 0) {
        ngx_log_error(NGX_LOG_ERR, log, 0, "video thumb extractor module: Seek to an invalid time, error: %d", rc);
        rc = NGX_HTTP_VIDEO_THUMBEXTRACTOR_SECOND_NOT_FOUND;
        goto exit;
    }

    int64_t second_on_stream_time_base = second * pFormatCtx->streams[videoStream]->time_base.den / pFormatCtx->streams[videoStream]->time_base.num;

    // Find the nearest frame
    rc = NGX_HTTP_VIDEO_THUMBEXTRACTOR_SECOND_NOT_FOUND;
    while (!frameFinished && av_read_frame(pFormatCtx, &packet) >= 0) {
        // Is this a packet from the video stream?
        if (packet.stream_index == videoStream) {
            // Decode video frame
            avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
            // Did we get a video frame?
            if (frameFinished) {
                frameDecoded = 1;
                if (!cf->only_keyframe && (pFrame->pkt_pts < second_on_stream_time_base)) {
                    frameFinished = 0;
                }
            }
        }

        // Free the packet that was allocated by av_read_frame
        av_free_packet(&packet);
    }
    av_free_packet(&packet);

    if (frameDecoded) {
        // Convert the image from its native format to RGB
        struct SwsContext *img_resample_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
                sws_width, sws_height, PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);

        sws_scale(img_resample_ctx, (const uint8_t * const *) pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
        sws_freeContext(img_resample_ctx);

        if (needs_crop) {
            MagickWandGenesis();
            mrc = MagickTrue;

            if ((m_wand = NewMagickWand()) == NULL){
                ngx_log_error(NGX_LOG_ERR, log, 0, "video thumb extractor module: Could not allocate MagickWand memory");
                mrc = MagickFalse;
            }

            if (mrc == MagickTrue) {
                mrc = MagickConstituteImage(m_wand, sws_width, sws_height, NGX_HTTP_VIDEO_THUMBEXTRACTOR_RGB, CharPixel, pFrameRGB->data[0]);
            }

            if (mrc == MagickTrue) {
                mrc = MagickSetImageGravity(m_wand, CenterGravity);
            }

            if (mrc == MagickTrue) {
                mrc = MagickCropImage(m_wand, width, height, (sws_width-width)/2, (sws_height-height)/2);
            }

            if (mrc == MagickTrue) {
                mrc = MagickExportImagePixels(m_wand, 0, 0, width, height, NGX_HTTP_VIDEO_THUMBEXTRACTOR_RGB, CharPixel, pFrameRGB->data[0]);
            }

            /* Clean up */
            if (m_wand) {
                m_wand = DestroyMagickWand(m_wand);
            }

            MagickWandTerminus();

            if (mrc != MagickTrue) {
                ngx_log_error(NGX_LOG_ERR, log, 0, "video thumb extractor module: Error cropping image");
                goto exit;
            }
        }

        // Compress to jpeg
        if (ngx_http_video_thumbextractor_jpeg_compress(cf, pFrameRGB->data[0], pCodecCtx->width, pCodecCtx->height, width, height, out_buffer, out_len, uncompressed_size, temp_pool) == 0) {
            rc = NGX_OK;
        }
    }

exit:

    if ((info->fd != NULL) && (fclose(info->fd) != 0)) {
        ngx_log_error(NGX_LOG_ERR, log, 0, "video thumb extractor module: Couldn't close file %s", filename);
        rc = EXIT_FAILURE;
    }

    /* destroy unneeded objects */

    // Free the RGB image
    if (buffer != NULL) av_free(buffer);
    if (pFrameRGB != NULL) av_freep(&pFrameRGB);

    // Free the YUV frame
    if (pFrame != NULL) av_freep(&pFrame);

    // Close the codec
    if (pCodecCtx != NULL) avcodec_close(pCodecCtx);

    // Close the video file
    if (pFormatCtx != NULL) {
#if LIBAVFORMAT_VERSION_INT <= AV_VERSION_INT(53, 5, 0)
        av_close_input_file(pFormatCtx);
#else
        avformat_close_input(&pFormatCtx);
#endif
    }

    // Free AVIO context
    if (pAVIOCtx != NULL) av_freep(pAVIOCtx);

    return rc;
}


static void
ngx_http_video_thumbextractor_init_libraries(void)
{
    // Register all formats and codecs
    av_register_all();
    av_log_set_level(AV_LOG_ERROR);
}


static uint32_t
ngx_http_video_thumbextractor_jpeg_compress(ngx_http_video_thumbextractor_loc_conf_t *cf, uint8_t * buffer, int in_width, int in_height, int out_width, int out_height, caddr_t *out_buffer, size_t *out_len, size_t uncompressed_size, ngx_pool_t *temp_pool)
{
    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr jerr;
    JSAMPROW row_pointer[1];
    int row_stride;
    int image_d_width = in_width;
    int image_d_height = in_height;

    if ( !buffer ) return 1;

    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_compress(&cinfo);
    ngx_http_video_thumbextractor_jpeg_memory_dest(&cinfo, out_buffer, out_len, uncompressed_size, temp_pool);

    cinfo.image_width = out_width;
    cinfo.image_height = out_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) */

    if (out_height * image_d_width > out_width * image_d_height) {
        image_d_width = out_height * image_d_width / image_d_height;
        image_d_height = out_height;
    } else {
        image_d_height = out_width * image_d_height / image_d_width;
        image_d_width = out_width;
    }

    cinfo.X_density = cf->jpeg_dpi * out_width / image_d_width;
    cinfo.Y_density = cf->jpeg_dpi * out_height / image_d_height;
    cinfo.write_Adobe_marker = TRUE;

    jpeg_set_quality(&cinfo, cf->jpeg_quality, cf->jpeg_baseline);
    cinfo.optimize_coding = cf->jpeg_optimize;
    cinfo.smoothing_factor = cf->jpeg_smooth;

    if ( cf->jpeg_progressive_mode ) {
        jpeg_simple_progression(&cinfo);
    }

    jpeg_start_compress(&cinfo, TRUE);

    row_stride = out_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);
    jpeg_destroy_compress(&cinfo);

    return 0;
}


typedef struct {
    struct jpeg_destination_mgr  pub; /* public fields */

    unsigned char              **buf;
    size_t                      *size;
    size_t                       uncompressed_size;
    ngx_pool_t                  *pool;
} ngx_http_video_thumbextractor_jpeg_destination_mgr;


static void ngx_http_video_thumbextractor_init_destination (j_compress_ptr cinfo)
{
    ngx_http_video_thumbextractor_jpeg_destination_mgr * dest = (ngx_http_video_thumbextractor_jpeg_destination_mgr *) cinfo->dest;

    *(dest->buf) = ngx_palloc(dest->pool, dest->uncompressed_size);
    *(dest->size) = dest->uncompressed_size;
    dest->pub.next_output_byte = *(dest->buf);
    dest->pub.free_in_buffer = dest->uncompressed_size;
}
Ejemplo n.º 11
0
int R_SaveAsJpeg(void  *d, int width, int height,
                 unsigned int (*gp)(void *, int, int),
                 int bgr, int quality, FILE *outfile, int res)
{
    struct jpeg_compress_struct cinfo;
    struct my_error_mgr jerr;
    /* More stuff */
    JSAMPLE *pscanline, *scanline = (JSAMPLE *) calloc(3*width,sizeof(JSAMPLE));
    int i, j;
    unsigned int col;
    DECLARESHIFTS;

    /* Have we enough memory?*/
    if (scanline == NULL)
        return 0;

    if (outfile == NULL) {
        free(scanline);
        return 0;
    }

    /* Step 1: allocate and initialize JPEG compression object */

    /*
     * We set up the normal JPEG error routines, then override error_exit
     * and output_message
     */
    cinfo.err = jpeg_std_error(&jerr.pub);
    jerr.pub.error_exit = my_error_exit ;
    jerr.pub.output_message = my_output_message ;
    /* 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);
        free(scanline);
        if (outfile) fclose(outfile);
        return 0;
    }
    /* Now we can initialize the JPEG compression object. */
    jpeg_create_compress(&cinfo);

    /* Step 2: specify data destination (eg, a file) */
    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 = width;	/* image width and height, in pixels */
    cinfo.image_height = height;
    cinfo.input_components = 3;		/* # of color components per pixel */
    cinfo.in_color_space = JCS_RGB;	/* colorspace of input image */
    jpeg_set_defaults(&cinfo);
    if(res > 0) {
        cinfo.density_unit = 1;  /* pixels per inch */
        cinfo.X_density = res;
        cinfo.Y_density = res;
    }
    jpeg_set_quality(&cinfo, quality, TRUE);
    /* Step 4: Start compressor */
    jpeg_start_compress(&cinfo, TRUE);

    /* Step 5: while (scan lines remain to be written) */
    /*           jpeg_write_scanlines(...); */
    for (i=0 ; i<height ; i++) {
        /* Build the scanline */
        pscanline = scanline;
        for ( j=0 ; j<width ; j++) {
            col = gp(d, i, j) & 0xFFFFFF;
            *pscanline++ = GETRED(col) ;
            *pscanline++ = GETGREEN(col) ;
            *pscanline++ = GETBLUE(col) ;
        }
        jpeg_write_scanlines(&cinfo, (JSAMPARRAY) &scanline, 1);
    }

    /* Step 6: Finish compression */

    jpeg_finish_compress(&cinfo);

    /* Step 7: release JPEG compression object */

    /* This is an important step since it will release a good deal of memory. */
    free(scanline);
    jpeg_destroy_compress(&cinfo);


    /* And we're done! */
    return 1;
}
Ejemplo n.º 12
0
int pixmap_write_jpg(const struct pixmap* img, const char* filename) {
	int err = 0;

	FILE* file = fopen(filename, "wb");
	if (file == NULL) {
		fprintf(stderr, "pixmap error: cannot open JPG file '%s'\n", filename);
		return 1;
	}

	j_compress_ptr jpg = calloc(1, sizeof(struct jpeg_compress_struct));
	if (jpg == NULL) {
		fprintf(stderr, "pixmap error: cannot create JPG compress struct");
		err = 1;
		goto fclose_jpg;
	}
	struct jpeg_error_mgr jerr;
	jpg->err = jpeg_std_error(&jerr);
	jpeg_create_compress(jpg);
	jpeg_stdio_dest(jpg, file);

	jpg->image_width = img->width;
	jpg->image_height = img->height;
	jpg->input_components = 3; // RGB
	jpg->in_color_space = JCS_RGB;
	jpeg_set_defaults(jpg);

	if (0 < img->quality || img->quality < 100) {
		jpeg_set_quality(jpg, img->quality, TRUE);
	} else {
		fprintf(stderr, "pixmap error: invalid quality value (%d), setting to default\n", img->quality);
		jpeg_set_quality(jpg, PIXMAP_GOOD_QUALITY, TRUE);
	}

	if (img->chroma == PIXMAP_CHROMA_411) {
		jpg->comp_info[0].h_samp_factor = 2;
		jpg->comp_info[0].v_samp_factor = 2;
	} else if (img->chroma == PIXMAP_CHROMA_422) {
		jpg->comp_info[0].h_samp_factor = 2;
		jpg->comp_info[0].v_samp_factor = 1;
	} else {
		if (img->chroma != PIXMAP_CHROMA_444) {
			fprintf(stderr, "pixmap error: invalid chroma value (%d), setting to default\n", img->chroma);
		}
		jpg->comp_info[0].h_samp_factor = 1;
		jpg->comp_info[0].v_samp_factor = 1;
	}
	jpg->comp_info[1].h_samp_factor = 1;
	jpg->comp_info[1].v_samp_factor = 1;
	jpg->comp_info[2].h_samp_factor = 1;
	jpg->comp_info[2].v_samp_factor = 1;

	jpeg_start_compress(jpg, TRUE);
	JSAMPROW* rows = calloc(img->height, sizeof(JSAMPROW));
	if (rows == NULL) {
		fprintf(stderr, "pixmap error: cannot allocate memory\n");
		err = 1;
		goto free_jpg;
	}
	for (int h = 0; h < img->height; h++) {
		rows[h] = img->bytes + PIXMAP_COLORS*h*img->width;
	}
	if (jpeg_write_scanlines(jpg, rows, img->height) != (unsigned int)img->height) {
		fprintf(stderr, "pixmap error: cannot write scanlines\n");
		err = 1;
	}

free_jpg:
	jpeg_finish_compress(jpg);
	jpeg_destroy_compress(jpg);
	free(rows);
	free(jpg);
fclose_jpg:
	if (fclose(file) != 0) {
		fprintf(stderr, "pixmap error: cannot close JPG file '%s'\n", filename);
		err = 1;
	}
	return err;
}
Ejemplo n.º 13
0
int
main (int argc, char **argv)
{
  struct jpeg_decompress_struct srcinfo;
  struct jpeg_compress_struct dstinfo;
  struct jpeg_error_mgr jsrcerr, jdsterr;
#ifdef PROGRESS_REPORT
  struct cdjpeg_progress_mgr progress;
#endif
  jvirt_barray_ptr * src_coef_arrays;
  jvirt_barray_ptr * dst_coef_arrays;
  int file_index;
  FILE * input_file;
  FILE * output_file;

  
#ifdef USE_CCOMMAND
  argc = ccommand(&argv);
#endif

  progname = argv[0];
  if (progname == NULL || progname[0] == 0)
    progname = "jpegtran";	

  
  srcinfo.err = jpeg_std_error(&jsrcerr);
  jpeg_create_decompress(&srcinfo);
  
  dstinfo.err = jpeg_std_error(&jdsterr);
  jpeg_create_compress(&dstinfo);

#ifdef NEED_SIGNAL_CATCHER
  enable_signal_catcher((j_common_ptr) &srcinfo);
#endif


  file_index = parse_switches(&dstinfo, argc, argv, 0, FALSE);
  jsrcerr.trace_level = jdsterr.trace_level;
  srcinfo.mem->max_memory_to_use = dstinfo.mem->max_memory_to_use;

#ifdef TWO_FILE_COMMANDLINE
  
  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
  
  if (file_index < argc-1) {
    fprintf(stderr, "%s: only one input file\n", progname);
    usage();
  }
#endif 

  
  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 {
    
    input_file = read_stdin();
  }

  
  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 {
    
    output_file = write_stdout();
  }

#ifdef PROGRESS_REPORT
  start_progress_monitor((j_common_ptr) &dstinfo, &progress);
#endif

  
  jpeg_stdio_src(&srcinfo, input_file);

  
  jcopy_markers_setup(&srcinfo, copyoption);

  
  (void) jpeg_read_header(&srcinfo, TRUE);

#if TRANSFORMS_SUPPORTED
  jtransform_request_workspace(&srcinfo, &transformoption);
#endif

  
  src_coef_arrays = jpeg_read_coefficients(&srcinfo);

  
  jpeg_copy_critical_parameters(&srcinfo, &dstinfo);

#if TRANSFORMS_SUPPORTED
  dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo,
						 src_coef_arrays,
						 &transformoption);
#else
  dst_coef_arrays = src_coef_arrays;
#endif

  
  file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE);

  
  jpeg_stdio_dest(&dstinfo, output_file);

  /* Start compressor (note no image data is actually written here) */
  jpeg_write_coefficients(&dstinfo, dst_coef_arrays);

  
  jcopy_markers_execute(&srcinfo, &dstinfo, copyoption);

  
#if TRANSFORMS_SUPPORTED
  jtransform_execute_transformation(&srcinfo, &dstinfo,
				    src_coef_arrays,
				    &transformoption);
#endif

  
  jpeg_finish_compress(&dstinfo);
  jpeg_destroy_compress(&dstinfo);
  (void) jpeg_finish_decompress(&srcinfo);
  jpeg_destroy_decompress(&srcinfo);

  
  if (input_file != stdin)
    fclose(input_file);
  if (output_file != stdout)
    fclose(output_file);

#ifdef PROGRESS_REPORT
  end_progress_monitor((j_common_ptr) &dstinfo);
#endif

  
  exit(jsrcerr.num_warnings + jdsterr.num_warnings ?EXIT_WARNING:EXIT_SUCCESS);
  return 0;			
}
/***********************************************************************
压缩图像到jpeg格式
如果压缩前图像为灰度图或24位图,压缩后图像色彩模式不变
如果压缩前图像为256色索引位图,压缩后变为灰度图
************************************************************************/
void bmptojpg(const char *strSourceFileName, const char *strDestFileName)
{
	BITMAPFILEHEADER bfh;		// bmp文件头
	BITMAPINFOHEADER bih;		// bmp头信息
	RGBQUAD rq[256];			// 调色板

	BYTE *data= NULL;//new BYTE[bih.biWidth*bih.biHeight];
	//BYTE *pDataConv = NULL;//new BYTE[bih.biWidth*bih.biHeight];
	int nComponent = 0;

	// 打开图像文件
	FILE *f = fopen(strSourceFileName,"rb");
	if (f==NULL)
	{
		printf("Open file error!\n");
		return;
	}
	// 读取文件头
	fread(&bfh,sizeof(bfh),1,f);
	// 读取图像信息
	fread(&bih,sizeof(bih),1,f);
	// 为了简单,在本例中,只演示8位索引图像
	switch (bih.biBitCount) 
	{
	case 8:
		if (bfh.bfOffBits-1024<54) 
		{
			fclose(f);
			return;
		}
		data= new BYTE[bih.biWidth*bih.biHeight];
		//pDataConv = new BYTE[bih.biWidth*bih.biHeight];

		// 定位调色板,并读取调色板
		fseek(f,bfh.bfOffBits-1024,SEEK_SET);	
		fread(rq,sizeof(RGBQUAD),256,f);
		// 读取位图
		fread(data,bih.biWidth*bih.biHeight,1,f);
		fclose(f);
		nComponent = 1;
		break;
	case 24:
		{
		data= new BYTE[bih.biWidth*bih.biHeight*3];
		//pDataConv = new BYTE[bih.biWidth*bih.biHeight*3];
		fseek(f,bfh.bfOffBits,SEEK_SET);	
		fread(data,bih.biWidth*bih.biHeight*3,1,f);
		fclose(f);
		for (int i = 0;i<bih.biWidth*bih.biHeight;i++)
		{
			BYTE red = data[i*3];
			data[i*3] = data[i*3+2];
			data[i*3+2] = red;
		}
		nComponent = 3;
		break;
		}
	default:
		fclose(f);
		return;
	}

	// 以上图像读取完毕
	/*
	// 下面对图像进行变换,只是针对灰度图,我在实际应用时需要用到
	int x=0,y=0;
	int nWidth = 0 , nHeight = 0;
	// Y镜像
	for (y=0;y<bih.biHeight;y++)
	{
		memcpy(&pDataConv[y*bih.biWidth],&data[(bih.biHeight-y-1)*bih.biWidth],bih.biWidth);
	}
	memcpy(data,pDataConv,bih.biSizeImage);
	// 根据命令行参数对图像进行变换
	if (argc==2)
	{
		switch (argv[1][0])
		{
		case 'x':
			// X镜像
			for (x=0;x<bih.biWidth;x++) {
				for (y=0;y<bih.biHeight;y++)
				{
					pDataConv[y*bih.biWidth+x] = data[(y+1)*bih.biWidth-x-1];
				}
			}
			nWidth = bih.biWidth;
			nHeight = bih.biHeight;
			break;
		case 'y':
			// Y镜像
			for (y=0;y<bih.biHeight;y++)
			{
				memcpy(&pDataConv[y*bih.biWidth],&data[(bih.biHeight-y-1)*bih.biWidth],bih.biWidth);
			}
			nWidth = bih.biWidth;
			nHeight = bih.biHeight;
			break;
		case 'a':
			// XY镜像
			for (x=0;x<bih.biWidth;x++) {
				for (y=0;y<bih.biHeight;y++)
				{
					pDataConv[y*bih.biWidth+x] = data[(bih.biHeight-y)*bih.biWidth-x-1];
				}
			}
			nWidth = bih.biWidth;
			nHeight = bih.biHeight;
			break;
		case 'r':
			// 先上下镜像然后旋转90度
			for (x=0;x<bih.biWidth;x++) {
				for (y=0;y<bih.biHeight;y++)
				{
					pDataConv[x*bih.biHeight+y] = data[(bih.biHeight -y-1)*bih.biWidth+x];
				}
			}
			nWidth = bih.biHeight;
			nHeight = bih.biWidth;
			break;
		case 'l':
			// 先上下镜像然后旋转270度
			for (x=0;x<bih.biWidth;x++) {
				for (y=0;y<bih.biHeight;y++)
				{
					pDataConv[x*bih.biHeight+y] = data[(y+1)*bih.biWidth-x-1];
				}
			}
			nWidth = bih.biHeight;
			nHeight = bih.biWidth;
			break;
		default: 
			printf("Invalid parameter\n\tTestLibjpeg.exe [x|y|a|r|]l\n");
			break;
		}
	}
	else
	{
		memcpy(pDataConv,data,bih.biSizeImage);
		nWidth = bih.biWidth;
		nHeight = bih.biHeight;
	}
	// 图像变换完毕,下面对图像进行压缩
	*/
	struct jpeg_compress_struct jcs;
	struct jpeg_error_mgr jem;
	jcs.err = jpeg_std_error(&jem);

	jpeg_create_compress(&jcs);

	f=fopen(strDestFileName,"wb");
	if (f==NULL) 
	{
		delete [] data;
		//delete [] pDataConv;
		return;
	}
	jpeg_stdio_dest(&jcs, f);
	jcs.image_width = bih.biWidth; 			// 为图的宽和高,单位为像素 
	jcs.image_height = bih.biHeight;
	jcs.input_components = nComponent;			// 1,表示灰度图, 如果是彩色位图,则为3 
	if (nComponent==1)
		jcs.in_color_space = JCS_GRAYSCALE; //JCS_GRAYSCALE表示灰度图,JCS_RGB表示彩色图像 
	else 
		jcs.in_color_space = JCS_RGB;

	jpeg_set_defaults(&jcs);	
	jpeg_set_quality (&jcs, 60, true);

	jpeg_start_compress(&jcs, TRUE);

	JSAMPROW row_pointer[1];			// 一行位图
	int row_stride;						// 每一行的字节数 

	row_stride = jcs.image_width*nComponent;		// 如果不是索引图,此处需要乘以3

	// 对每一行进行压缩
	while (jcs.next_scanline < jcs.image_height) {
	    row_pointer[0] = & data[(jcs.image_height-jcs.next_scanline-1) * row_stride];
	    jpeg_write_scanlines(&jcs, row_pointer, 1);
	}

	jpeg_finish_compress(&jcs);

	jpeg_destroy_compress(&jcs);

	fclose(f);
	delete [] data;

}
Ejemplo n.º 15
0
int main(int argc, char **argv) 
{
  char tmpfilename[MAXPATHLEN],tmpdir[MAXPATHLEN];
  char newname[MAXPATHLEN], dest_path[MAXPATHLEN];
  volatile int i;
  int c,j, err_count;
  int opt_index = 0;
  long insize,outsize;
  double ratio;
  struct utimbuf time_save;
  jpeg_saved_marker_ptr cmarker; 


  if (rcsid); /* so compiler won't complain about "unused" rcsid string */

  signal(SIGINT,own_signal_handler);
  signal(SIGTERM,own_signal_handler);

  /* initialize decompression object */
  dinfo.err = jpeg_std_error(&jderr.pub);
  jpeg_create_decompress(&dinfo);
  jderr.pub.error_exit=my_error_exit;
  jderr.pub.output_message=my_output_message;

  /* initialize compression object */
  cinfo.err = jpeg_std_error(&jcerr.pub);
  jpeg_create_compress(&cinfo);
  jcerr.pub.error_exit=my_error_exit;
  jcerr.pub.output_message=my_output_message;


  if (argc<2) {
    if (!quiet_mode) fprintf(stderr,"jpegoptim: file arguments missing\n"
			     "Try 'jpegoptim --help' for more information.\n");
    exit(1);
  }
 
  /* parse command line parameters */
  while(1) {
    opt_index=0;
    if ((c=getopt_long(argc,argv,"d:hm:ntqvfVpoT:",long_options,&opt_index))
	      == -1) 
      break;

    switch (c) {
    case 'm':
      {
        int tmpvar;

        if (sscanf(optarg,"%d",&tmpvar) == 1) {
	  quality=tmpvar;
	  if (quality < 0) quality=0;
	  if (quality > 100) quality=100;
	}
	else 
	  fatal("invalid argument for -m, --max");
      }
      break;
    case 'd':
      if (realpath(optarg,dest_path)==NULL || !is_directory(dest_path)) {
	fatal("invalid argument for option -d, --dest");
      }
      if (verbose_mode) 
	fprintf(stderr,"Destination directory: %s\n",dest_path);
      dest=1;
      break;
    case 'v':
      verbose_mode++;
      break;
    case 'h':
      p_usage();
      break;
    case 'q':
      quiet_mode=1;
      break;
    case 't':
      totals_mode=1;
      break;
    case 'n':
      noaction=1;
      break;
    case 'f':
      force=1;
      break;
    case '?':
      break;
    case 'V':
      printf("jpegoptim v%s  %s\n",VERSIO,HOST_TYPE);
      printf("Copyright (c) Timo Kokkonen, 1996-2011.\n");
      exit(0);
      break;
    case 'o':
      overwrite_mode=1;
      break;
    case 'p':
      preserve_mode=1;
      break;
    case 's':
      save_exif=0;
      save_iptc=0;
      save_com=0;
      save_icc=0;
      break;
    case 'c':
      save_com=0;
      break;
    case 'e':
      save_exif=0;
      break;
    case 'i':
      save_iptc=0;
      break;
    case 'P':
      save_icc=0;
      break;
    case 'T':
      {
	int tmpvar;
	if (sscanf(optarg,"%d",&tmpvar) == 1) {
	  threshold=tmpvar;
	  if (threshold < 0) threshold=0;
	  if (threshold > 100) threshold=100;
	}
	else fatal("invalid argument for -T, --threshold");
      }
      break;

    default:
      if (!quiet_mode) 
	fprintf(stderr,"jpegoptim: error parsing parameters.\n");
    }
  }


  if (verbose_mode && (quality>=0)) 
    fprintf(stderr,"Image quality limit set to: %d\n",quality);
  if (verbose_mode && (threshold>=0)) 
    fprintf(stderr,"Compression treshold (%%) set to: %d\n",threshold);
  

  /* loop to process the input files */
  i=1;  
  do {
   if (!argv[i][0]) continue;
   if (argv[i][0]=='-') continue;

   if (!noaction) {
     /* generate temp (& new) filename */
     if (dest) {
       strncpy(tmpdir,dest_path,sizeof(tmpdir));
       strncpy(newname,dest_path,sizeof(newname));
       if (tmpdir[strlen(tmpdir)-1] != '/') {
	 strncat(tmpdir,"/",sizeof(tmpdir)-strlen(tmpdir));
	 strncat(newname,"/",sizeof(newname)-strlen(newname));
       }
       strncat(newname,(char*)basename(argv[i]),
	       sizeof(newname)-strlen(newname));
     } else {
       if (!splitdir(argv[i],tmpdir,sizeof(tmpdir))) 
	 fatal("splitdir() failed!");
       strncpy(newname,argv[i],sizeof(newname));
     }
     snprintf(tmpfilename,sizeof(tmpfilename),
	      "%sjpegoptim-%d-%d.tmp", tmpdir, (int)getuid(), (int)getpid());
   }

  retry_point:
   if ((infile=fopen(argv[i],"r"))==NULL) {
     if (!quiet_mode) fprintf(stderr, "jpegoptim: can't open %s\n", argv[i]);
     continue;
   }
   if (is_dir(infile,&time_save.actime,&time_save.modtime)) {
     fclose(infile);
     if (verbose_mode) printf("directory: %s  skipped\n",argv[i]); 
     continue;
   }

   /* setup error handling for decompress */
   if (setjmp(jderr.setjmp_buffer)) {
      jpeg_abort_decompress(&dinfo);
      fclose(infile);
      if (buf) {
	for (j=0;j<dinfo.output_height;j++) free(buf[j]);
	free(buf); buf=NULL;
      }
      printf(" [ERROR]\n");
      continue;
   }

   if (!retry) { printf("%s ",argv[i]); fflush(stdout); }

   /* prepare to decompress */
   global_error_counter=0;
   err_count=jderr.pub.num_warnings;
   if (save_com) jpeg_save_markers(&dinfo, JPEG_COM, 0xffff);
   if (save_iptc) jpeg_save_markers(&dinfo, IPTC_JPEG_MARKER, 0xffff);
   if (save_exif) jpeg_save_markers(&dinfo, EXIF_JPEG_MARKER, 0xffff);
   if (save_icc) jpeg_save_markers(&dinfo, ICC_JPEG_MARKER, 0xffff);

   jpeg_stdio_src(&dinfo, infile);
   jpeg_read_header(&dinfo, TRUE); 

   /* check for Exif/IPTC markers */
   exif_marker=NULL;
   iptc_marker=NULL;
   icc_marker=NULL;
   cmarker=dinfo.marker_list;
   while (cmarker) {
     if (cmarker->marker == EXIF_JPEG_MARKER) {
       if (!memcmp(cmarker->data,EXIF_IDENT_STRING,EXIF_IDENT_STRING_SIZE)) 
	 exif_marker=cmarker;
     }
     if (cmarker->marker == IPTC_JPEG_MARKER) {
       iptc_marker=cmarker;
     }
     if (cmarker->marker == ICC_JPEG_MARKER) {
       if (!memcmp(cmarker->data,ICC_IDENT_STRING,ICC_IDENT_STRING_SIZE)) 
	 icc_marker=cmarker;
     }
     cmarker=cmarker->next;
   }


   if (!retry) {
     printf("%dx%d %dbit ",(int)dinfo.image_width,
	    (int)dinfo.image_height,(int)dinfo.num_components*8);

     if (exif_marker) printf("Exif ");
     if (iptc_marker) printf("IPTC ");
     if (icc_marker) printf("ICC ");
     if (dinfo.saw_Adobe_marker) printf("Adobe ");
     if (dinfo.saw_JFIF_marker) printf("JFIF ");
     fflush(stdout);
   }

   insize=file_size(infile);

  /* decompress the file */
   if (quality>=0 && !retry) {
     jpeg_start_decompress(&dinfo);

     buf = malloc(sizeof(JSAMPROW)*dinfo.output_height);
     if (!buf) fatal("not enough memory");
     for (j=0;j<dinfo.output_height;j++) {
       buf[j]=malloc(sizeof(JSAMPLE)*dinfo.output_width*
		     dinfo.out_color_components);
       if (!buf[j]) fatal("not enough memory");
     }

     while (dinfo.output_scanline < dinfo.output_height) {
       jpeg_read_scanlines(&dinfo,&buf[dinfo.output_scanline],
			   dinfo.output_height-dinfo.output_scanline);
     }
   } else {
     coef_arrays = jpeg_read_coefficients(&dinfo);
   }

   if (!retry) {
     if (!global_error_counter) printf(" [OK] ");
     else printf(" [WARNING] ");
     fflush(stdout);
   }


   if (dest && !noaction) {
     if (file_exists(newname) && !overwrite_mode) {
       fprintf(stderr,"target file already exists!\n");
       jpeg_abort_decompress(&dinfo);
       fclose(infile);
       if (buf) {
	 for (j=0;j<dinfo.output_height;j++) free(buf[j]);
	 free(buf); buf=NULL;
       }
       continue;
     }
   }

   if (noaction) {
     outfname=NULL;
     if ((outfile=tmpfile())==NULL) fatal("error opening temp file");
   } else {
     outfname=tmpfilename;
     if ((outfile=fopen(outfname,"w"))==NULL) 
       fatal("error opening target file");
   }

   if (setjmp(jcerr.setjmp_buffer)) {
      jpeg_abort_compress(&cinfo);
      jpeg_abort_decompress(&dinfo);
      fclose(outfile);
      if (infile) fclose(infile);
      printf(" [Compress ERROR]\n");
      if (buf) {
	for (j=0;j<dinfo.output_height;j++) free(buf[j]);
	free(buf); buf=NULL;
      }
      if (file_exists(outfname)) delete_file(outfname);
      outfname=NULL;
      continue;
   }


   jpeg_stdio_dest(&cinfo, outfile);

   if (quality>=0 && !retry) {
     /* lossy "optimization" ... */

     cinfo.in_color_space=dinfo.out_color_space;
     cinfo.input_components=dinfo.output_components;
     cinfo.image_width=dinfo.image_width;
     cinfo.image_height=dinfo.image_height;
     jpeg_set_defaults(&cinfo); 
     jpeg_set_quality(&cinfo,quality,TRUE);
     cinfo.optimize_coding = TRUE;
     
     j=0;
     jpeg_start_compress(&cinfo,TRUE);
     
     /* write markers */
     write_markers(&dinfo,&cinfo);

     while (cinfo.next_scanline < cinfo.image_height) {
       jpeg_write_scanlines(&cinfo,&buf[cinfo.next_scanline],
			    dinfo.output_height);
     }
     
     for (j=0;j<dinfo.output_height;j++) free(buf[j]);
     free(buf); buf=NULL;
   } else {
     /* lossless "optimization" ... */

     jpeg_copy_critical_parameters(&dinfo, &cinfo);
     cinfo.optimize_coding = TRUE;

     jpeg_write_coefficients(&cinfo, coef_arrays);

     /* write markers */
     write_markers(&dinfo,&cinfo);
   }



   jpeg_finish_compress(&cinfo);
   jpeg_finish_decompress(&dinfo);
   fclose(infile);
   outsize=file_size(outfile);
   fclose(outfile);

   if (preserve_mode && !noaction) {
     if (utime(outfname,&time_save) != 0) {
       fprintf(stderr,"jpegoptim: failed to reset output file time/date\n");
     }
   }

   if (quality>=0 && outsize>=insize && !retry) {
     if (verbose_mode) printf("(retry w/lossless) ");
     retry=1;
     goto retry_point; 
   }

   retry=0;
   ratio=(insize-outsize)*100.0/insize;
   printf("%ld --> %ld bytes (%0.2f%%), ",insize,outsize,ratio);
   average_count++;
   average_rate+=(ratio<0 ? 0.0 : ratio);

   if ((outsize < insize && ratio >= threshold) || force) {
        total_save+=(insize-outsize)/1024.0;
	printf("optimized.\n");
        if (noaction) continue;
	if (verbose_mode > 1 && !quiet_mode) 
	  fprintf(stderr,"renaming: %s to %s\n",outfname,newname);
	if (rename(outfname,newname)) fatal("cannot rename temp file");
   } else {
	printf("skipped.\n");
	if (!noaction) delete_file(outfname);
   }
   

  } while (++i<argc);


  if (totals_mode&&!quiet_mode)
    printf("Average ""compression"" (%ld files): %0.2f%% (%0.0fk)\n",
	   average_count, average_rate/average_count, total_save);
  jpeg_destroy_decompress(&dinfo);
  jpeg_destroy_compress(&cinfo);

  return 0;
}
Ejemplo n.º 16
0
static gboolean
_cairo_surface_write_as_jpeg (cairo_surface_t  *image,
			      char            **buffer,
			      gsize            *buffer_size,
			      char            **keys,
			      char            **values,
			      GError          **error)
{
	struct jpeg_compress_struct cinfo;
	struct error_handler_data jerr;
	guchar            *buf = NULL;
	guchar            *pixels = NULL;
	volatile int       quality = 85; /* default; must be between 0 and 100 */
	volatile int       smoothing = 0;
	volatile gboolean  optimize = FALSE;
#ifdef HAVE_PROGRESSIVE_JPEG
	volatile gboolean  progressive = FALSE;
#endif
	int                w, h = 0;
	int                rowstride = 0;

	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;
				}
			}
#ifdef HAVE_PROGRESSIVE_JPEG
			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;
				}
			}
#endif
			else {
				g_warning ("Bad option name '%s' passed to JPEG saver", *kiter);
				return FALSE;
			}

			++kiter;
			++viter;
		}
	}

	rowstride = cairo_image_surface_get_stride (image);
	w = cairo_image_surface_get_width (image);
	h = cairo_image_surface_get_height (image);
	pixels = _cairo_image_surface_flush_and_get_data (image);
	g_return_val_if_fail (pixels != NULL, FALSE);

	/* allocate a small buffer to convert image data */

	buf = g_try_malloc (w * 3 * 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_memory_dest (&cinfo, (void **)buffer, buffer_size);

	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);

	/* go one scanline at a time... and save */
	while (cinfo.next_scanline < cinfo.image_height) {
		JSAMPROW *jbuf;

		/* convert scanline from RGBA to RGB packed */

		_cairo_copy_line_as_rgba_big_endian (buf, pixels, w, FALSE);

		/* write scanline */
		jbuf = (JSAMPROW *)(&buf);
		jpeg_write_scanlines (&cinfo, jbuf, 1);

		pixels += rowstride;
	}

	/* finish off */

	jpeg_finish_compress (&cinfo);
	jpeg_destroy_compress (&cinfo);
	g_free (buf);

	return TRUE;
}
Ejemplo n.º 17
0
bool LICE_WriteJPG(const char *filename, LICE_IBitmap *bmp, int quality, bool force_baseline)
{
  if (!bmp || !filename) return false;

  FILE *fp=NULL;
#if defined(_WIN32) && !defined(WDL_NO_SUPPORT_UTF8)
  #ifdef WDL_SUPPORT_WIN9X
  if (GetVersion()<0x80000000)
  #endif
  {
    WCHAR wf[2048];
    if (MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,filename,-1,wf,2048))
      fp = _wfopen(wf,L"wb");
  }
#endif
  if (!fp) fp = fopen(filename,"wb");

  if (!fp) return false;

  struct jpeg_compress_struct cinfo;
  struct my_error_mgr jerr={0,};
  jerr.pub.error_exit = LICEJPEG_Error;
  jerr.pub.emit_message = LICEJPEG_EmitMsg;
  jerr.pub.output_message = LICEJPEG_OutMsg;
  jerr.pub.format_message = LICEJPEG_FmtMsg;
  jerr.pub.reset_error_mgr = LICEJPEG_reset_error_mgr;

  cinfo.err = &jerr.pub;
  unsigned char *buf = NULL;

  if (setjmp(jerr.setjmp_buffer)) 
  {
    jpeg_destroy_compress(&cinfo);
    if (fp) fclose(fp);
    free(buf);
    return false;
  }
  jpeg_create_compress(&cinfo);

  jpeg_stdio_dest(&cinfo, fp);

  cinfo.image_width = bmp->getWidth(); 	/* image width and height, in pixels */
  cinfo.image_height = bmp->getHeight();
  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, !!force_baseline);
  jpeg_start_compress(&cinfo, TRUE);

  buf = (unsigned char *)malloc(cinfo.image_width * 3);
  LICE_pixel_chan *rd = (LICE_pixel_chan *)bmp->getBits();
  int rowspan = bmp->getRowSpan()*4;
  if (bmp->isFlipped())
  {
    rd += rowspan*(bmp->getHeight()-1);
    rowspan=-rowspan;
  }
  while (cinfo.next_scanline < cinfo.image_height) 
  {
    unsigned char *outp=buf;
    LICE_pixel_chan *rdp = rd;
    int x=cinfo.image_width;
    while(x--)
    {
      outp[0] = rdp[LICE_PIXEL_R];
      outp[1] = rdp[LICE_PIXEL_G];
      outp[2] = rdp[LICE_PIXEL_B];
      outp+=3;
      rdp+=4;
    }
    jpeg_write_scanlines(&cinfo, &buf, 1);

    rd+=rowspan;
  }
  free(buf); 
  buf=0;

  jpeg_finish_compress(&cinfo);

  if (fp) fclose(fp);
  fp=0;

  jpeg_destroy_compress(&cinfo);

  return true;
}
Ejemplo n.º 18
0
static gboolean
background_jpeg_save (PreviewPersistent *pp)
{
  gint yend;

  if (pp->abort_me || (pp->cinfo.next_scanline >= pp->cinfo.image_height))
    {
      /* clean up... */
      if (pp->abort_me)
        {
          jpeg_abort_compress (&(pp->cinfo));
        }
      else
        {
          jpeg_finish_compress (&(pp->cinfo));
        }

      fclose (pp->outfile);
      jpeg_destroy_compress (&(pp->cinfo));

      g_free (pp->data);

      if (pp->buffer)
        g_object_unref (pp->buffer);

      /* display the preview stuff */
      if (!pp->abort_me)
        {
          GFile     *file = g_file_new_for_path (pp->file_name);
          GFileInfo *info;
          gchar     *text;
          GError    *error = NULL;

          info = g_file_query_info (file,
                                    G_FILE_ATTRIBUTE_STANDARD_SIZE,
                                    G_FILE_QUERY_INFO_NONE,
                                    NULL, &error);

          if (info)
            {
              goffset  size = g_file_info_get_size (info);
              gchar   *size_text;

              size_text = g_format_size (size);
              text = g_strdup_printf (_("File size: %s"), size_text);
              g_free (size_text);

              g_object_unref (info);
            }
          else
            {
              text = g_strdup_printf (_("File size: %s"), error->message);
              g_clear_error (&error);
            }

          gtk_label_set_text (GTK_LABEL (preview_size), text);
          g_free (text);

          g_object_unref (file);

          /* and load the preview */
          load_image (pp->file_name, GIMP_RUN_NONINTERACTIVE, TRUE, NULL, NULL);
        }

      /* we cleanup here (load_image doesn't run in the background) */
      g_unlink (pp->file_name);

      g_free (pp);
      prev_p = NULL;

      gimp_displays_flush ();
      gdk_flush ();

      return FALSE;
    }
  else
    {
      if ((pp->cinfo.next_scanline % pp->tile_height) == 0)
        {
          yend = pp->cinfo.next_scanline + pp->tile_height;
          yend = MIN (yend, pp->cinfo.image_height);
          gegl_buffer_get (pp->buffer,
                           GEGL_RECTANGLE (0, pp->cinfo.next_scanline,
                                           pp->cinfo.image_width,
                                           (yend - pp->cinfo.next_scanline)),
                           1.0,
                           pp->format,
                           pp->data,
                           GEGL_AUTO_ROWSTRIDE,
                           GEGL_ABYSS_NONE);
          pp->src = pp->data;
        }

      jpeg_write_scanlines (&(pp->cinfo), (JSAMPARRAY) &(pp->src), 1);
      pp->src += pp->rowstride;

      return TRUE;
    }
}
Ejemplo n.º 19
0
static bool encodePixels(IntSize imageSize, unsigned char* inputPixels, bool premultiplied, int quality, Vector<unsigned char>* output)
{
    JPEGOutputBuffer destination;
    destination.output = output;
    Vector<JSAMPLE> row;

    jpeg_compress_struct cinfo;
    jpeg_error_mgr error;
    cinfo.err = jpeg_std_error(&error);
    error.error_exit = handleError;
    jmp_buf jumpBuffer;
    cinfo.client_data = &jumpBuffer;

    if (setjmp(jumpBuffer)) {
        jpeg_destroy_compress(&cinfo);
        return false;
    }

    jpeg_create_compress(&cinfo);
    cinfo.dest = &destination;
    cinfo.dest->init_destination = prepareOutput;
    cinfo.dest->empty_output_buffer = writeOutput;
    cinfo.dest->term_destination = finishOutput;

    imageSize.clampNegativeToZero();
    cinfo.image_height = imageSize.height();
    cinfo.image_width = imageSize.width();

#if defined(JCS_EXTENSIONS)
    if (premultiplied) {
        cinfo.in_color_space = SK_B32_SHIFT ? JCS_EXT_RGBX : JCS_EXT_BGRX;

        cinfo.input_components = 4;

        jpeg_set_defaults(&cinfo);
        jpeg_set_quality(&cinfo, quality, TRUE);
        jpeg_start_compress(&cinfo, TRUE);

        unsigned char* pixels = inputPixels;
        const size_t pixelRowStride = cinfo.image_width * 4;
        while (cinfo.next_scanline < cinfo.image_height) {
            jpeg_write_scanlines(&cinfo, &pixels, 1);
            pixels += pixelRowStride;
        }

        jpeg_finish_compress(&cinfo);
        jpeg_destroy_compress(&cinfo);
        return true;
    }
#endif

    cinfo.in_color_space = JCS_RGB;
    cinfo.input_components = 3;

    void (*extractRowRGB)(const unsigned char*, unsigned int, unsigned char* output);
    extractRowRGB = &RGBAtoRGB;
    if (premultiplied)
        extractRowRGB = &preMultipliedBGRAtoRGB;

    jpeg_set_defaults(&cinfo);
    jpeg_set_quality(&cinfo, quality, TRUE);
    jpeg_start_compress(&cinfo, TRUE);

    unsigned char* pixels = inputPixels;
    row.resize(cinfo.image_width * cinfo.input_components);
    const size_t pixelRowStride = cinfo.image_width * 4;
    while (cinfo.next_scanline < cinfo.image_height) {
        extractRowRGB(pixels, cinfo.image_width, row.data());
        jpeg_write_scanlines(&cinfo, row.dataSlot(), 1);
        pixels += pixelRowStride;
    }

    jpeg_finish_compress(&cinfo);
    jpeg_destroy_compress(&cinfo);
    return true;
}
Ejemplo n.º 20
0
gboolean
save_image (const gchar  *filename,
            gint32        image_ID,
            gint32        drawable_ID,
            gint32        orig_image_ID,
            gboolean      preview,
            GError      **error)
{
  GimpImageType  drawable_type;
  GeglBuffer    *buffer = NULL;
  const Babl    *format;
  GimpParasite  *parasite;
  static struct jpeg_compress_struct cinfo;
  static struct my_error_mgr         jerr;
  JpegSubsampling             subsampling;
  FILE     * volatile outfile;
  guchar   *data;
  guchar   *src;
  gboolean  has_alpha;
  gint      rowstride, yend;

  drawable_type = gimp_drawable_type (drawable_ID);
  buffer = gimp_drawable_get_buffer (drawable_ID);

  if (! preview)
    gimp_progress_init_printf (_("Saving '%s'"),
                               gimp_filename_to_utf8 (filename));

  /* 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.pub);
  jerr.pub.error_exit = my_error_exit;

  outfile = NULL;
  /* 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)
        fclose (outfile);
      if (buffer)
        g_object_unref (buffer);

      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. */

  /* 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.
   */
  if ((outfile = g_fopen (filename, "wb")) == NULL)
    {
      g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
                   _("Could not open '%s' for writing: %s"),
                   gimp_filename_to_utf8 (filename), g_strerror (errno));
      return FALSE;
    }

  jpeg_stdio_dest (&cinfo, outfile);

  /* Get the input image and a pointer to its data.
   */
  switch (drawable_type)
    {
    case GIMP_RGB_IMAGE:
      /* # of color components per pixel */
      cinfo.input_components = 3;
      has_alpha = FALSE;
      format = babl_format ("R'G'B' u8");
      break;

    case GIMP_GRAY_IMAGE:
      /* # of color components per pixel */
      cinfo.input_components = 1;
      has_alpha = FALSE;
      format = babl_format ("Y' u8");
      break;

    case GIMP_RGBA_IMAGE:
      /* # of color components per pixel (minus the GIMP alpha channel) */
      cinfo.input_components = 4 - 1;
      has_alpha = TRUE;
      format = babl_format ("R'G'B' u8");
      break;

    case GIMP_GRAYA_IMAGE:
      /* # of color components per pixel (minus the GIMP alpha channel) */
      cinfo.input_components = 2 - 1;
      has_alpha = TRUE;
      format = babl_format ("Y' u8");
      break;

    case GIMP_INDEXED_IMAGE:
    default:
      return FALSE;
    }

  /* 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:
   */
  /* image width and height, in pixels */
  cinfo.image_width  = gegl_buffer_get_width (buffer);
  cinfo.image_height = gegl_buffer_get_height (buffer);
  /* colorspace of input image */
  cinfo.in_color_space = (drawable_type == GIMP_RGB_IMAGE ||
                          drawable_type == GIMP_RGBA_IMAGE)
    ? JCS_RGB : JCS_GRAYSCALE;
  /* 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);

  jpeg_set_quality (&cinfo, (gint) (jsvals.quality + 0.5), jsvals.baseline);

  if (jsvals.use_orig_quality && num_quant_tables > 0)
    {
      guint **quant_tables;
      gint    t;

      /* override tables generated by jpeg_set_quality() with custom tables */
      quant_tables = jpeg_restore_original_tables (image_ID, num_quant_tables);
      if (quant_tables)
        {
          for (t = 0; t < num_quant_tables; t++)
            {
              jpeg_add_quant_table (&cinfo, t, quant_tables[t],
                                    100, jsvals.baseline);
              g_free (quant_tables[t]);
            }
          g_free (quant_tables);
        }
    }

  if (arithc_supported)
    {
      cinfo.arith_code = jsvals.arithmetic_coding;
      if (!jsvals.arithmetic_coding)
        cinfo.optimize_coding = jsvals.optimize;
    }
  else
    cinfo.optimize_coding = jsvals.optimize;

  subsampling = (gimp_drawable_is_rgb (drawable_ID) ?
                 jsvals.subsmp : JPEG_SUBSAMPLING_1x1_1x1_1x1);

  /*  smoothing is not supported with nonstandard sampling ratios  */
  if (subsampling != JPEG_SUBSAMPLING_2x1_1x1_1x1 &&
      subsampling != JPEG_SUBSAMPLING_1x2_1x1_1x1)
    {
      cinfo.smoothing_factor = (gint) (jsvals.smoothing * 100);
    }

  if (jsvals.progressive)
    {
      jpeg_simple_progression (&cinfo);
    }

  switch (subsampling)
    {
    case JPEG_SUBSAMPLING_2x2_1x1_1x1:
    default:
      cinfo.comp_info[0].h_samp_factor = 2;
      cinfo.comp_info[0].v_samp_factor = 2;
      cinfo.comp_info[1].h_samp_factor = 1;
      cinfo.comp_info[1].v_samp_factor = 1;
      cinfo.comp_info[2].h_samp_factor = 1;
      cinfo.comp_info[2].v_samp_factor = 1;
      break;

    case JPEG_SUBSAMPLING_2x1_1x1_1x1:
      cinfo.comp_info[0].h_samp_factor = 2;
      cinfo.comp_info[0].v_samp_factor = 1;
      cinfo.comp_info[1].h_samp_factor = 1;
      cinfo.comp_info[1].v_samp_factor = 1;
      cinfo.comp_info[2].h_samp_factor = 1;
      cinfo.comp_info[2].v_samp_factor = 1;
      break;

    case JPEG_SUBSAMPLING_1x1_1x1_1x1:
      cinfo.comp_info[0].h_samp_factor = 1;
      cinfo.comp_info[0].v_samp_factor = 1;
      cinfo.comp_info[1].h_samp_factor = 1;
      cinfo.comp_info[1].v_samp_factor = 1;
      cinfo.comp_info[2].h_samp_factor = 1;
      cinfo.comp_info[2].v_samp_factor = 1;
      break;

    case JPEG_SUBSAMPLING_1x2_1x1_1x1:
      cinfo.comp_info[0].h_samp_factor = 1;
      cinfo.comp_info[0].v_samp_factor = 2;
      cinfo.comp_info[1].h_samp_factor = 1;
      cinfo.comp_info[1].v_samp_factor = 1;
      cinfo.comp_info[2].h_samp_factor = 1;
      cinfo.comp_info[2].v_samp_factor = 1;
      break;
    }

  cinfo.restart_interval = 0;
  cinfo.restart_in_rows = jsvals.restart;

  switch (jsvals.dct)
    {
    case 0:
    default:
      cinfo.dct_method = JDCT_ISLOW;
      break;

    case 1:
      cinfo.dct_method = JDCT_IFAST;
      break;

    case 2:
      cinfo.dct_method = JDCT_FLOAT;
      break;
    }

  {
    gdouble xresolution;
    gdouble yresolution;

    gimp_image_get_resolution (orig_image_ID, &xresolution, &yresolution);

    if (xresolution > 1e-5 && yresolution > 1e-5)
      {
        gdouble factor;

        factor = gimp_unit_get_factor (gimp_image_get_unit (orig_image_ID));

        if (factor == 2.54 /* cm */ ||
            factor == 25.4 /* mm */)
          {
            cinfo.density_unit = 2;  /* dots per cm */

            xresolution /= 2.54;
            yresolution /= 2.54;
          }
        else
          {
            cinfo.density_unit = 1;  /* dots per inch */
          }

        cinfo.X_density = xresolution;
        cinfo.Y_density = yresolution;
      }
  }

  /* 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 4.1: Write the comment out - pw */
  if (image_comment && *image_comment)
    {
#ifdef GIMP_UNSTABLE
      g_print ("jpeg-save: saving image comment (%d bytes)\n",
               (int) strlen (image_comment));
#endif
      jpeg_write_marker (&cinfo, JPEG_COM,
                         (guchar *) image_comment, strlen (image_comment));
    }

  /* Step 4.2: store the color profile if there is one */
  parasite = gimp_image_get_parasite (orig_image_ID, "icc-profile");
  if (parasite)
    {
      jpeg_icc_write_profile (&cinfo,
                              gimp_parasite_data (parasite),
                              gimp_parasite_data_size (parasite));
      gimp_parasite_free (parasite);
    }

  /* 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.
   */
  /* JSAMPLEs per row in image_buffer */
  rowstride = cinfo.input_components * cinfo.image_width;
  data = g_new (guchar, rowstride * gimp_tile_height ());

  /* fault if cinfo.next_scanline isn't initially a multiple of
   * gimp_tile_height */
  src = NULL;

  /*
   * sg - if we preview, we want this to happen in the background -- do
   * not duplicate code in the future; for now, it's OK
   */

  if (preview)
    {
      PreviewPersistent *pp = g_new (PreviewPersistent, 1);

      /* pass all the information we need */
      pp->cinfo       = cinfo;
      pp->tile_height = gimp_tile_height();
      pp->data        = data;
      pp->outfile     = outfile;
      pp->has_alpha   = has_alpha;
      pp->rowstride   = rowstride;
      pp->data        = data;
      pp->buffer      = buffer;
      pp->format      = format;
      pp->src         = NULL;
      pp->file_name   = filename;
      pp->abort_me    = FALSE;

      g_warn_if_fail (prev_p == NULL);
      prev_p = pp;

      pp->cinfo.err = jpeg_std_error(&(pp->jerr));
      pp->jerr.error_exit = background_error_exit;

      gtk_label_set_text (GTK_LABEL (preview_size),
                          _("Calculating file size..."));

      pp->source_id = g_idle_add ((GSourceFunc) background_jpeg_save, pp);

      /* background_jpeg_save() will cleanup as needed */
      return TRUE;
    }

  while (cinfo.next_scanline < cinfo.image_height)
    {
      if ((cinfo.next_scanline % gimp_tile_height ()) == 0)
        {
          yend = cinfo.next_scanline + gimp_tile_height ();
          yend = MIN (yend, cinfo.image_height);
          gegl_buffer_get (buffer,
                           GEGL_RECTANGLE (0, cinfo.next_scanline,
                                           cinfo.image_width,
                                           (yend - cinfo.next_scanline)),
                           1.0,
                           format,
                           data,
                           GEGL_AUTO_ROWSTRIDE,
                           GEGL_ABYSS_NONE);
          src = data;
        }

      jpeg_write_scanlines (&cinfo, (JSAMPARRAY) &src, 1);
      src += rowstride;

      if ((cinfo.next_scanline % 32) == 0)
        gimp_progress_update ((gdouble) cinfo.next_scanline /
                              (gdouble) cinfo.image_height);
    }

  /* 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);

  /* free the temporary buffer */
  g_free (data);

  /* And we're done! */
  gimp_progress_update (1.0);

  g_object_unref (buffer);

  return TRUE;
}
Ejemplo n.º 21
0
bool CCImage::_saveImageToJPG(const char * pszFilePath)
{
	bool bRet = false;
	do 
	{
		CC_BREAK_IF(NULL == pszFilePath);

		struct jpeg_compress_struct cinfo;
		struct jpeg_error_mgr jerr;
		FILE * outfile;                 /* target file */
		JSAMPROW row_pointer[1];        /* pointer to JSAMPLE row[s] */
		int     row_stride;          /* physical row width in image buffer */

		cinfo.err = jpeg_std_error(&jerr);
		/* Now we can initialize the JPEG compression object. */
		jpeg_create_compress(&cinfo);

		CC_BREAK_IF((outfile = fopen(pszFilePath, "wb")) == NULL);
		
		jpeg_stdio_dest(&cinfo, outfile);

		cinfo.image_width = m_nWidth;    /* image width and height, in pixels */
		cinfo.image_height = m_nHeight;
		cinfo.input_components = 3;       /* # of color components per pixel */
		cinfo.in_color_space = JCS_RGB;       /* colorspace of input image */

		jpeg_set_defaults(&cinfo);

		jpeg_start_compress(&cinfo, TRUE);

		row_stride = m_nWidth * 3; /* JSAMPLEs per row in image_buffer */

		if (m_bHasAlpha)
		{
			unsigned char *pTempData = new unsigned char[m_nWidth * m_nHeight * 3];
			if (NULL == pTempData)
			{
				jpeg_finish_compress(&cinfo);
				jpeg_destroy_compress(&cinfo);
				fclose(outfile);
				break;
			}

			for (int i = 0; i < m_nHeight; ++i)
			{
				for (int j = 0; j < m_nWidth; ++j)
				{
					pTempData[(i * m_nWidth + j) * 3] = m_pData[(i * m_nWidth + j) * 4];
					pTempData[(i * m_nWidth + j) * 3 + 1] = m_pData[(i * m_nWidth + j) * 4 + 1];
					pTempData[(i * m_nWidth + j) * 3 + 2] = m_pData[(i * m_nWidth + j) * 4 + 2];
				}
			}

			while (cinfo.next_scanline < cinfo.image_height) {
				row_pointer[0] = & pTempData[cinfo.next_scanline * row_stride];
				(void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
			}

			CC_SAFE_DELETE_ARRAY(pTempData);
		} 
		else
		{
			while (cinfo.next_scanline < cinfo.image_height) {
				row_pointer[0] = & m_pData[cinfo.next_scanline * row_stride];
				(void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
			}
		}

		jpeg_finish_compress(&cinfo);
		fclose(outfile);
		jpeg_destroy_compress(&cinfo);
		
		bRet = true;
	} while (0);
	return bRet;
}
Ejemplo n.º 22
0
/* 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;
		default:
			break;
	}

	// couldn't find a color converter
	if ( 0 == format )
		return false;

	const core::dimension2du 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);
}
Ejemplo n.º 23
0
void gdImageJpegCtx (gdImagePtr im, gdIOCtx * outfile, int quality)
{
	struct jpeg_compress_struct cinfo;
	struct jpeg_error_mgr jerr;
	int i, j, jidx;
	/* volatile so we can gdFree it on return from longjmp */
	volatile JSAMPROW row = 0;
	JSAMPROW rowptr[1];
	jmpbuf_wrapper jmpbufw;
	JDIMENSION nlines;
	char comment[255];

	memset (&cinfo, 0, sizeof (cinfo));
	memset (&jerr, 0, sizeof (jerr));

	cinfo.err = jpeg_std_error (&jerr);
	cinfo.client_data = &jmpbufw;
	if (setjmp (jmpbufw.jmpbuf) != 0) {
		/* we're here courtesy of longjmp */
		if (row) {
			gdFree (row);
		}
		return;
	}

	cinfo.err->error_exit = fatal_jpeg_error;

	jpeg_create_compress (&cinfo);

	cinfo.image_width = im->sx;
	cinfo.image_height = im->sy;
	cinfo.input_components = 3;	/* # of color components per pixel */
	cinfo.in_color_space = JCS_RGB;	/* colorspace of input image */
	jpeg_set_defaults (&cinfo);
	if (quality >= 0) {
		jpeg_set_quality (&cinfo, quality, TRUE);
	}

	/* If user requests interlace, translate that to progressive JPEG */
	if (gdImageGetInterlaced (im)) {
		jpeg_simple_progression (&cinfo);
	}

	jpeg_gdIOCtx_dest (&cinfo, outfile);

	row = (JSAMPROW) safe_emalloc(cinfo.image_width * cinfo.input_components, sizeof(JSAMPLE), 0);
	memset(row, 0, cinfo.image_width * cinfo.input_components * sizeof(JSAMPLE));
	rowptr[0] = row;

	jpeg_start_compress (&cinfo, TRUE);

	if (quality >= 0) {
		snprintf(comment, sizeof(comment)-1, "CREATOR: gd-jpeg v%s (using IJG JPEG v%d), quality = %d\n", GD_JPEG_VERSION, JPEG_LIB_VERSION, quality);
	} else {
		snprintf(comment, sizeof(comment)-1, "CREATOR: gd-jpeg v%s (using IJG JPEG v%d), default quality\n", GD_JPEG_VERSION, JPEG_LIB_VERSION);
	}
	jpeg_write_marker (&cinfo, JPEG_COM, (unsigned char *) comment, (unsigned int) strlen (comment));
	if (im->trueColor) {

#if BITS_IN_JSAMPLE == 12
		php_gd_error("gd-jpeg: error: jpeg library was compiled for 12-bit precision. This is mostly useless, because JPEGs on the web are 8-bit and such versions of the jpeg library won't read or write them. GD doesn't support these unusual images. Edit your jmorecfg.h file to specify the correct precision and completely 'make clean' and 'make install' libjpeg again. Sorry");
		goto error;
#endif /* BITS_IN_JSAMPLE == 12 */

		for (i = 0; i < im->sy; i++) {
			for (jidx = 0, j = 0; j < im->sx; j++) {
				int val = im->tpixels[i][j];

				row[jidx++] = gdTrueColorGetRed (val);
				row[jidx++] = gdTrueColorGetGreen (val);
				row[jidx++] = gdTrueColorGetBlue (val);
			}

			nlines = jpeg_write_scanlines (&cinfo, rowptr, 1);
			if (nlines != 1) {
				php_gd_error_ex(E_WARNING, "gd_jpeg: warning: jpeg_write_scanlines returns %u -- expected 1", nlines);
			}
		}
	} else {
		for (i = 0; i < im->sy; i++) {
			for (jidx = 0, j = 0; j < im->sx; j++) {
				int idx = im->pixels[i][j];

				/* NB: Although gd RGB values are ints, their max value is
				 * 255 (see the documentation for gdImageColorAllocate())
				 * -- perfect for 8-bit JPEG encoding (which is the norm)
				 */
#if BITS_IN_JSAMPLE == 8
				row[jidx++] = im->red[idx];
				row[jidx++] = im->green[idx];
				row[jidx++] = im->blue[idx];
#elif BITS_IN_JSAMPLE == 12
				row[jidx++] = im->red[idx] << 4;
				row[jidx++] = im->green[idx] << 4;
				row[jidx++] = im->blue[idx] << 4;
#else
#error IJG JPEG library BITS_IN_JSAMPLE value must be 8 or 12
#endif
			}

			nlines = jpeg_write_scanlines (&cinfo, rowptr, 1);
			if (nlines != 1) {
				php_gd_error_ex(E_WARNING, "gd_jpeg: warning: jpeg_write_scanlines returns %u -- expected 1", nlines);
			}
		}
	}

	jpeg_finish_compress (&cinfo);
	jpeg_destroy_compress (&cinfo);
	gdFree (row);
}
//**************************************************************************
bool JPEGCompression::compress(unsigned char * indata,
                const unsigned long int & width, 
                const unsigned long int & height) throw()
{
  JSAMPROW row_pointer[1];
  int row_stride(0);
  struct jpeg_error_mgr jerr;
  try
  {
    //create the jpeg compression
    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_compress(&cinfo);
    
    //set up the memory manager
    cinfo.dest = &pub;
    
    if (buffer)
    {
      delete [] buffer;
      buffer = 0;
    }
    
    //create the buffer
    if (!(buffer = new (std::nothrow) JOCTET[width*height*3]))
      throw std::bad_alloc();

    
    cinfo.image_width = width;
    cinfo.image_height = height;
    cinfo.input_components = 3;
    cinfo.in_color_space = JCS_RGB;
    
    //set the compression defaults
    jpeg_set_defaults(&cinfo);
    jpeg_set_quality(&cinfo, quality, TRUE);
    
    pub.next_output_byte = buffer;
    pub.free_in_buffer = width*height*3;

    //start the compression
    jpeg_start_compress(&cinfo, TRUE);
    
    row_stride = width*3;
    
    //do the deal
    while (cinfo.next_scanline < cinfo.image_height)
    {
      row_pointer[0] = &indata[cinfo.next_scanline*row_stride];
      jpeg_write_scanlines(&cinfo, row_pointer, 1);
    }
      
    jpeg_finish_compress(&cinfo);
    
    buffer_size = width*height*3 - pub.free_in_buffer;
    //release the cinfo stuff
    jpeg_destroy_compress(&cinfo);
    
    return true;
 
  }
  catch(...)
  {
    delete [] buffer;
    return false;
  } 

}
Ejemplo n.º 25
0
int
main( int argc, char **argv ) {	
	irz_config_t *config;
	char *temp_out = tmpnam(NULL);

	FILE *in_fh = NULL;
	FILE *out_fh = NULL;
	
	config = parse_options(argc, argv);
	if( config == NULL ) {
		return EXIT_FAILURE+9;
	}
	
	config->logger = irz_logger_stdio;
	config->logger_cfg = stdout;
	
	in_fh = fopen(config->in_file,"r");
	if( ! in_fh ) {
		char buf[200];
		strerror_r(errno, buf, sizeof(buf));
		irz_log(config, IRZ_ERROR, "Cannot open in-file '%s': %s", config->in_file, buf);
		return EXIT_FAILURE+11;
	}
	
	struct jpeg_compress_struct out_cinfo;
	struct jpeg_decompress_struct in_dinfo;
	struct jpeg_error_mgr       jerr;		
	
	setup_in(&in_dinfo, &jerr, in_fh);

	if( config->debug ) {
		irz_log(config, IRZ_DEBUG, "Image Width: %ipx\n", (int)in_dinfo.image_width);
	        irz_log(config, IRZ_DEBUG, "Image Height: %ipx\n", (int)in_dinfo.image_height);
	        irz_log(config, IRZ_DEBUG, "Tmp Loc: %s\n", temp_out);
	}

	if ( config->out_width != 0 ) {
        	if ( (int)in_dinfo.image_width < (int)config->out_width ) {
            		irz_log(config, IRZ_WARN, "specified width is larger than original image, reducing to %ipx.\n", (int)in_dinfo.image_width);
            		config->out_width = (double)in_dinfo.image_width;
        	}
    	}

    	if ( config->out_height != 0 ) {
        	if ( (int)in_dinfo.image_height < (int)config->out_height ) {
            		irz_log(config, IRZ_WARN, "specified height is larger than original image, reducing to %ipx.\n", (int)in_dinfo.image_height);
            		config->out_height = (double)in_dinfo.image_height;
        	}
    	}
	
	/* Auto-scale width or height if either was not specified */
	if( config->mode == MODE_SCALE ) {		
		if( config->out_height == 0 ) {
			double ratio = (double)config->out_width / (double)in_dinfo.image_width;
			config->out_height = ((double)in_dinfo.image_height * ratio);
		}
		else if( config->out_width == 0 ) {
			double ratio = (double)config->out_height / (double)in_dinfo.image_height;
			config->out_width = ((double)in_dinfo.image_width * ratio);
		}
	}
    	else if( config->mode == MODE_SCALEASPECT ) {
        	double ratio;
        	unsigned int new_width = in_dinfo.image_width;
        	unsigned int new_height = in_dinfo.image_height;

        	if (in_dinfo.image_width > in_dinfo.image_height) {
            		ratio = ( (double)in_dinfo.image_width / (double)in_dinfo.image_height ) ;
        	}
		else {
            		ratio = ( (double)in_dinfo.image_height / (double)in_dinfo.image_width ) ;
        	}

		if( config->debug ) {
        		irz_log(config, IRZ_DEBUG, "Ratio: %f\n", ratio);
		}

        	if (in_dinfo.image_width < in_dinfo.image_height) {
            		if (new_width > config->out_width) {
                		new_width = config->out_width;
                		new_height = ( new_height - ( ( (double)in_dinfo.image_width - (double)config->out_width) * ratio ) );

				if( config->debug ) {
             	   			irz_log(config, IRZ_DEBUG, "aspect changed: width: %u / height: %u\n", new_width, new_height );
				}
            		}

            		if (new_height > config->out_height) {
                		new_width = ( new_width - ( ( (double)new_height - (double)config->out_height) / ratio ) );
                		new_height = config->out_height;

				if( config->debug ) {
             	   			irz_log(config, IRZ_DEBUG, "aspect changed: width: %u / height: %u\n", new_width, new_height );
				}
            		}
        	}
		else {
            		if (new_width > config->out_width) {
                		new_width = config->out_width;
                		new_height = ( new_height - ( ( (double)in_dinfo.image_width - (double)config->out_width) / ratio ) );

				if( config->debug ) {
             	   			irz_log(config, IRZ_DEBUG, "aspect changed: width: %u / height: %u\n", new_width, new_height );
				}
            		}

            		if (new_height > config->out_height) {
                		new_width = ( new_width - ( ( (double)new_height - (double)config->out_height) * ratio ) );
                		new_height = config->out_height;

				if( config->debug ) {
              	  			irz_log(config, IRZ_DEBUG, "aspect changed: width: %u / height: %u\n", new_width, new_height );
				}
            		}
        	}

        	config->out_width = new_width;
        	config->out_height = new_height;
	}
	else if( config->mode == MODE_SCALEFIT ) {
		if( in_dinfo.image_width > config->out_width ) {
			double ratio = (double)config->out_width / (double)in_dinfo.image_width;
			config->out_height = ((double)in_dinfo.image_height * ratio);
			config->out_width = ((double)in_dinfo.image_width * ratio);
		}
		if( in_dinfo.image_height > config->out_height ) {
			double ratio = (double)config->out_height / (double)in_dinfo.image_height;
			config->out_height = ((double)in_dinfo.image_height * ratio);
			config->out_width = ((double)in_dinfo.image_width * ratio);
		}
	}
	else if( config->mode == MODE_CROPMANUAL ) {
		if( (config->crop_x2 - config->crop_x) < 10 ) {
			irz_log(config, IRZ_ERROR, "source crop width too small\n");
			return EXIT_FAILURE+10;
		}
		else if( (config->crop_y2 - config->crop_y) < 10 ) {
			irz_log(config, IRZ_ERROR, "source crop height too small\n");
			return EXIT_FAILURE+10;
		}
		else if( config->crop_x2 > in_dinfo.image_width || config->crop_y2 > in_dinfo.image_height ) {
			irz_log(config, IRZ_ERROR, "source crop area outside of image dimension\n");
			return EXIT_FAILURE+10;
		}
	}

	if( config->debug ) {
        	irz_log(config, IRZ_DEBUG, "Out Width: %upx\n", config->out_width);
        	irz_log(config, IRZ_DEBUG, "Out Height: %upx\n", config->out_height);
	}
	
	out_fh = fopen(temp_out,"wb");
	if( ! out_fh ) {
		char buf[200];
		strerror_r(errno, buf, sizeof(buf));
		irz_log(config, IRZ_ERROR, "Cannot open output file '%s': %s", temp_out, buf);
		return EXIT_FAILURE+12;
	}

	setup_out(&out_cinfo, &jerr, out_fh, config->out_width, config->out_height, config->out_quality);

	int row_stride = in_dinfo.output_width * in_dinfo.output_components;
	JSAMPARRAY buffer;
	buffer = (in_dinfo.mem->alloc_sarray)((j_common_ptr) &in_dinfo, JPOOL_IMAGE, row_stride, 1);
		
	do_resize(&out_cinfo, &in_dinfo, config);

	jpeg_finish_decompress(&in_dinfo);
	jpeg_destroy_decompress(&in_dinfo);
	
	jpeg_finish_compress(&out_cinfo);
	jpeg_destroy_compress(&out_cinfo);
	
	fclose(in_fh);
	fclose(out_fh);
	
	/* XXX: needs to be refactored as rename() won't work across filesystems
	 * temp_out should be in the same directory as out_file */
	if( rename( temp_out, config->out_file ) != 0 ) {
		char buf[200];
		strerror_r(errno, buf, sizeof(buf));
		irz_log(config, IRZ_ERROR, "Cannot rename temporary file '%s' to real file '%s': %s", temp_out, config->out_file, buf);
		return EXIT_FAILURE+13;
	}
	
	free(config);	
	return EXIT_SUCCESS;
}
Ejemplo n.º 26
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;
	struct jpeg_error_mgr       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);
	cinfo.err->error_exit     = R_JPGErrorExit;
	cinfo.err->output_message = R_JPGOutputMessage;

	/* 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;
}
Ejemplo n.º 27
0
BOOL JpegFile::RGBToJpegFile(CString fileName,
              BYTE *dataBuf,
              UINT widthPix,
              UINT height,
              BOOL color,
              int quality)
{
  if (dataBuf==NULL)
    return FALSE;
  if (widthPix==0)
    return FALSE;
  if (height==0)
    return FALSE;

  LPBYTE tmp;
  if (!color) {
    tmp = (BYTE*)new BYTE[widthPix*height];
    if (tmp==NULL) {
      AfxMessageBox("Memory error");
      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 (!color) {
      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[250];
    sprintf(buf, "JpegFile :\nCan't open %s\n", fileName);
    AfxMessageBox(buf);
    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 (color) {
    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 (color) {
      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 (!color)
    delete [] tmp;
  /* And we're done! */

  return TRUE;
}
Ejemplo n.º 28
0
int CScreen::Save(void)
{
	static int iIndex = 0;
	char sFileName[STD_BUF];

	char *sFileExt =
	#ifdef HAVE_JPEG
		"jpg";
	#else
		"bmp";
	#endif

	do
	{
		iIndex++;
		snprintf(sFileName, STD_BUF, "screenshot/screenshot_%04d.%s", iIndex, sFileExt);
	} while(!access(sFileName, 0));


#ifdef HAVE_JPEG
	struct jpeg_compress_struct info;
	struct jpeg_error_mgr jerr;
	FILE* FP_ptr_OutFile;
	JSAMPROW iRow_ptr[1];
	int iRow_Stride;
	int iDeleteBuffer = 0;
	unsigned char* ucImageBuffer = NULL;
	SDL_Surface* SS_p_nSurface;

	info.err = jpeg_std_error(&jerr);
	jpeg_create_compress(&info);

    if ((FP_ptr_OutFile = fopen(sFileName, "wb")) == NULL)
	{
		std::cout << "Impossível abrir o arquivo de destino: " << sFileName << std::endl;
		return -1;
    }

	jpeg_stdio_dest(&info, FP_ptr_OutFile);

	info.image_width = SS_p_Screen->w;
	info.image_height = SS_p_Screen->h;
	info.input_components = 3;
	info.in_color_space = JCS_RGB;


	#if SDL_BYTEORDER == SDL_BIG_ENDIAN
		SS_p_nSurface = SDL_CreateRGBSurface(SDL_SWSURFACE, SS_p_Screen->w, SS_p_Screen->h,
											   24, 0xff000000, 0x00ff0000, 0x0000ff00, 0x00000000);
	#else
		SS_p_nSurface = SDL_CreateRGBSurface(SDL_SWSURFACE, SS_p_Screen->w, SS_p_Screen->h,
											   24, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000);
	#endif

	if(SS_p_nSurface == NULL)
	{
		std::cout << "Erro ao alocar superfície para \'screenshot\'" << std::endl;
		return -1;
	}

	SDL_BlitSurface(SS_p_Screen, NULL, SS_p_nSurface, NULL);
	SS_p_Screen = SS_p_nSurface;
	iDeleteBuffer = 1;

	if(SDL_MUSTLOCK(SS_p_Screen))
	SDL_LockSurface(SS_p_Screen);

	ucImageBuffer = (unsigned char *)SS_p_Screen->pixels;

	jpeg_set_defaults(&info);

	jpeg_set_quality(&info, JPEG_QUALITY_DEFAULT, TRUE);
	jpeg_start_compress(&info, TRUE);

	iRow_Stride = SS_p_Screen->pitch;

	while (info.next_scanline < info.image_height)
	{
		iRow_ptr[0] = &ucImageBuffer[info.next_scanline * iRow_Stride];
		(void) jpeg_write_scanlines(&info, iRow_ptr, 1);
    }

	jpeg_finish_compress(&info);
	fclose(FP_ptr_OutFile);

	jpeg_destroy_compress(&info);

	if(SDL_MUSTLOCK(SS_p_Screen))
	SDL_UnlockSurface(SS_p_Screen);

	if(iDeleteBuffer)
	SDL_FreeSurface(SS_p_Screen);

	return 0;
#else // Caso contrario não tenha a bibliote JPEG no sistema salva como BMP

	SDL_SaveBMP(SS_p_Screen, sFileName);
	return 0;
#endif // Fim de HAVE_JPEG
}
Ejemplo n.º 29
0
LibJPEG::~LibJPEG()
{
	jpeg_destroy_compress(&m_cinfo);

	jpeg_destroy_decompress(&m_dinfo);
}
BOOL LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time )
{
	llassert_always(raw_image);
	
	resetLastError();

	switch( raw_image->getComponents() )
	{
	case 1:
	case 3:
		break;
	default:
		setLastError("Unable to encode a JPEG image that doesn't have 1 or 3 components.");
		return FALSE;
	}

	setSize(raw_image->getWidth(), raw_image->getHeight(), raw_image->getComponents());

	// Allocate a temporary buffer big enough to hold the entire compressed image (and then some)
	// (Note: we make it bigger in emptyOutputBuffer() if we need to)
	delete[] mOutputBuffer;
	mOutputBufferSize = getWidth() * getHeight() * getComponents() + 1024;
	mOutputBuffer = new U8[ mOutputBufferSize ];
	if(!mOutputBuffer)
	{
		llwarns << "could not allocate memory for image encoding, size:" << mOutputBufferSize << llendl;
		return FALSE;
	}

	const U8* raw_image_data = NULL;
	S32 row_stride = 0;

	////////////////////////////////////////
	// Step 1: allocate and initialize JPEG compression object

	// This struct contains the JPEG compression parameters and pointers to
	// working space (which is allocated as needed by the JPEG library).
	struct jpeg_compress_struct cinfo;
	cinfo.client_data = this;

	// 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.
	struct jpeg_error_mgr jerr;
	cinfo.err = jpeg_std_error(&jerr);

	// Customize with our own callbacks
	jerr.error_exit =		&LLImageJPEG::errorExit;			// Error exit handler: does not return to caller
	jerr.emit_message =		&LLImageJPEG::errorEmitMessage;		// Conditionally emit a trace or warning message
	jerr.output_message =	&LLImageJPEG::errorOutputMessage;	// Routine that actually outputs a trace or error message

	//
	//try/catch will crash on Mac and Linux if LLImageJPEG::errorExit throws an error
	//so as instead, we use setjmp/longjmp to avoid this crash, which is the best we can get. --bao 
	//
	if( setjmp(sSetjmpBuffer) ) 
	{
		// 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);
		delete[] mOutputBuffer;
		mOutputBuffer = NULL;
		mOutputBufferSize = 0;
		return FALSE;
	}

	try
	{

		// Now we can initialize the JPEG compression object.
		jpeg_create_compress(&cinfo);

		////////////////////////////////////////
		// Step 2: specify data destination
		// (code is a modified form of jpeg_stdio_dest() )
		if( cinfo.dest == NULL)
		{	
			cinfo.dest = (struct jpeg_destination_mgr *)
				(*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT,
				sizeof(struct jpeg_destination_mgr));
		}
		cinfo.dest->next_output_byte =		mOutputBuffer;		// => next byte to write in buffer
		cinfo.dest->free_in_buffer =		mOutputBufferSize;	// # of byte spaces remaining in buffer
		cinfo.dest->init_destination =		&LLImageJPEG::encodeInitDestination;
		cinfo.dest->empty_output_buffer =	&LLImageJPEG::encodeEmptyOutputBuffer;
		cinfo.dest->term_destination =		&LLImageJPEG::encodeTermDestination;

		////////////////////////////////////////
		// 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 = getWidth(); 	// image width and height, in pixels 
		cinfo.image_height = getHeight();

		switch( getComponents() )
		{
		case 1:
			cinfo.input_components = 1;		// # of color components per pixel
			cinfo.in_color_space = JCS_GRAYSCALE; // colorspace of input image
			break;
		case 3:
			cinfo.input_components = 3;		// # of color components per pixel
			cinfo.in_color_space = JCS_RGB; // colorspace of input image
			break;
		default:
			setLastError("Unable to encode a JPEG image that doesn't have 1 or 3 components.");
			return FALSE;
		}

		// 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.
		jpeg_set_quality(&cinfo, mEncodeQuality, 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 = getWidth() * getComponents();	// JSAMPLEs per row in image_buffer

		// NOTE: For compatibility with LLImage, we need to invert the rows.
		raw_image_data = raw_image->getData();
		
		const U8* last_row_data = raw_image_data + (getHeight()-1) * row_stride;

		JSAMPROW row_pointer[1];				// pointer to JSAMPLE row[s]
		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.

			//Ugly const uncast here (jpeg_write_scanlines should take a const* but doesn't)
			//row_pointer[0] = (JSAMPROW)(raw_image_data + (cinfo.next_scanline * row_stride));
			row_pointer[0] = (JSAMPROW)(last_row_data - (cinfo.next_scanline * row_stride));

			jpeg_write_scanlines(&cinfo, row_pointer, 1);
		}

		////////////////////////////////////////
		//   Step 6: Finish compression 
		jpeg_finish_compress(&cinfo);

		// After finish_compress, we can release the temp output buffer. 
		delete[] mOutputBuffer;
		mOutputBuffer = NULL;
		mOutputBufferSize = 0;

		////////////////////////////////////////
		//   Step 7: release JPEG compression object 
		jpeg_destroy_compress(&cinfo);
	}

	catch(int)
	{
		jpeg_destroy_compress(&cinfo);
		delete[] mOutputBuffer;
		mOutputBuffer = NULL;
		mOutputBufferSize = 0;
		return FALSE;
	}

	return TRUE;
}