Ejemplo n.º 1
0
csPtr<iDataBuffer> csJNGImageIO::Save (iImage *Image,
	iImageIO::FileFormatDescription *, const char* extraoptions)
{
  // we need to get a RGB/RGBA version of the image.
  switch (Image->GetFormat() & CS_IMGFMT_MASK)
  {
    case CS_IMGFMT_PALETTED8:
      //imgRGBA = Image->Clone ();
      //imgRGBA->SetFormat (CS_IMGFMT_TRUECOLOR | (Image->GetFormat() & CS_IMGFMT_ALPHA));
      // act like JPEG plugin; reject paletted image so no
      // unwanted/unnoticed conversions take place.
      return 0;
      break;
    case CS_IMGFMT_TRUECOLOR:
      imgRGBA = csRef<iImage>(Image);
      break;
    default:
      // unknown format
      return 0;
  } 

  // compression options
  int quality = 80;
  bool progressive = false;
  bool alpha_jpeg = false;
  int alpha_png_compress = 6;
  int alpha_jpeg_quality = -1;

  /*
     parse output options.
     options are a comma-separated list and can be either
     'option' or 'option=value'.

     supported options:
       compress=#	  image color compression, 0..100 higher values give smaller files
			  but uglier results.
       progressive	  progressive encoding.
       jng_lossy_alpha	  use lossy JPEG compression for alpha channel (instead of
			  default lossles PNG)
       jng_alpha_compress alpha channel compression, 0..100
			  Impact of higher value depends on alpha channel type.
			  JPEG - smaller files, uglier results.
			  PNG - smaller files, longer time to encode.
			  Note: defaults to value for image color compression if lossy alpha
			  is selected.
	    

     examples:
       compress=50
       progressive,compress=30
   */
  csImageLoaderOptionsParser optparser (extraoptions);
  optparser.GetBool ("progressive", progressive);
  if (optparser.GetInt ("compress", quality))
  {
    quality = 100 - quality;
    if (quality < 0) quality = 0;
    if (quality > 100) quality = 100;
    if (alpha_jpeg_quality == -1) alpha_jpeg_quality = quality;
  }
  if (optparser.GetBool ("jng_lossy_alpha", alpha_jpeg))
  {
    if (alpha_jpeg_quality == -1) alpha_jpeg_quality = quality;
  }
  if (optparser.GetInt ("jng_alpha_compress", alpha_png_compress))
  {
    alpha_jpeg_quality = 100 - alpha_png_compress;
    if (alpha_jpeg_quality < 0) alpha_jpeg_quality = 0;
    if (alpha_jpeg_quality > 100) alpha_jpeg_quality = 100;
    alpha_png_compress /= 10;
    if (alpha_png_compress < 0) alpha_png_compress = 0;
    if (alpha_png_compress > 9) alpha_png_compress = 9;
  }

  mng_handle handle = mng_initialize ( mng_ptr(this), cb_alloc, 
                                      cb_free, MNG_NULL);
  if (!handle)
  {
    Report (object_reg, CS_REPORTER_SEVERITY_WARNING,
      "failed to initialize libmng");
    return 0;
  }

  if ((mng_setcb_openstream (handle, cb_openstream) != MNG_NOERROR) ||
      (mng_setcb_closestream (handle, cb_closestream) != MNG_NOERROR) ||
      (mng_setcb_writedata (handle, cb_writedata) != MNG_NOERROR))
  {
    ReportLibmngError (object_reg, handle, "failed to set libmng callbacks");
    mng_cleanup (&handle);
    return 0;
  }

  outfile = new csMemFile ();

  if (mng_create (handle) != MNG_NOERROR)
  {
    ReportLibmngError (object_reg, handle, "failed to create new jng");
    mng_cleanup (&handle);
    delete outfile;
    imgRGBA = 0;
    return 0;
  }

  bool has_alpha = (imgRGBA->GetFormat() & CS_IMGFMT_ALPHA) != 0;

  if (mng_putchunk_jhdr (handle, imgRGBA->GetWidth(), imgRGBA->GetHeight(),
			 has_alpha ? MNG_COLORTYPE_JPEGCOLORA 
				   : MNG_COLORTYPE_JPEGCOLOR,
			 MNG_BITDEPTH_JPEG8, MNG_COMPRESSION_BASELINEJPEG,
			 progressive ? MNG_INTERLACE_PROGRESSIVE
				     : MNG_INTERLACE_SEQUENTIAL,
				     has_alpha?8:0, has_alpha?(alpha_jpeg?8:0):0, 
			 0, 0) != MNG_NOERROR)
  {
    ReportLibmngError (object_reg, handle, "failed to put JHDR chunk");
    mng_cleanup (&handle);
    delete outfile;
    imgRGBA = 0;
    return 0;
  }

  // @@@ chunk data generation.
  // lots of stuff needs to be done manually.
  // should be changed as libmng evolves.

  // write out alpha channel
  if (has_alpha)
  {
    // extract the alpha channel from the image
    int pixels = imgRGBA->GetWidth() * imgRGBA->GetHeight();
    uint8 *alpha = new uint8 [pixels];
    uint8 *alphaptr = alpha;
    csRGBpixel *imgdata = (csRGBpixel*)imgRGBA->GetImageData();

    while (pixels>0)
    {
      *alphaptr++ = (imgdata++)->alpha;
      pixels--;
    }

    if (alpha_jpeg)
    {
      // compress the alpha data as JPEG and write it out.
      uint8* volatile row = 0;
      struct jpg_datastore ds;
      struct jpeg_compress_struct cinfo;
      struct my_error_mgr jerr;
      cinfo.err = jpeg_std_error (&jerr.pub);
      jerr.pub.error_exit = my_error_exit;

      if (setjmp (jerr.setjmp_buffer))
      {
	Report (object_reg, CS_REPORTER_SEVERITY_WARNING,
		"failed to JPEG compress alpha data");
	mng_cleanup (&handle);
	delete outfile;
	delete [] row;
	delete[] alpha;
	jpeg_destroy_compress (&cinfo);
	imgRGBA = 0;
	return 0;
      }

      jpeg_create_compress (&cinfo);
      jpeg_buffer_dest (&cinfo, &ds);

      cinfo.image_width = imgRGBA->GetWidth ();
      cinfo.image_height = imgRGBA->GetHeight ();
      cinfo.input_components = 1;
      cinfo.in_color_space = JCS_GRAYSCALE;

      row = new uint8[cinfo.image_width];
      jpeg_set_defaults (&cinfo);
      jpeg_set_quality (&cinfo, alpha_jpeg_quality, true);
      jpeg_start_compress (&cinfo, true);

      JSAMPROW row_pointer[1];
      uint8 *image = alpha;
      row_pointer[0] = (JSAMPLE*)&row[0];

      while (cinfo.next_scanline < cinfo.image_height)
      {
	for (size_t i=0; i < cinfo.image_width; i++)
	  row[i] = image[cinfo.next_scanline * cinfo.image_width + i];
	jpeg_write_scanlines (&cinfo, row_pointer, 1);
      }

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

      delete [] row;

      // funny, mng_putchunk_jdaa is missing from libmng
      //if (mng_putchunk_jdaa (handle, ds.len, ds.data) != MNG_NOERROR)
      if (mng_putchunk_unknown (handle, MNG_UINT_JDAA, 
	(mng_uint32)ds.len, ds.data) != MNG_NOERROR)
      {
	ReportLibmngError (object_reg, handle, "failed to put JDAA chunk");
	mng_cleanup (&handle);
	delete outfile;
	delete[] alpha;
	imgRGBA = 0;
	return 0;
      }
    }
    else
    {
      // generate the IDAT chunk data
      // we use the "Up" filter. 
      uint8* chunkdata = new uint8[(imgRGBA->GetWidth() + 1) * imgRGBA->GetHeight()];
      uint8* lastline = new uint8[imgRGBA->GetWidth()];
      uint8* chunkptr = chunkdata;
      alphaptr = alpha;

      memset (lastline, 0, imgRGBA->GetWidth());
      int lines = imgRGBA->GetHeight();
      while (lines > 0) 
      {
	*chunkptr++ = 2;
	int pix = 0;
	while (pix<imgRGBA->GetWidth())
	{
	  *chunkptr++ = *alphaptr - lastline[pix];
	  lastline[pix] = *alphaptr++;
	  pix++;
	}
	lines--;
      }
      delete[] lastline;

      // now compress the data
      z_stream zs;

      zs.zalloc = (alloc_func) 0;
      zs.zfree = (free_func) 0;
      zs.next_in = (Byte *) chunkdata;
      zs.avail_in = (imgRGBA->GetWidth() + 1) * imgRGBA->GetHeight();

      if (deflateInit (&zs, alpha_png_compress) != Z_OK)
      {
	Report (object_reg, CS_REPORTER_SEVERITY_WARNING,
	  "deflateInit() failed");
	mng_cleanup (&handle);
	delete outfile;
	delete[] chunkdata;
	delete[] alpha;
	imgRGBA = 0;
	return 0;
      }

      char buff[0x8000];

      while (1)
      {
        zs.next_out = (Byte *)buff;
        zs.avail_out = sizeof (buff);

        int rc = deflate (&zs, Z_FINISH);   /* Do actual compression */
        size_t size = sizeof (buff) - zs.avail_out;

	// create a chuk w/compressed data.
	if (mng_putchunk_idat (handle, (mng_uint32)size, &buff) != MNG_NOERROR)
	{
	  ReportLibmngError (object_reg, handle, "failed to put IDAT chunk");
          deflateEnd (&zs);
	  mng_cleanup (&handle);
	  delete outfile;
	  delete[] chunkdata;
	  delete[] alpha;
	  imgRGBA = 0;
	  return 0;
	}
        if (rc == Z_STREAM_END)
          break;            /* finished */
      } 
      deflateEnd (&zs);

      delete[] chunkdata;
    }

    delete[] alpha;
  }

  // compress the color data as JPEG and write it out.
  csRGBcolor* volatile row = 0;
  struct jpg_datastore ds;
  struct jpeg_compress_struct cinfo;
  struct my_error_mgr jerr;
  cinfo.err = jpeg_std_error (&jerr.pub);
  jerr.pub.error_exit = my_error_exit;

  if (setjmp (jerr.setjmp_buffer))
  {
    Report (object_reg, CS_REPORTER_SEVERITY_WARNING,
	    "failed to JPEG compress color data");
    mng_cleanup (&handle);
    delete outfile;
    delete [] row;
    jpeg_destroy_compress (&cinfo);
    imgRGBA = 0;
    return 0;
  }

  jpeg_create_compress (&cinfo);
  jpeg_buffer_dest (&cinfo, &ds);

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

  row = new csRGBcolor[cinfo.image_width];
  jpeg_set_defaults (&cinfo);
  jpeg_set_quality (&cinfo, quality, true);
  if (progressive) jpeg_simple_progression (&cinfo);
  jpeg_start_compress (&cinfo, true);

  JSAMPROW row_pointer[1];
  JSAMPLE *image = (JSAMPLE*)csPackRGB::PackRGBpixelToRGB
    ((csRGBpixel*)Image->GetImageData (),
    Image->GetWidth () * Image->GetHeight ());
  row_pointer[0] = (JSAMPLE*)&row[0];

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

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

  delete [] row;

  if (mng_putchunk_jdat (handle, (mng_uint32)ds.len, ds.data) != MNG_NOERROR)
  {
    ReportLibmngError (object_reg, handle, "failed to put JDAT chunk");
    mng_cleanup (&handle);
    delete outfile;
    imgRGBA = 0;
    return 0;
  }
  
  imgRGBA = 0;

  if (mng_putchunk_iend (handle) != MNG_NOERROR)
  {
    ReportLibmngError (object_reg, handle, "failed to put IEND chunk");
    mng_cleanup (&handle);
    delete outfile;
    return 0;
  }

  if (mng_write (handle) != MNG_NOERROR)
  {
    ReportLibmngError (object_reg, handle, "failed to write out JNG data");
    mng_cleanup (&handle);
    delete outfile;
    return 0;
  }

  mng_cleanup (&handle);

  csRef<iDataBuffer> db (outfile->GetAllData ());

  delete outfile;

  return csPtr<iDataBuffer> (db);
}
Ejemplo n.º 2
0
int
ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
{
    JPEGENCODERSTATE* context = (JPEGENCODERSTATE*) state->context;
    int ok;

    if (setjmp(context->error.setjmp_buffer)) {
	/* JPEG error handler */
	jpeg_destroy_compress(&context->cinfo);
	state->errcode = IMAGING_CODEC_BROKEN;
	return -1;
    }

    if (!state->state) {

	/* Setup compression context (very similar to the decoder) */
	context->cinfo.err = jpeg_std_error(&context->error.pub);
	context->error.pub.error_exit = error;
	jpeg_create_compress(&context->cinfo);
	jpeg_buffer_dest(&context->cinfo, &context->destination);

        context->extra_offset = 0;

	/* Ready to encode */
	state->state = 1;

    }

    /* Load the destination buffer */
    context->destination.pub.next_output_byte = buf;
    context->destination.pub.free_in_buffer = bytes;

    switch (state->state) {

    case 1:

	context->cinfo.image_width = state->xsize;
	context->cinfo.image_height = state->ysize;

	switch (state->bits) {
        case 8:
            context->cinfo.input_components = 1;
            context->cinfo.in_color_space = JCS_GRAYSCALE;
            break;
        case 24:
            context->cinfo.input_components = 3;
            if (strcmp(im->mode, "YCbCr") == 0)
                context->cinfo.in_color_space = JCS_YCbCr;
            else
                context->cinfo.in_color_space = JCS_RGB;
            break;
        case 32:
            context->cinfo.input_components = 4;
            context->cinfo.in_color_space = JCS_CMYK;
            break;
        default:
            state->errcode = IMAGING_CODEC_CONFIG;
            return -1;
	}

	/* Compressor configuration */
	jpeg_set_defaults(&context->cinfo);

	/* Use custom quantization tables */
	if (context->qtables) {
        int i;
        int quality = 100;
        if (context->quality > 0) {
            quality = context->quality;
        }
        for (i = 0; i < sizeof(context->qtables)/sizeof(unsigned int); i++) {
             // TODO: Should add support for none baseline
            jpeg_add_quant_table(&context->cinfo, i, context->qtables[i],
                quality, TRUE);
        }
	} else if (context->quality > 0) {
	    jpeg_set_quality(&context->cinfo, context->quality, 1);
	}

	/* Set subsampling options */
	switch (context->subsampling)
	{
		case 0:  /* 1x1 1x1 1x1 (4:4:4) : None */
		{
			context->cinfo.comp_info[0].h_samp_factor = 1;
			context->cinfo.comp_info[0].v_samp_factor = 1;
			context->cinfo.comp_info[1].h_samp_factor = 1;
			context->cinfo.comp_info[1].v_samp_factor = 1;
			context->cinfo.comp_info[2].h_samp_factor = 1;
			context->cinfo.comp_info[2].v_samp_factor = 1;
			break;
		}
		case 1:  /* 2x1, 1x1, 1x1 (4:2:2) : Medium */
		{
			context->cinfo.comp_info[0].h_samp_factor = 2;
			context->cinfo.comp_info[0].v_samp_factor = 1;
			context->cinfo.comp_info[1].h_samp_factor = 1;
			context->cinfo.comp_info[1].v_samp_factor = 1;
			context->cinfo.comp_info[2].h_samp_factor = 1;
			context->cinfo.comp_info[2].v_samp_factor = 1;
			break;
		}
		case 2:  /* 2x2, 1x1, 1x1 (4:1:1) : High */
		{
			context->cinfo.comp_info[0].h_samp_factor = 2;
			context->cinfo.comp_info[0].v_samp_factor = 2;
			context->cinfo.comp_info[1].h_samp_factor = 1;
			context->cinfo.comp_info[1].v_samp_factor = 1;
			context->cinfo.comp_info[2].h_samp_factor = 1;
			context->cinfo.comp_info[2].v_samp_factor = 1;
			break;
		}
		default:
		{
			/* Use the lib's default */
			break;
		}
	}
	if (context->progressive)
	    jpeg_simple_progression(&context->cinfo);
	context->cinfo.smoothing_factor = context->smooth;
	context->cinfo.optimize_coding = (boolean) context->optimize;
        if (context->xdpi > 0 && context->ydpi > 0) {
            context->cinfo.density_unit = 1; /* dots per inch */
            context->cinfo.X_density = context->xdpi;
            context->cinfo.Y_density = context->ydpi;
        }
	switch (context->streamtype) {
	case 1:
	    /* tables only -- not yet implemented */
	    state->errcode = IMAGING_CODEC_CONFIG;
	    return -1;
	case 2:
	    /* image only */
	    jpeg_suppress_tables(&context->cinfo, TRUE);
	    jpeg_start_compress(&context->cinfo, FALSE);
            /* suppress extra section */
            context->extra_offset = context->extra_size;
        //add exif header
        if (context->rawExifLen > 0)
            jpeg_write_marker(&context->cinfo, JPEG_APP0+1, (unsigned char*)context->rawExif, context->rawExifLen);

	    break;
	default:
	    /* interchange stream */
	    jpeg_start_compress(&context->cinfo, TRUE);
        //add exif header
        if (context->rawExifLen > 0)
            jpeg_write_marker(&context->cinfo, JPEG_APP0+1, (unsigned char*)context->rawExif, context->rawExifLen);

        break;
	}
	state->state++;
	/* fall through */

    case 2:

        if (context->extra) {
            /* copy extra buffer to output buffer */
            unsigned int n = context->extra_size - context->extra_offset;
            if (n > context->destination.pub.free_in_buffer)
                n = context->destination.pub.free_in_buffer;
            memcpy(context->destination.pub.next_output_byte,
                   context->extra + context->extra_offset, n);
            context->destination.pub.next_output_byte += n;
            context->destination.pub.free_in_buffer -= n;
            context->extra_offset += n;
            if (context->extra_offset >= context->extra_size)
                state->state++;
            else
                break;
        } else
              state->state++;

    case 3:

	ok = 1;
	while (state->y < state->ysize) {
	    state->shuffle(state->buffer,
			   (UINT8*) im->image[state->y + state->yoff] +
			   state->xoff * im->pixelsize, state->xsize);
	    ok = jpeg_write_scanlines(&context->cinfo, &state->buffer, 1);
	    if (ok != 1)
		break;
	    state->y++;
	}

	if (ok != 1)
	    break;
	state->state++;
	/* fall through */

    case 4:

	/* Finish compression */
	if (context->destination.pub.free_in_buffer < 100)
	    break;
	jpeg_finish_compress(&context->cinfo);

	/* Clean up */
        if (context->extra)
            free(context->extra);
	jpeg_destroy_compress(&context->cinfo);
	/* if (jerr.pub.num_warnings) return BROKEN; */
	state->errcode = IMAGING_CODEC_END;
	break;

    }

    /* Return number of bytes in output buffer */
    return context->destination.pub.next_output_byte - buf;

}
bool JpegEncoder::write( const Mat& img, const vector<int>& params )
{
    m_last_error.clear();

    struct fileWrapper
    {
        FILE* f;

        fileWrapper() : f(0) {}
        ~fileWrapper() { if(f) fclose(f); }
    };
    bool result = false;
    fileWrapper fw;
    int width = img.cols, height = img.rows;

    vector<uchar> out_buf(1 << 12);
    AutoBuffer<uchar> _buffer;
    uchar* buffer;

    struct jpeg_compress_struct cinfo;
    JpegErrorMgr jerr;
    JpegDestination dest;

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

    if( !m_buf )
    {
        fw.f = fopen( m_filename.c_str(), "wb" );
        if( !fw.f )
            goto _exit_;
        jpeg_stdio_dest( &cinfo, fw.f );
    }
    else
    {
        dest.dst = m_buf;
        dest.buf = &out_buf;

        jpeg_buffer_dest( &cinfo, &dest );

        dest.pub.next_output_byte = &out_buf[0];
        dest.pub.free_in_buffer = out_buf.size();
    }

    if( setjmp( jerr.setjmp_buffer ) == 0 )
    {
        cinfo.image_width = width;
        cinfo.image_height = height;

        int _channels = img.channels();
        int channels = _channels > 1 ? 3 : 1;
        cinfo.input_components = channels;
        cinfo.in_color_space = channels > 1 ? JCS_RGB : JCS_GRAYSCALE;

        int quality = 95;

        for( size_t i = 0; i < params.size(); i += 2 )
        {
            if( params[i] == CV_IMWRITE_JPEG_QUALITY )
            {
                quality = params[i+1];
                quality = MIN(MAX(quality, 0), 100);
            }
        }

        jpeg_set_defaults( &cinfo );
        jpeg_set_quality( &cinfo, quality,
                          TRUE /* limit to baseline-JPEG values */ );
        jpeg_start_compress( &cinfo, TRUE );

        if( channels > 1 )
            _buffer.allocate(width*channels);
        buffer = _buffer;

        for( int y = 0; y < height; y++ )
        {
            uchar *data = img.data + img.step*y, *ptr = data;

            if( _channels == 3 )
            {
                icvCvt_BGR2RGB_8u_C3R( data, 0, buffer, 0, cvSize(width,1) );
                ptr = buffer;
            }
            else if( _channels == 4 )
            {
                icvCvt_BGRA2BGR_8u_C4C3R( data, 0, buffer, 0, cvSize(width,1), 2 );
                ptr = buffer;
            }

            jpeg_write_scanlines( &cinfo, &ptr, 1 );
        }

        jpeg_finish_compress( &cinfo );
        result = true;
    }

_exit_:

    if(!result)
    {
        char jmsg_buf[JMSG_LENGTH_MAX];
        jerr.pub.format_message((j_common_ptr)&cinfo, jmsg_buf);
        m_last_error = jmsg_buf;
    }

    jpeg_destroy_compress( &cinfo );

    return result;
}
Ejemplo n.º 4
0
void ModeJpeg::jpegCompressForJetReady()
{
    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr       jerr;
    jmp_buf                     setjmp_buffer;


//  Use the modified Mojave CSC table
    hp_rgb_ycc_setup (1);

    compressedsize = 0;
    memset (compressBuf, 0xFF, m_max_file_size);

    cinfo.err = jpeg_std_error (&jerr);
    jerr.error_exit = HPJpeg_error;
    if (setjmp (setjmp_buffer))
    {
        jpeg_destroy_compress (&cinfo);
        return;
    }

    jpeg_create_compress (&cinfo);
    cinfo.in_color_space = (m_iColorMode == 0) ? JCS_RGB : JCS_GRAYSCALE;
    jpeg_set_defaults (&cinfo);
    cinfo.image_width = m_iRowWidth / 3;
    cinfo.image_height = m_iBandHeight;
    cinfo.input_components = (m_iColorMode == 0) ? 3 : 1;
    cinfo.data_precision = 8;

    // Create a static quant table here. 

    static unsigned int mojave_quant_table1[64] =  {
                                                    2,3,4,5,5,5,5,5,
                                                    3,6,5,8,5,8,5,8,
                                                    4,5,5,5,5,5,5,5,
                                                    5,8,5,8,5,8,5,8,
                                                    5,5,5,5,5,5,5,5,
                                                    5,8,5,8,5,8,5,8,
                                                    5,5,5,5,5,5,5,5,
                                                    5,8,5,8,5,8,5,8
                                                    };
    
    //
    // JetReady specific Q-Tables will be added here. We do the following:
    //  1. Add three Q-Tables.
    //  2. Scale the Q-Table elemets with the given scale factor.
    //  3. Check to see if any of the element in the table is greater than 255
    //     reset that elemet to 255.
    //  5. There is a specific scaling needed to be done to the first 6 
    //     elements in the matrix. This is required to achieve better
    //     compression ratio.
    //  4. Check to see if any the of the recently modified element is
    //     greater than 255, reset that to 255.
    //
    //  Please refer to sRGBLaserHostBasedSoftwareERS.doc v9.0 section 5.2.5.3.1.1
    //  for more details.
    //
    //  [NOTE] These loop needs to be further optimized.
    //
    for (int i = 0; i < 3; i++)
    {
        // Adding Q-Table.

        jpeg_add_quant_table(&cinfo, i, mojave_quant_table1,  0, FALSE );
        //
        // Scaling the Q-Table elements. 
        // Reset the element to 255, if it is greater than 255.
        //

        for(int j = 1; j < 64; j++)
        {
            cinfo.quant_tbl_ptrs[i]->quantval[j] = (UINT16)((mojave_quant_table1[j] * m_pQTableInfo->qFactor) & 0xFF);  
        }   // for (int j = 1; j < 64; j++)

        //
        // Special scaling for first 6 elements in the table.
        // Reset the specially scaled elements 255, if it is greater than 255.
        //

        //
        // 1st component in the table. Unchanged, I need not change anything here.
        //
        cinfo.quant_tbl_ptrs[i]->quantval[0] = (UINT16)mojave_quant_table1[0];
        
        //
        // 2nd and 3rd components in the zig zag order
        //
        // The following dTemp is being used  to ceil the vales: e.g 28.5 to 29
        //
        double dTemp = mojave_quant_table1[1] * (1 + 0.25 * (m_pQTableInfo->qFactor - 1)) + 0.5;
        cinfo.quant_tbl_ptrs[i]->quantval[1] = (UINT16)dTemp & 0xFF;
        
        dTemp = mojave_quant_table1[8] * (1 + 0.25 * (m_pQTableInfo->qFactor - 1)) + 0.5;
        cinfo.quant_tbl_ptrs[i]->quantval[8] = (UINT16)dTemp & 0xFF;
       
        //
        // 4th, 5th and 6th components in the zig zag order
        //
        dTemp = mojave_quant_table1[16] * (1 + 0.50 * (m_pQTableInfo->qFactor - 1)) + 0.5;
        cinfo.quant_tbl_ptrs[i]->quantval[16] = (UINT16)dTemp & 0xFF;
        
        dTemp = mojave_quant_table1[9] * (1 + 0.50 * (m_pQTableInfo->qFactor - 1)) + 0.5;
        cinfo.quant_tbl_ptrs[i]->quantval[9]  = (UINT16)dTemp & 0xFF;
        
        dTemp = mojave_quant_table1[2] * (1 + 0.50 * (m_pQTableInfo->qFactor - 1)) + 0.5;
        cinfo.quant_tbl_ptrs[i]->quantval[2]  = (UINT16)dTemp & 0xFF;
    }   // for (i = 0; i < 3; i++)

    // Hard code to use sampling mode 4:4:4

    cinfo.comp_info[0].h_samp_factor = 1;
    cinfo.comp_info[0].v_samp_factor = 1;

    jpeg_buffer_dest (&cinfo, (JOCTET *) this, (void *) (output_buffer_callback));

    int    row_width = m_iRowWidth;
    if (m_iColorMode != 0)
    {
        row_width = m_iRowWidth / 3;
        cinfo.write_JFIF_header = FALSE;
        cinfo.write_Adobe_marker = FALSE;
        jpeg_suppress_tables(&cinfo, TRUE);
    }

    jpeg_start_compress (&cinfo, TRUE);
    JSAMPROW    pRowArray[1];
    BYTE        *pScanLine = m_pbyInputBuffer;
    int         i;
    for (i = 0; i < m_iBandHeight; i++)
    {
        pRowArray[0] = (JSAMPROW) pScanLine;
        jpeg_write_scanlines (&cinfo, pRowArray, 1);
        pScanLine += (row_width);
    }
    jpeg_finish_compress (&cinfo);

//  Read the quantization table used for this compression

    if (cinfo.quant_tbl_ptrs[0] != NULL)
    {
//        memcpy(m_pQTableInfo->qtable0, cinfo.quant_tbl_ptrs[0]->quantval, QTABLE_SIZE);
        for (i = 0; i < QTABLE_SIZE; i++)
        {
            m_pQTableInfo->qtable0[i] = cinfo.quant_tbl_ptrs[0]->quantval[i];
        }
    }
    if (cinfo.quant_tbl_ptrs[1] != NULL)
    {
//        memcpy(m_pQTableInfo->qtable1, cinfo.quant_tbl_ptrs[1]->quantval, QTABLE_SIZE);
        for (i = 0; i < QTABLE_SIZE; i++)
        {
            m_pQTableInfo->qtable1[i] = cinfo.quant_tbl_ptrs[1]->quantval[i];
        }
    }
    if (cinfo.quant_tbl_ptrs[2] != NULL)
    {
//        memcpy(m_pQTableInfo->qtable2, cinfo.quant_tbl_ptrs[2]->quantval, QTABLE_SIZE);
        for (i = 0; i < QTABLE_SIZE; i++)
        {
            m_pQTableInfo->qtable2[i] = cinfo.quant_tbl_ptrs[2]->quantval[i];
        }
    }
    jpeg_destroy_compress (&cinfo);
    if (m_iColorMode != 0)
    {
        unsigned int    l = 0;
        while (l < compressedsize)
        {
            if (compressBuf[l] == 0xFF && compressBuf[l+1] == 0xDA)
                break;
            l++;
        }
        if (l != compressedsize)
        {
            m_uiGrayscaleOffset = l + 10;
        }
    }
}
Ejemplo n.º 5
0
void ModeJpeg::jpegCompressForQuickConnect()
{
    BYTE    *p;
    int     iQuality = 100;

/*
 *  Convert the byte buffer to jpg, if converted size is greater than 2MB, delete it and
 *  convert with a higher compression factor.
 */

    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr       jerr;
    jmp_buf                     setjmp_buffer;

    bool    bRedo;

//  Use the standard RGB to YCC table rather than the modified one for JetReady

    hp_rgb_ycc_setup (0);
    do
    {
        bRedo = 0;
        compressedsize = 0;
        memset (compressBuf, 0xFF, m_max_file_size);
        p = m_pbyInputBuffer;

        cinfo.err = jpeg_std_error (&jerr);
        jerr.error_exit = HPJpeg_error;
        if (setjmp (setjmp_buffer))
        {
            jpeg_destroy_compress (&cinfo);
            return;
        }

        jpeg_create_compress (&cinfo);
        cinfo.in_color_space = JCS_RGB;
        jpeg_set_defaults (&cinfo);
        cinfo.image_width = m_iRowWidth / 3;
        cinfo.image_height = m_iRowNumber;
        cinfo.input_components = 3;
        cinfo.data_precision = 8;
        jpeg_set_quality (&cinfo, iQuality, TRUE);
        jpeg_buffer_dest (&cinfo, (JOCTET *) this, (void *) (output_buffer_callback));
        jpeg_start_compress (&cinfo, TRUE);
        JSAMPROW    pRowArray[1];
        for (int i = 0; i < m_iRowNumber; i++)
        {
            pRowArray[0] = (JSAMPROW) p;
            jpeg_write_scanlines (&cinfo, pRowArray, 1);
            p += (m_iRowWidth);
            if (compressedsize > m_max_file_size)
            {
                compressedsize = 0;
                bRedo = 1;
            }
        }
        jpeg_finish_compress (&cinfo);
        jpeg_destroy_compress (&cinfo);
        iQuality -= 10;
        if (iQuality == 0)
        {
            compressedsize = 0;
            return;
        }
    } while (bRedo);
    return;
}
Ejemplo n.º 6
0
bool JpegEncoder::write( const Mat& img, const std::vector<int>& params )
{
    m_last_error.clear();

    struct fileWrapper
    {
        FILE* f;

        fileWrapper() : f(0) {}
        ~fileWrapper() { if(f) fclose(f); }
    };
    volatile bool result = false;
    fileWrapper fw;
    int width = img.cols, height = img.rows;

    std::vector<uchar> out_buf(1 << 12);
    AutoBuffer<uchar> _buffer;
    uchar* buffer;

    struct jpeg_compress_struct cinfo;
    JpegErrorMgr jerr;
    JpegDestination dest;

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

    if( !m_buf )
    {
        fw.f = fopen( m_filename.c_str(), "wb" );
        if( !fw.f )
            goto _exit_;
        jpeg_stdio_dest( &cinfo, fw.f );
    }
    else
    {
        dest.dst = m_buf;
        dest.buf = &out_buf;

        jpeg_buffer_dest( &cinfo, &dest );

        dest.pub.next_output_byte = &out_buf[0];
        dest.pub.free_in_buffer = out_buf.size();
    }

    if( setjmp( jerr.setjmp_buffer ) == 0 )
    {
        cinfo.image_width = width;
        cinfo.image_height = height;

        int _channels = img.channels();
        int channels = _channels > 1 ? 3 : 1;
        cinfo.input_components = channels;
        cinfo.in_color_space = channels > 1 ? JCS_RGB : JCS_GRAYSCALE;

        int quality = 95;
        int progressive = 0;
        int optimize = 0;
        int rst_interval = 0;
        int luma_quality = -1;
        int chroma_quality = -1;

        for( size_t i = 0; i < params.size(); i += 2 )
        {
            if( params[i] == CV_IMWRITE_JPEG_QUALITY )
            {
                quality = params[i+1];
                quality = MIN(MAX(quality, 0), 100);
            }

            if( params[i] == CV_IMWRITE_JPEG_PROGRESSIVE )
            {
                progressive = params[i+1];
            }

            if( params[i] == CV_IMWRITE_JPEG_OPTIMIZE )
            {
                optimize = params[i+1];
            }

            if( params[i] == CV_IMWRITE_JPEG_LUMA_QUALITY )
            {
                if (params[i+1] >= 0)
                {
                    luma_quality = MIN(MAX(params[i+1], 0), 100);

                    quality = luma_quality;

                    if (chroma_quality < 0)
                    {
                        chroma_quality = luma_quality;
                    }
                }
            }

            if( params[i] == CV_IMWRITE_JPEG_CHROMA_QUALITY )
            {
                if (params[i+1] >= 0)
                {
                    chroma_quality = MIN(MAX(params[i+1], 0), 100);
                }
            }

            if( params[i] == CV_IMWRITE_JPEG_RST_INTERVAL )
            {
                rst_interval = params[i+1];
                rst_interval = MIN(MAX(rst_interval, 0), 65535L);
            }
        }

        jpeg_set_defaults( &cinfo );
        cinfo.restart_interval = rst_interval;

        jpeg_set_quality( &cinfo, quality,
                          TRUE /* limit to baseline-JPEG values */ );
        if( progressive )
            jpeg_simple_progression( &cinfo );
        if( optimize )
            cinfo.optimize_coding = TRUE;

#if JPEG_LIB_VERSION >= 70
        if (luma_quality >= 0 && chroma_quality >= 0)
        {
            cinfo.q_scale_factor[0] = jpeg_quality_scaling(luma_quality);
            cinfo.q_scale_factor[1] = jpeg_quality_scaling(chroma_quality);
            if ( luma_quality != chroma_quality )
            {
                /* disable subsampling - ref. Libjpeg.txt */
                cinfo.comp_info[0].v_samp_factor = 1;
                cinfo.comp_info[0].h_samp_factor = 1;
                cinfo.comp_info[1].v_samp_factor = 1;
                cinfo.comp_info[1].h_samp_factor = 1;
            }
            jpeg_default_qtables( &cinfo, TRUE );
        }
#endif // #if JPEG_LIB_VERSION >= 70

        jpeg_start_compress( &cinfo, TRUE );

        if( channels > 1 )
            _buffer.allocate(width*channels);
        buffer = _buffer;

        for( int y = 0; y < height; y++ )
        {
            uchar *data = img.data + img.step*y, *ptr = data;

            if( _channels == 3 )
            {
                icvCvt_BGR2RGB_8u_C3R( data, 0, buffer, 0, cvSize(width,1) );
                ptr = buffer;
            }
            else if( _channels == 4 )
            {
                icvCvt_BGRA2BGR_8u_C4C3R( data, 0, buffer, 0, cvSize(width,1), 2 );
                ptr = buffer;
            }

            jpeg_write_scanlines( &cinfo, &ptr, 1 );
        }

        jpeg_finish_compress( &cinfo );
        result = true;
    }

_exit_:

    if(!result)
    {
        char jmsg_buf[JMSG_LENGTH_MAX];
        jerr.pub.format_message((j_common_ptr)&cinfo, jmsg_buf);
        m_last_error = jmsg_buf;
    }

    jpeg_destroy_compress( &cinfo );

    return result;
}
static int
jpeg_image_control(ErlDrvData handle, unsigned int command, 
		   char* buf, int count, 
		   char** res, int res_size)
{
  JSAMPROW row;
  ErlDrvBinary* bin = 0;

  switch (command) {
  case 0: {			/* Read */
    struct jpeg_decompress_struct cinfo;
    int row_stride;		/* physical row width in output buffer */
    unsigned char* rbuf;
    struct my_error_mgr jerr;

    cinfo.err = jpeg_std_error(&jerr.pub);
    jerr.pub.error_exit = my_error_exit;

    /* Establish the setjmp return context for my_error_exit to use. */
    if (setjmp(jerr.setjmp_buffer)) {
      /* If we get here, the JPEG code has signaled an error.
       * We need to clean up the JPEG object, close the input file, and return.
       */
      char buffer[JMSG_LENGTH_MAX];

      /* Create the message */
      (cinfo.err->format_message)((j_common_ptr) &cinfo, buffer);
      jpeg_destroy_decompress(&cinfo);

      bin = driver_alloc_binary(4+strlen(buffer));
      rbuf = bin->orig_bytes;
      ((unsigned *)rbuf)[0] = 0;
      rbuf += 4;
      memcpy(rbuf, buffer, strlen(buffer));
      *res = (void *) bin;
      return 0;
    }

    jpeg_create_decompress(&cinfo);
    jpeg_buffer_src(&cinfo, buf, count);
    (void) jpeg_read_header(&cinfo, TRUE);
    (void) jpeg_start_decompress(&cinfo);

    row_stride = cinfo.output_width * cinfo.output_components;
    res_size = row_stride * cinfo.output_height;
    bin = driver_alloc_binary(res_size+12);
    rbuf = bin->orig_bytes;
    ((unsigned *)rbuf)[0] = cinfo.output_width;
    ((unsigned *)rbuf)[1] = cinfo.output_height;
    ((unsigned *)rbuf)[2] = cinfo.output_components;
    rbuf += 12;
    while (cinfo.output_scanline < cinfo.output_height) {
      row = (JSAMPROW) rbuf;
      (void) jpeg_read_scanlines(&cinfo, &row, 1);
      rbuf += row_stride;
    }
    (void) jpeg_finish_decompress(&cinfo);
    *res = (void *) bin;
    return 0;
  }
  case 1: {			/* Write */
    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr jerr;
    int row_stride;		/* physical row width */

    bin = driver_alloc_binary(count);

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

    jpeg_buffer_dest(&cinfo, bin);
    cinfo.image_width = ((unsigned *)buf)[0];
    cinfo.image_height = ((unsigned *)buf)[1];
    cinfo.input_components = ((unsigned *)buf)[2];
    cinfo.in_color_space = JCS_RGB;
    jpeg_set_defaults(&cinfo);
    buf += 12;
    count -= 12;

    jpeg_start_compress(&cinfo, TRUE);
    row_stride = cinfo.input_components * cinfo.image_width;
        
    while (cinfo.next_scanline < cinfo.image_height) {
      row = (JSAMPROW) buf;
      (void) jpeg_write_scanlines(&cinfo, &row, 1);
      buf += row_stride;
    }

    jpeg_finish_compress(&cinfo);
    bin = jpeg_buffer_dest_get_bin(&cinfo);
    jpeg_destroy_compress(&cinfo);
    *res = (void *) bin;
    return 0;
  }
  default:
    return -1;			/* Error return, throws exception in erlang */
  }
}
Ejemplo n.º 8
0
csPtr<iDataBuffer> csJPGImageIO::Save(iImage *Image,
    iImageIO::FileFormatDescription*, const char* extraoptions)
{
  int format = Image->GetFormat ();
  switch (format & CS_IMGFMT_MASK)
  {
    case CS_IMGFMT_TRUECOLOR:
      break;
    default:
      // unknown format
      return 0;
  } /* endswitch */

  // compression options
  int quality = 80;
  bool progressive = false;

  /*
     parse output options.
     options are a comma-separated list and can be either
     'option' or 'option=value'.

     supported options:
       compress=#   image compression, 0..100 higher values give smaller files
		    but uglier results.
       progressive  progressive encoding.

     examples:
       compress=50
       progressive,compress=30
   */
  csImageLoaderOptionsParser optparser (extraoptions);
  optparser.GetBool ("progressive", progressive);
  if (optparser.GetInt ("compress", quality))
  {
    quality = 100 - quality;
    if (quality < 0) quality = 0;
    if (quality > 100) quality = 100;
  }

  JSAMPLE* volatile row = 0;
  struct jpg_datastore ds;
  struct jpeg_compress_struct cinfo;
  struct my_error_mgr jerr;
  cinfo.err = jpeg_std_error (&jerr.pub);
  jerr.pub.error_exit = my_error_exit;

  if (setjmp (jerr.setjmp_buffer))
  {
    delete [] row;
    char errmsg [256];
    cinfo.err->format_message ((jpeg_common_struct *)&cinfo, errmsg);
    Report (object_reg, CS_REPORTER_SEVERITY_WARNING,
      "%s\n", errmsg);
    jpeg_destroy_compress (&cinfo);
    return 0;
  }

  jpeg_create_compress (&cinfo);
  jpeg_buffer_dest (&cinfo, &ds);

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

  jpeg_set_defaults (&cinfo);
  jpeg_set_quality (&cinfo, quality, true);
  if (progressive) jpeg_simple_progression (&cinfo);
  jpeg_start_compress (&cinfo, true);

  JSAMPROW row_pointer[1];
  JSAMPLE *image = (JSAMPLE*)csPackRGB::PackRGBpixelToRGB
    ((csRGBpixel*)Image->GetImageData (),
     Image->GetWidth () * Image->GetHeight ());
  row_pointer[0] = (JSAMPLE*)&row[0];

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

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

  delete[] image;
  delete [] row;

  /* make the iDataBuffer to return */
  csDataBuffer *db = new csDataBuffer (ds.len);
  memcpy (db->GetData (), ds.data, ds.len);

  return csPtr<iDataBuffer> (db);
}