コード例 #1
0
static uint32_t jpeg_write(uint8_t * name, uint8_t * buffer)
{
    FILE *outfile;
    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr jerr;
    JSAMPROW row_pointer[1];
    int row_stride;

    if ( !buffer ) return 1; 
    if ( (outfile = fopen(name, "wb") ) == NULL ) {
        mp_msg(MSGT_VO, MSGL_ERR, "\n%s: %s\n", info.short_name,
                MSGTR_VO_CantCreateFile);
        mp_msg(MSGT_VO, MSGL_ERR, "%s: %s: %s\n",
                info.short_name, MSGTR_VO_GenericError,
                strerror(errno) );
        exit_player(MSGTR_Exit_error);
    }
 
    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_compress(&cinfo);
    jpeg_stdio_dest(&cinfo, outfile);
    
    cinfo.image_width = image_width;
    cinfo.image_height = image_height;
    cinfo.input_components = 3;
    cinfo.in_color_space = JCS_RGB;

    jpeg_set_defaults(&cinfo);
    /* Important: Header info must be set AFTER jpeg_set_defaults() */
    cinfo.write_JFIF_header = TRUE;
    cinfo.JFIF_major_version = 1;
    cinfo.JFIF_minor_version = 2;
    cinfo.density_unit = 1; /* 0=unknown, 1=dpi, 2=dpcm */
    /* Image DPI is determined by Y_density, so we leave that at
       jpeg_dpi if possible and crunch X_density instead (PAR > 1) */
    cinfo.X_density = jpeg_dpi*image_width/image_d_width;
    cinfo.Y_density = jpeg_dpi*image_height/image_d_height;
    cinfo.write_Adobe_marker = TRUE;

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

    if ( jpeg_progressive_mode ) {
        jpeg_simple_progression(&cinfo);
    }
    
    jpeg_start_compress(&cinfo, TRUE);
    
    row_stride = image_width * 3;
    while (cinfo.next_scanline < cinfo.image_height) {
        row_pointer[0] = &buffer[cinfo.next_scanline * row_stride];
        (void)jpeg_write_scanlines(&cinfo, row_pointer,1);
    }

    jpeg_finish_compress(&cinfo);
    fclose(outfile);
    jpeg_destroy_compress(&cinfo);
    
    return 0;
}
コード例 #2
0
ファイル: CCImage.cpp プロジェクト: JayKingston/StupidTest
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;
}
コード例 #3
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;
}
コード例 #4
0
ファイル: gd_jpeg.c プロジェクト: 0/php-src
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);
}
コード例 #5
0
//**************************************************************************
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;
  } 

}
コード例 #6
0
ファイル: gth-image-saver-jpeg.c プロジェクト: KapTmaN/gthumb
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;
}
コード例 #7
0
ファイル: jpeg-save.c プロジェクト: frne/gimp
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;
}
コード例 #8
0
ファイル: mgImageUtil.cpp プロジェクト: duaneking/SeaOfMemes
//--------------------------------------------------------------
// save BGR image data to a jpg file
void mgWriteBGRtoJPGFile(
  const char* fileName,
  int width,
  int height,
  const BYTE* pData)
{
  FILE* pOutFile = mgOSFileOpen(fileName, "wb");
  if (pOutFile == NULL)
    throw new mgErrorMsg("imgBadOpen", "filename", "%s", (const char*) fileName);

  struct jpeg_error_mgr compErr;    // error handler 
  struct jpeg_compress_struct compInfo;
  compInfo.err = jpeg_std_error(&compErr);  // standard error handler
  compErr.error_exit = ImageErrorExit;
  compErr.output_message = ImageOutputMessage;

  // allocate and initialize JPEG compression object 
  jpeg_create_compress(&compInfo);
  jpeg_stdio_dest(&compInfo, pOutFile);

  compInfo.in_color_space = JCS_RGB;
  jpeg_set_defaults(&compInfo);
  jpeg_set_quality(&compInfo, 99, true);

  compInfo.in_color_space = JCS_RGB;
  compInfo.input_components = 3;
  compInfo.data_precision = 8;
  compInfo.image_width = width;
  compInfo.image_height = height;
  jpeg_default_colorspace(&compInfo);

  // Start compressor, write complete file 
  jpeg_start_compress(&compInfo, TRUE);

  // read scanlines from the screen, top to bottom
  int sourceSpan = width*3;
  sourceSpan = 4*((sourceSpan+3)/4);

  BYTE* line = new BYTE[width*3];
  const BYTE* pSource = pData;
  for (int i = 0; i < height; i++)
  {
    int targetOffset = 0;
    int sourceOffset = 0;
    for (int j = 0; j < width; j++)
    {
      line[targetOffset++] = pSource[sourceOffset+2];
      line[targetOffset++] = pSource[sourceOffset+1];
      line[targetOffset++] = pSource[sourceOffset+0];
      sourceOffset += 3;
    }
    jpeg_write_scanlines(&compInfo, &line, 1);
    pSource += sourceSpan;
  }
  delete line;

  jpeg_finish_compress(&compInfo);
  jpeg_destroy_compress(&compInfo);

  fclose(pOutFile);
}
コード例 #9
0
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;
}
コード例 #10
0
ファイル: gl_rmisc.c プロジェクト: Jaegermeiste/quake2_322
/* 
================== 
GL_ScreenShot_JPG
By Robert 'Heffo' Heffernan
================== 
*/
void GL_ScreenShot_JPG_f (void)
{
	struct jpeg_compress_struct		cinfo;
	struct jpeg_error_mgr			jerr;
	byte							*rgbdata;
	JSAMPROW						s[1];
	FILE							*file;
	char							picname[80], checkname[MAX_OSPATH];
	int								i, offset;

	// Create the scrnshots directory if it doesn't exist
	Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot", ri.FS_Gamedir());
	Sys_Mkdir (checkname);

	// Find a file name to save it to 
	strcpy(picname,"quake00.jpg");

	for (i=0 ; i<=99 ; i++) 
	{ 
		picname[5] = i/10 + '0'; 
		picname[6] = i%10 + '0'; 
		Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot/%s", ri.FS_Gamedir(), picname);
		file = fopen (checkname, "rb");
		if (!file)
			break;	// file doesn't exist
		fclose (file);
	} 
	if (i==100) 
	{
		ri.Con_Printf (PRINT_ALL, "SCR_JPGScreenShot_f: Couldn't create a file\n"); 
		return;
 	}

	// Open the file for Binary Output
	file = fopen(checkname, "wb");
	if(!file)
	{
		ri.Con_Printf (PRINT_ALL, "GL_ScreenShotJPG_f: Couldn't create a file\n"); 
		return;
 	}

	// Allocate room for a copy of the framebuffer
	rgbdata = malloc(vid.width * vid.height * 3);
	if(!rgbdata)
	{
		fclose(file);
		return;
	}

	// Read the framebuffer into our storage
	qglReadPixels(0, 0, vid.width, vid.height, GL_RGB, GL_UNSIGNED_BYTE, rgbdata);

	// Initialise the JPEG compression object
	cinfo.err = jpeg_std_error(&jerr);
	jpeg_create_compress(&cinfo);
	jpeg_stdio_dest(&cinfo, file);

	// Setup JPEG Parameters
	cinfo.image_width = vid.width;
	cinfo.image_height = vid.height;
	cinfo.in_color_space = JCS_RGB;
	cinfo.input_components = 3;
	jpeg_set_defaults(&cinfo);
	if((r_jpeg_quality->value >= 101) || (r_jpeg_quality->value <= 0))
		ri.Cvar_Set("r_jpeg_quality", "85");
	jpeg_set_quality(&cinfo, r_jpeg_quality->value, 1);

	// Start Compression
	jpeg_start_compress(&cinfo, 1);

	// Feed Scanline data
	offset = (cinfo.image_width * cinfo.image_height * 3) - (cinfo.image_width * 3);
	while(cinfo.next_scanline < cinfo.image_height)
	{
		s[0] = &rgbdata[offset - (cinfo.next_scanline * (cinfo.image_width * 3))];
		jpeg_write_scanlines(&cinfo, s, 1);
	}

	// Finish Compression
	jpeg_finish_compress(&cinfo);

	// Destroy JPEG object
	jpeg_destroy_compress(&cinfo);

	// Close File
	fclose(file);

	// Free Temp Framebuffer
	free(rgbdata);

	// Done!
	ri.Con_Printf (PRINT_ALL, "Wrote %s\n", picname);
}
コード例 #11
0
ファイル: jpeg.cpp プロジェクト: Vezart/Mjolnir
/*---------------------------------------------------------------------------*/
void JPEG_write_data(FILE *fd, int pixtype, int xdim, int ydim, char *data)
{
   struct jpeg_compress_struct cinfo;
   struct jpeg_error_mgr jerr;
   int i, quality = 95, smoothness = 0, index = 0;
   // JSAMPARRAY colormap;
   JSAMPARRAY buffer;
   JSAMPROW ptr;

   /* Initialize the JPEG compression object with default error handling. */
   cinfo.err = jpeg_std_error(&jerr);
   jpeg_create_compress(&cinfo);

   /* Initialize JPEG parameters which may be overridden later */
   cinfo.in_color_space = JCS_RGB;
   jpeg_set_defaults(&cinfo);

   /* Set up color map */
   // colormap = (*cinfo.mem->alloc_sarray) ((j_common_ptr) & cinfo, JPOOL_IMAGE, 256, 3);

   /* Obtain file size and colorspace */
   if (pixtype == JPEG_RGB)
   {
      cinfo.input_components = 3;
      cinfo.in_color_space = JCS_RGB;
   }
   else
   {
      cinfo.input_components = 1;
      cinfo.in_color_space = JCS_GRAYSCALE;
   }
   cinfo.image_width = xdim;
   cinfo.image_height = ydim;
   cinfo.data_precision = BITS_IN_JSAMPLE;
   buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) & cinfo, JPOOL_IMAGE,
      (JDIMENSION) (cinfo.image_width * cinfo.input_components), (JDIMENSION) 1);

   /* Fix colorspace-dependent defaults */
   jpeg_default_colorspace(&cinfo);

   /* Customize parameters */
   cinfo.smoothing_factor = smoothness;
   jpeg_set_quality(&cinfo, quality, TRUE);

   /* Specify data destination for compression */
   jpeg_stdio_dest(&cinfo, fd);

   /* Start compressor */
   jpeg_start_compress(&cinfo, TRUE);

   /* Process JPEG scanlines */
   while (cinfo.next_scanline < cinfo.image_height)
   {
      ptr = buffer[0];
      for (i = 0; i < (int) cinfo.image_width; i++)
      {
	 if (pixtype == JPEG_RGB)
	 {
	    *ptr++ = (unsigned char) data[index++];
	    *ptr++ = (unsigned char) data[index++];
	    *ptr++ = (unsigned char) data[index++];
	 }
	 else
	    *ptr++ = (unsigned char) data[index++];
      }
      (void) jpeg_write_scanlines(&cinfo, buffer, 1);
   }

   /* Finish compression and release memory */
   jpeg_finish_compress(&cinfo);
   jpeg_destroy_compress(&cinfo);
}
コード例 #12
0
ファイル: ImageEncoderJPEG.cpp プロジェクト: irov/Mengine
	size_t ImageEncoderJPEG::encode( const void * _buffer, size_t _size, const CodecDataInfo* _dataInfo )
	{
		(void)_size;

		const ImageCodecDataInfo* dataInfo = static_cast<const ImageCodecDataInfo*>( _dataInfo );

		EncoderJPEGErrorManager errorMgr;

		errorMgr.pub.error_exit = &s_jpegErrorExit;
		errorMgr.pub.output_message = &s_jpegOutputMessage;

		if( setjmp( errorMgr.setjmp_buffer ) )
		{
			// If we get here, the JPEG code has signaled an error.
			// We need to clean up the JPEG object and return.
			
			return 0;
		}
		
		struct jpeg_compress_struct cinfo = {0};
		cinfo.err = jpeg_std_error(&errorMgr.pub);
		cinfo.client_data = m_serviceProvider;

		jpeg_create_compress( &cinfo );

		jpeg_menge_dst( &cinfo, m_stream.get() );

		cinfo.image_width = (JDIMENSION)dataInfo->width;
		cinfo.image_height = (JDIMENSION)dataInfo->height;
		cinfo.input_components = dataInfo->channels;

		cinfo.in_color_space = JCS_RGB;
				
		//int pixel_depth = 8;

		jpeg_set_defaults( &cinfo );
		jpeg_set_quality( &cinfo, dataInfo->quality, TRUE );

		jpeg_start_compress( &cinfo, TRUE );

        JSAMPROW jpeg_buffer = (JSAMPROW)_buffer;

		size_t pitch = m_options.pitch;

		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.
			row_pointer[0] = jpeg_buffer + cinfo.next_scanline * pitch;
			(void) jpeg_write_scanlines( &cinfo, row_pointer, 1);
		}

		// Step 6: Finish compression

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

		return pitch * dataInfo->height;
	}
