/*
* jpeg_write.c
*
* JPEG_WRITE(JPEGOBJ,FILENAME)
*
* Reads JPEGOBJ, a Matlab struct containing the JPEG header,
* quantization tables and the DCT coefficients (as returned by JPEG_READ),
* and writes the information into a JPEG file with the name FILENAME.
*
* This software is based in part on the work of the Independent JPEG Group.
* In order to compile, you must first build IJG's JPEG Tools code library,
* available at ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz.
*
* Phil Sallee, Surya De 6/2003
*
* Copyright (c) 2003 The Regents of the University of California.
* All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for educational, research and non-profit purposes,
* without fee, and without a written agreement is hereby granted,
* provided that the above copyright notice, this paragraph and the
* following three paragraphs appear in all copies.
*
* Permission to incorporate this software into commercial products may
* be obtained by contacting the University of California. Contact Jo Clare
* Peterman, University of California, 428 Mrak Hall, Davis, CA, 95616.
*
* This software program and documentation are copyrighted by The Regents
* of the University of California. The software program and
* documentation are supplied "as is", without any accompanying services
* from The Regents. The Regents does not warrant that the operation of
* the program will be uninterrupted or error-free. The end-user
* understands that the program was developed for research purposes and
* is advised not to rely exclusively on the program for any reason.
*
* IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
* FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
* INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND
* ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF
* CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE
* MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <jerror.h>
#include <jpeglib.h>
#include <setjmp.h>
#include <jpegint.h>
#include "mex.h"
/* We need to create our own error handler so that we can override the
* default handler in case a fatal error occurs. The standard error_exit
* method calls exit() which doesn't clean things up properly and also
* exits Matlab. This is described in the example.c routine provided in
* the IJG's code library.
*/
struct my_error_mgr {
struct jpeg_error_mgr pub; /* "public" fields */
jmp_buf setjmp_buffer; /* for return to caller */
};
/* The default output_message routine causes a seg fault in Matlab,
* at least on Windows. Its generally used to emit warnings, since
* fatal errors call the error_exit routine, so we emit a Matlab
* warning instead. If desired, warnings can be turned off by the
* user with "warnings off". -- PAS 10/03
*/
METHODDEF(void)
my_output_message (j_common_ptr cinfo)
{
char buffer[JMSG_LENGTH_MAX];
/* Create the message */
(*cinfo->err->format_message) (cinfo, buffer);
mexWarnMsgTxt(buffer);
}
typedef struct my_error_mgr * my_error_ptr;
METHODDEF(void)
my_error_exit (j_common_ptr cinfo)
{
char buffer[JMSG_LENGTH_MAX];
/* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
my_error_ptr myerr = (my_error_ptr) cinfo->err;
/* create the message */
(*cinfo->err->format_message) (cinfo, buffer);
printf("Error: %s\n",buffer);
/* return control to the setjmp point */
longjmp(myerr->setjmp_buffer, 1);
}
/* mex function */
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
struct jpeg_compress_struct cinfo;
struct my_error_mgr jerr;
const mxArray *mxjpeg_obj;
mxArray *mxcoef_arrays,*mxhuff_tables,*mxcomp_info,*mxtemp,
*mxquant_tables,*mxcomments;
char *filename,*comment;
int strlen,c_height,c_width,ci,i,j,n,t;
FILE *outfile;
jvirt_barray_ptr *coef_arrays = NULL;
jpeg_component_info *compptr;
JDIMENSION blk_x,blk_y;
JBLOCKARRAY buffer;
JCOEFPTR bufptr;
double *mp, *mptop;
/* check the input values */
if (nrhs != 2) mexErrMsgTxt("Two input arguments required.");
/* check the output values */
if (nlhs != 0) mexErrMsgTxt("Too many output arguments.");
if (mxIsChar(prhs[1]) != 1) mexErrMsgTxt("Filename must be a string.");
/* get filename */
strlen = mxGetM(prhs[1])*mxGetN(prhs[1]) + 1;
filename = mxCalloc(strlen, sizeof(char));
mxGetString(prhs[1],filename,strlen);
/* open the output file*/
if ((outfile = fopen(filename, "wb")) == NULL)
mexErrMsgTxt("Can't open file.");
/* set up the normal JPEG error routines, then override error_exit. */
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))
{
jpeg_destroy_compress(&cinfo);
fclose(outfile);
mexErrMsgTxt("Error writing to file.");
}
/* set the input */
mxjpeg_obj = prhs[0];
/* initialize JPEG decompression object */
jpeg_create_compress(&cinfo);
/* write the output file */
jpeg_stdio_dest(&cinfo, outfile);
/* Set the compression object with our parameters */
cinfo.image_width =
(unsigned int) mxGetScalar(mxGetField(mxjpeg_obj,0,"image_width"));
cinfo.image_height =
(unsigned int) mxGetScalar(mxGetField(mxjpeg_obj,0,"image_height"));
cinfo.input_components =
(int) mxGetScalar(mxGetField(mxjpeg_obj,0,"image_components"));
cinfo.in_color_space =
(int) mxGetScalar(mxGetField(mxjpeg_obj,0,"image_color_space"));
/* set the compression object with default parameters */
jpeg_set_defaults(&cinfo);
cinfo.optimize_coding =
(unsigned char) mxGetScalar(mxGetField(mxjpeg_obj,0,"optimize_coding"));
cinfo.num_components =
(int) mxGetScalar(mxGetField(mxjpeg_obj,0,"jpeg_components"));
cinfo.jpeg_color_space =
(int) mxGetScalar(mxGetField(mxjpeg_obj,0,"jpeg_color_space"));
/* basic support for writing progressive mode JPEG */
if (mxGetField(mxjpeg_obj,0,"progressive_mode")) {
if ((int) mxGetScalar(mxGetField(mxjpeg_obj,0,"progressive_mode")))
jpeg_simple_progression(&cinfo);
}
/* obtain the component array from the jpeg object */
mxcomp_info = mxGetField(mxjpeg_obj,0,"comp_info");
/* copy component information into cinfo from jpeg_obj*/
for (ci = 0; ci < cinfo.num_components; ci++)
{
cinfo.comp_info[ci].component_id =
(int) mxGetScalar(mxGetField(mxcomp_info,ci,"component_id"));
cinfo.comp_info[ci].h_samp_factor =
(int) mxGetScalar(mxGetField(mxcomp_info,ci,"h_samp_factor"));
cinfo.comp_info[ci].v_samp_factor =
(int) mxGetScalar(mxGetField(mxcomp_info,ci,"v_samp_factor"));
cinfo.comp_info[ci].quant_tbl_no =
(int) mxGetScalar(mxGetField(mxcomp_info,ci,"quant_tbl_no"))-1;
cinfo.comp_info[ci].ac_tbl_no =
(int) mxGetScalar(mxGetField(mxcomp_info,ci,"ac_tbl_no"))-1;
cinfo.comp_info[ci].dc_tbl_no =
(int) mxGetScalar(mxGetField(mxcomp_info,ci,"dc_tbl_no"))-1;
}
/* request virtual block arrays */
mxcoef_arrays = mxGetField(mxjpeg_obj, 0, "coef_arrays");
coef_arrays = (jvirt_barray_ptr *)
(cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_IMAGE,
sizeof(jvirt_barray_ptr) * cinfo.num_components);
for (ci = 0; ci < cinfo.num_components; ci++)
{
compptr = cinfo.comp_info + ci;
c_height = mxGetM(mxGetCell(mxcoef_arrays,ci));
c_width = mxGetN(mxGetCell(mxcoef_arrays,ci));
comp