コード例 #13
0
ファイル: jpgInput.c プロジェクト: AmmarkoV/AmmarServer
/**
 * 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)
{
    if ( (filename==0) && ( (mem==0) || (mem_size==0) ) ) { fprintf(stderr,"WriteJPEGInternal called with null filename and this is not a memory write call\n"); return 0;}
    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;
}
コード例 #14
0
ファイル: avin.c プロジェクト: xieran1988/simple
void poll_frame_and_output_jpg(AVFrame *frm, AVStream *st, char *path) {
	//H264Context *h = st->codec->priv_data;
	int n = 0;
	for (n = 0; n < 1060; n++) {
		AVPacket pkt;
		int i = av_read_frame(ifc, &pkt);
//		printf("read %d, pkt: size=%d index=%d\n", 
//				i, pkt.size, pkt.stream_index);
		if (pkt.stream_index != st->index)
			continue;
		int got_pic; 
		i = avcodec_decode_video2(st->codec, frm, &got_pic, &pkt);
		printf("decode %d, w=%d h=%d\n", i, frm->width, frm->height);
		if (got_pic && frm->key_frame)
			break;
	}

	// YUV420P
	printf("format=%d\n", frm->format);
	printf("key_frame=%d\n", frm->key_frame);
	printf("linesize=%d,%d,%d\n", frm->linesize[0], frm->linesize[1], frm->linesize[2]);

	struct jpeg_compress_struct cinfo;
	struct jpeg_error_mgr jerr;

	printf("write to %s\n", path);
	FILE *outfile = fopen(path, "wb+");
	cinfo.err = jpeg_std_error(&jerr);
	jpeg_create_compress(&cinfo);
	jpeg_stdio_dest(&cinfo, outfile);
	cinfo.image_width = frm->width; 
	cinfo.image_height = frm->height;
	cinfo.input_components = 3;        
	cinfo.in_color_space = JCS_YCbCr;
	jpeg_set_defaults(&cinfo);
	jpeg_set_quality(&cinfo, 90, TRUE);
	cinfo.raw_data_in = TRUE;
	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; 
	printf("dct_size=%d\n", DCTSIZE);
	jpeg_start_compress(&cinfo, TRUE);
	int i, j;
	JSAMPROW y[16], cb[16], cr[16];
	JSAMPARRAY data[3];
	data[0] = y;
	data[2] = cb;
	data[1] = cr;
	for (j = 0; j < cinfo.image_height; j += 16) {
		for (i = 0; i < 16; i++) {
			y[i] = frm->data[0] + frm->linesize[0]*(i+j);
			cr[i/2] = frm->data[1] + frm->linesize[1]*((i+j)/2);
			cb[i/2] = frm->data[2] + frm->linesize[2]*((i+j)/2);
		}
		jpeg_write_raw_data(&cinfo, data, 16);
	}
	jpeg_finish_compress(&cinfo);
	fclose(outfile);
	jpeg_destroy_compress(&cinfo);
}
コード例 #15
0
static void write_jpeg(struct jpeg_compress_struct * cinfo, struct ImBuf * ibuf)
{
    JSAMPLE * buffer = NULL;
    JSAMPROW row_pointer[1];
    uchar * rect;
    int x, y;
    char neogeo[128];
    ImMetaData *iptr;
    char *text;

    jpeg_start_compress(cinfo, TRUE);

    strcpy(neogeo, "NeoGeo");
    ibuf_ftype = BIG_LONG(ibuf->ftype);

    memcpy(neogeo + 6, &ibuf_ftype, 4);
    jpeg_write_marker(cinfo, 0xe1, (JOCTET*) neogeo, 10);

    if(ibuf->metadata) {
        /* key + max value + "Blender" */
        text= MEM_mallocN(530, "stamp info read");
        iptr= ibuf->metadata;
        while(iptr) {
            if (!strcmp (iptr->key, "None")) {
                jpeg_write_marker(cinfo, JPEG_COM, (JOCTET *) iptr->value, strlen (iptr->value) + 1);
                goto next_stamp_info;
            }

            /*
             * The JPEG format don't support a pair "key/value"
             * like PNG, so we "encode" the stamp in a
             * single string:
             *	"Blender:key:value"
             *
             * The first "Blender" is a simple identify to help
             * in the read process.
             */
            sprintf (text, "Blender:%s:%s", iptr->key, iptr->value);
            jpeg_write_marker(cinfo, JPEG_COM, (JOCTET *) text, strlen (text)+1);
next_stamp_info:
            iptr = iptr->next;
        }
        MEM_freeN(text);
    }

    row_pointer[0] =
        MEM_mallocN(sizeof(JSAMPLE) *
                    cinfo->input_components *
                    cinfo->image_width, "jpeg row_pointer");

    for(y = ibuf->y - 1; y >= 0; y--) {
        rect = (uchar *) (ibuf->rect + y * ibuf->x);
        buffer = row_pointer[0];

        switch(cinfo->in_color_space) {
        case JCS_RGB:
            for (x = 0; x < ibuf->x; x++) {
                *buffer++ = rect[0];
                *buffer++ = rect[1];
                *buffer++ = rect[2];
                rect += 4;
            }
            break;
        case JCS_GRAYSCALE:
            for (x = 0; x < ibuf->x; x++) {
                *buffer++ = rect[0];
                rect += 4;
            }
            break;
        case JCS_UNKNOWN:
            memcpy(buffer, rect, 4 * ibuf->x);
            break;
        /* default was missing... intentional ? */
        default:
            ; /* do nothing */
        }

        jpeg_write_scanlines(cinfo, row_pointer, 1);
    }

    jpeg_finish_compress(cinfo);
    MEM_freeN(row_pointer[0]);
}
コード例 #16
0
/**************************************************************************
压缩图像到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;

}
コード例 #17
0
ファイル: jpegtran.c プロジェクト: clobber/UME
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 */
}
コード例 #18
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;

}
コード例 #19
0
ファイル: jpeg-save.c プロジェクト: frne/gimp
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;
    }
}
コード例 #20
0
ファイル: jpegtran.c プロジェクト: qtekfun/htcDesire820Kernel
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;			
}
コード例 #21
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);
}
コード例 #22
0
ファイル: pixmap_jpg.c プロジェクト: bszcz/pixmap
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;
}
コード例 #23
0
ファイル: sw_encode.c プロジェクト: dancingalone/sharescreen
int sw_encode (struct hw_enc_param *param)
{
	static unsigned char *pdest = NULL;
	static unsigned long dest_size;
	static struct jpeg_compress_struct cinfo;
	static struct jpeg_error_mgr jerr;
	static unsigned long long stamp, stamp2;
	int i;
	int is_scaled = 0;
	int scale_rate;
	int scale_rate_div;
	static JSAMPROW rowPointer[1];
	static int started = 0;
	static int started2 = 0;

	char *p_in_buf = (char *)in_buf;
	char *p_in_buf_qcom = (char *)in_buf_qcom;
	int line_bytes = 0;

	pdest = out_buf_ptr;
	dest_size = MAX_BUFFER_SIZE;


	if (param->in_buf == NULL)
	{
		LOG_D ("JPEG input buffer is NULL!!\n");
		return -1;
	}

	/* discard verbose data for qcom platform */
	int pad = 0;
	int loop;
	if (support_qcom)
		pad = (16 - ( param->width % 16 ) ) % 16;

	LOG_D("pad = %d, support_qcom = %d\n", pad, support_qcom);
	LOG_D("param->height = %d, param->width = %d",
			param->height, param->width);
	LOG_D("bytes_per_pixel = %d", param->bytes_per_pixel);

	memcpy (in_buf, param->in_buf, param->height * (param->width + pad) * param->bytes_per_pixel);

#if 0
	//dump in_buf
	LOG_D("==========================================================");
	for (loop = 0; loop < param->width * param->bytes_per_pixel * 2;)
	{
		LOG_D("in_buf[%d] = %0X %0X %0X %0X",
				loop / 4,
				*(in_buf + loop),
				*(in_buf + loop + 1),
				*(in_buf + loop + 2),
				*(in_buf + loop + 3)
				);
		loop += param->bytes_per_pixel;
	}
	LOG_D("***********************************************************");
#endif

	if(pad)
	{
		/* in_buf -> in_buf_qcom */
		for (loop = 0; loop < param->height; loop++)
		{
			line_bytes = param->bytes_per_pixel * param->width;
			memcpy(p_in_buf_qcom, p_in_buf, line_bytes);
			p_in_buf_qcom += line_bytes;
			p_in_buf += line_bytes + pad * param->bytes_per_pixel;
		}

	}

	p_in_buf = pad ? (char *)in_buf_qcom : (char *)in_buf;

#if 0
	//dump in_buf_qcom
	LOG_D("==========================================================");
	for (loop = 0; loop < param->width * param->bytes_per_pixel * 2;)
	{
		LOG_D("in_buf_qcom[%d] = %0X %0X %0X %0X",
				loop / 4,
				*(in_buf_qcom + loop),
				*(in_buf_qcom + loop + 1),
				*(in_buf_qcom + loop + 2),
				*(in_buf_qcom + loop + 3)
				);
		loop += param->bytes_per_pixel;
	}
	LOG_D("***********************************************************");
#endif

	/* rgb scale */
	out_buf = rgb_buf;
	if (param->height > 1024 || param->width > 768)
	{
		is_scaled = 1;
		scale_rate = 3;
		scale_rate_div = 5;
	}

	if (is_scaled)
	{
		LOG_D("rgb scaling ......\n");
		stamp = _get_system_mstime();
		rgb_scale((char *)out_buf, (char *)p_in_buf,
				(unsigned int)((( param->width ) / scale_rate_div) * scale_rate ) & 0xfffffff0,
				(unsigned int)((( param->height ) / scale_rate_div) * scale_rate ) & 0xfffffff0,
				(unsigned int)param->width, (unsigned int)param->height);
		stamp2 = _get_system_mstime();
		LOG_D("scale time: %lldms\n", stamp2 - stamp);
	}

	if (started2 == 0)
	cinfo.err = jpeg_std_error(&jerr);
	if (started == 0)
	jpeg_create_compress(&cinfo);

	cinfo.image_width = is_scaled ?
		((param->width / scale_rate_div) * scale_rate ) & 0xfffffff0
		:
		param->width;
	cinfo.image_height = is_scaled ?
		((param->height / scale_rate_div) * scale_rate ) & 0xfffffff0
		:
		param->height;

	/* Rotation */
	/* WARNING:
	 * If pad is existed,
	 * This portion should be added for qualcomm 16-pixels alignment
	 * Ha, nothing qualcomm phone is available, so addition later...
	 */
	/* Ratation image from A * B to B * A */

	char * pSrc = p_in_buf;
	char * pDest = (char *)in_buf_rotation;
	int i2,j2;
	int _height = cinfo.image_height;
	int _width = cinfo.image_width;
	int cube = param->bytes_per_pixel;

	/*Debug ratation*/
#if 0
	param->angle = 270;
#endif

/* 0 -> 90
 * */
	static int pre_angle = 0;
	//if (pre_angle != param->angle) g_clear_screen = 1;
	LOGD("pre_angle = %d, param->angle = %d, g_clear_screen = %d",
			pre_angle, param->angle, g_clear_screen);

	switch (param->angle)
	{
	case 0:
	case 180:
		/*
		for (i2 = 0; i2 < _height; i2++)
			for (j2 = 0; j2 < _width; j2++)
				memcpy((pDest + (_width - j2) * _height * cube + i2 * cube),
					   (pSrc + j2 * cube + i2 * _width * cube), cube);

		cinfo.image_height = _width;
		cinfo.image_width = _height;
		p_in_buf = (char *)in_buf_rotation;
		*/
		break;
	case 90:
		for (i2 = 0; i2 < _height; i2++)
			for (j2 = 0; j2 < _width; j2++)
				memcpy((pDest + (_width - j2) * _height * cube + i2 * cube),
					   (pSrc + j2 * cube + i2 * _width * cube), cube);

		cinfo.image_height = _width;
		cinfo.image_width = _height;
		p_in_buf = (char *)in_buf_rotation;
		break;
	case 270:
		for (i2 = 0; i2 < _height; i2++)
			for (j2 = 0; j2 < _width; j2++)
				memcpy((pDest + j2 * _height * cube + (_height - i2) * cube),
					   (pSrc + j2 * cube + i2 * _width * cube), cube);

		cinfo.image_height = _width;
		cinfo.image_width = _height;
		p_in_buf = (char *)in_buf_rotation;
		break;
	case 360:
#if 1
		for (i2 = 0; i2 < _height; i2++)
			for (j2 = 0; j2 < _width; j2++)
				memcpy((pDest + (_width - j2) * _height * cube + i2 * cube),
					   (pSrc + j2 * cube + i2 * _width * cube), cube);

		cinfo.image_height = _width;
		cinfo.image_width = _height;
		p_in_buf = (char *)in_buf_rotation;
		break;
#else
		for (i2 = 0; i2 < _height; i2++)
		{
			for (j2 = 0; j2 < _width; j2++)
			{
				memcpy((pDest + (_height - i2) * _width * cube + (_width - j2) * cube),
					   (pSrc + j2 * cube + i2 * _width * cube), cube);
			}
		}

		cinfo.image_height = _height;
		cinfo.image_width = _width;
		p_in_buf = (char *)in_buf_rotation;
		break;
#endif
	default:
		LOGE("ERROR: angle = %d, VOID value\n", param->angle);
		break;
	}

	cinfo.input_components = param->bytes_per_pixel;

#if 0
	/* check if should clear screen */
	LOGD("g_clear_screen = %d, g_frame_nums = %d\n",
			g_clear_screen, g_frame_nums);
	if (g_clear_screen || g_frame_nums)
	{
		LOGD("clear screen! deeply blank, Oh, My God! somebody shut down lights!");
		long _height = cinfo.image_height;
		long _width = cinfo.image_width;
		long unit = param->bytes_per_pixel;
		long go_to_cinema = _height * _width * unit;
		memset(p_in_buf, 0, go_to_cinema);
		if(g_clear_screen == 1)
			memset(p_in_buf, 0xFF, 0xF);
		if (g_clear_screen)
			g_frame_nums = 1;
		else
			g_frame_nums--;
	}
#endif
	switch (param->in_format)
	{
	case SW_RGBX:
		cinfo.in_color_space = JCS_EXT_RGBX;
		break;
	case SW_BGRX:
		cinfo.in_color_space = JCS_EXT_BGRX;
		break;
	case SW_XRGB:
		cinfo.in_color_space = JCS_EXT_XRGB;
		break;
	case SW_XBGR:
		cinfo.in_color_space = JCS_EXT_XBGR;
		break;
	default:
		LOGE("unsupport color format param->in_format = %d\n", param->in_format);
		cinfo.in_color_space = JCS_UNKNOWN;
	}
	if (started == 0)
	jpeg_set_defaults(&cinfo);

	LOG_D("cinfo.in_color_space = %d\n", cinfo.in_color_space);
	if (started == 0)
	jpeg_default_colorspace(&cinfo);
	if (started == 0)
	jpeg_set_quality(&cinfo, is_scaled ? 80 : 75, TRUE);
	if (started == 0)
	jpeg_mem_dest((j_compress_ptr)&cinfo, (unsigned char **)&pdest, &dest_size);  // Data written to mem

	jpeg_start_compress(&cinfo, TRUE);
	rowPointer[0] = is_scaled ? (JSAMPROW)out_buf : (JSAMPROW)p_in_buf;

	LOGD("O o O o O o O o O o O o O o");
	LOGD("cinfo.image_height = %d, cinfo.image_width = %d\n",
			cinfo.image_height, cinfo.image_width);
	stamp = _get_system_mstime();
	int count = 0;
	for (i = 0; i < cinfo.image_height; ++i)
	{
		++count;
		if (is_scaled)
		{
			LOG_D("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
			rowPointer[0] = (out_buf + cinfo.input_components * i * cinfo.image_width);
		}
		else
		{
			//LOG_D("%d,%d, --", __LINE__, count);
			if (p_in_buf == NULL)
				LOG_D("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
			rowPointer[0] = (JSAMPROW)((char *)p_in_buf + cinfo.input_components * i * cinfo.image_width);
		}
			jpeg_write_scanlines(&cinfo, rowPointer, 1);
	}
	stamp2 = _get_system_mstime();
	LOG_D("\t\t sw encode time: %lldms, jpeg size is %d\n", stamp2 - stamp, (int)dest_size);

	if (started == 0)
	jpeg_finish_compress(&cinfo);
	if (started2 == 0)
	//jpeg_destroy_compress(&cinfo);

	param->out_buf = pdest;
	param->outdata_size = dest_size;
	out_buf_size = dest_size;
	printf("param->out_buf = %X, param->outdata_size = %d\n\n",
		  (unsigned int)param->out_buf, param->outdata_size);

	static int firstIn = 0;
	//if(firstIn == 0)
	if (g_clear_screen == 1)
	{
		firstIn = 1;
		FILE *pfile = fopen("/sdcard/clear_screen.jpg", "w");
		if (pfile == NULL)
		{
			LOG_D("open file error!\n");
			goto AAAA;
		}
		fwrite(pdest, 1, dest_size, pfile);
		fclose(pfile);
	}
AAAA:
	if(!out_buf_size)
	{
		LOGE("Out size is 0!\n");
		return -1;
	}

	if (started == 0)
		started = 0;
	if (started2 == 0)
		started2 = 0;

	pre_angle = param->angle;
	return 0;
}
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;
}
コード例 #25
0
ファイル: tr_image_jpg.c プロジェクト: winrid/etlegacy
/*
=================
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;
}
コード例 #26
0
ファイル: rbitmap.c プロジェクト: ViennaR/r-source
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;
}
コード例 #27
0
ファイル: CScreen.cpp プロジェクト: skhaz/oldies
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
}
コード例 #28
0
ファイル: imagjpeg.cpp プロジェクト: erwincoumans/wxWidgets
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;
}
コード例 #29
0
ファイル: JpegIO.cpp プロジェクト: Nomoreillusion/kodi-cmake
bool CJpegIO::CreateThumbnailFromSurface(unsigned char* bufferin, unsigned int width, unsigned int height, unsigned int format, unsigned int pitch, const std::string& 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;
}
コード例 #30
0
ファイル: gl_rmisc.c プロジェクト: turol/webquake2
void GL_ScreenShot_JPG (byte *buffer)
{
	struct jpeg_compress_struct cinfo;
	struct jpeg_error_mgr jerr;
	JSAMPROW s[1];
	FILE *f;
	char picname[80], checkname[MAX_OSPATH];
	int i, offset, w3;

	// create the scrnshots directory if it doesn't exist
	Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot/", FS_Gamedir());
	FS_CreatePath (checkname);

	for (i = 0; i < 999; i++) {
		sprintf (picname, "%s/scrnshot/quake%.3d.jpg", FS_Gamedir(), i);
		f = fopen (picname, "rb");
		if (!f)
			break;
		fclose (f);
	}

	f = fopen (picname, "wb");
	if (!f)
	{
		VID_Printf (PRINT_ALL, "Couldn't open %s for writing.\n", picname);
		return;
	}

	// Initialise the JPEG compression object
	cinfo.err = jpeg_std_error(&jerr);
	jpeg_create_compress(&cinfo);
	jpeg_stdio_dest(&cinfo, f);

	// Setup JPEG Parameters
	cinfo.image_width = viddef.width;
	cinfo.image_height = viddef.height;
	cinfo.in_color_space = JCS_RGB;
	cinfo.input_components = 3;

	jpeg_set_defaults(&cinfo);

	// Niceass: 85 is the quality. 0-100
	jpeg_set_quality(&cinfo, Q_ftol(gl_jpg_quality->value), TRUE);

	// Start Compression
	jpeg_start_compress(&cinfo, true);

	// Feed scanline data
	w3 = cinfo.image_width * 3;
	offset = w3 * cinfo.image_height - w3;

	while (cinfo.next_scanline < cinfo.image_height)
	{
		s[0] = &buffer[offset - cinfo.next_scanline * w3];
		jpeg_write_scanlines(&cinfo, s, 1);
	}

	// Finish Compression
	jpeg_finish_compress(&cinfo);

	jpeg_destroy_compress(&cinfo);

	fclose(f);
	free(buffer);

	VID_Printf (PRINT_ALL, "Wrote %s\n", picname);
}