00001 // Filename: pnmFileTypeJPGWriter.cxx 00002 // Created by: mike (19Jun00) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved 00008 // 00009 // All use of this software is subject to the terms of the Panda 3d 00010 // Software license. You should have received a copy of this license 00011 // along with this source code; you will also find a current copy of 00012 // the license at http://www.panda3d.org/license.txt . 00013 // 00014 // To contact the maintainers of this program write to 00015 // panda3d@yahoogroups.com . 00016 // 00017 //////////////////////////////////////////////////////////////////// 00018 00019 #include "pnmFileTypeJPG.h" 00020 #include "config_pnmimagetypes.h" 00021 00022 #include "pnmImage.h" 00023 #include "pnmWriter.h" 00024 00025 00026 // 00027 // The following bit of code, for setting up jpeg_ostream_src(), was 00028 // lifted from jpeglib, and modified to work with ostream instead of 00029 // stdio. 00030 // 00031 00032 /* 00033 * jdatadst.c 00034 * 00035 * Copyright (C) 1994-1996, Thomas G. Lane. 00036 * This file is part of the Independent JPEG Group's software. 00037 * For conditions of distribution and use, see the accompanying README file. 00038 * 00039 * This file contains compression data destination routines for the case of 00040 * emitting JPEG data to a file (or any stdio stream). While these routines 00041 * are sufficient for most applications, some will want to use a different 00042 * destination manager. 00043 * IMPORTANT: we assume that fwrite() will correctly transcribe an array of 00044 * JOCTETs into 8-bit-wide elements on external storage. If char is wider 00045 * than 8 bits on your machine, you may need to do some tweaking. 00046 */ 00047 00048 /* this is not a core library module, so it doesn't define JPEG_INTERNALS */ 00049 extern "C" { 00050 #include <jpeglib.h> 00051 #include <jerror.h> 00052 } 00053 00054 00055 /* Expanded data destination object for stdio output */ 00056 00057 typedef struct { 00058 struct jpeg_destination_mgr pub; /* public fields */ 00059 00060 ostream * outfile; /* target stream */ 00061 JOCTET * buffer; /* start of buffer */ 00062 } my_destination_mgr; 00063 00064 typedef my_destination_mgr * my_dest_ptr; 00065 00066 #define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */ 00067 00068 00069 /* 00070 * Initialize destination --- called by jpeg_start_compress 00071 * before any data is actually written. 00072 */ 00073 00074 METHODDEF(void) 00075 init_destination (j_compress_ptr cinfo) 00076 { 00077 my_dest_ptr dest = (my_dest_ptr) cinfo->dest; 00078 00079 /* Allocate the output buffer --- it will be released when done with image */ 00080 dest->buffer = (JOCTET *) 00081 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, 00082 OUTPUT_BUF_SIZE * sizeof(JOCTET)); 00083 00084 dest->pub.next_output_byte = dest->buffer; 00085 dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; 00086 } 00087 00088 00089 /* 00090 * Empty the output buffer --- called whenever buffer fills up. 00091 * 00092 * In typical applications, this should write the entire output buffer 00093 * (ignoring the current state of next_output_byte & free_in_buffer), 00094 * reset the pointer & count to the start of the buffer, and return TRUE 00095 * indicating that the buffer has been dumped. 00096 * 00097 * In applications that need to be able to suspend compression due to output 00098 * overrun, a FALSE return indicates that the buffer cannot be emptied now. 00099 * In this situation, the compressor will return to its caller (possibly with 00100 * an indication that it has not accepted all the supplied scanlines). The 00101 * application should resume compression after it has made more room in the 00102 * output buffer. Note that there are substantial restrictions on the use of 00103 * suspension --- see the documentation. 00104 * 00105 * When suspending, the compressor will back up to a convenient restart point 00106 * (typically the start of the current MCU). next_output_byte & free_in_buffer 00107 * indicate where the restart point will be if the current call returns FALSE. 00108 * Data beyond this point will be regenerated after resumption, so do not 00109 * write it out when emptying the buffer externally. 00110 */ 00111 00112 METHODDEF(boolean) 00113 empty_output_buffer (j_compress_ptr cinfo) 00114 { 00115 my_dest_ptr dest = (my_dest_ptr) cinfo->dest; 00116 00117 if (!dest->outfile->write((const char *)dest->buffer, OUTPUT_BUF_SIZE)) 00118 ERREXIT(cinfo, JERR_FILE_WRITE); 00119 00120 dest->pub.next_output_byte = dest->buffer; 00121 dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; 00122 00123 return TRUE; 00124 } 00125 00126 00127 /* 00128 * Terminate destination --- called by jpeg_finish_compress 00129 * after all data has been written. Usually needs to flush buffer. 00130 * 00131 * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding 00132 * application must deal with any cleanup that should happen even 00133 * for error exit. 00134 */ 00135 00136 METHODDEF(void) 00137 term_destination (j_compress_ptr cinfo) 00138 { 00139 my_dest_ptr dest = (my_dest_ptr) cinfo->dest; 00140 size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; 00141 00142 /* Write any data remaining in the buffer */ 00143 if (datacount > 0) { 00144 if (!dest->outfile->write((const char *)dest->buffer, datacount)) 00145 ERREXIT(cinfo, JERR_FILE_WRITE); 00146 } 00147 dest->outfile->flush(); 00148 /* Make sure we wrote the output file OK */ 00149 if (dest->outfile->fail()) 00150 ERREXIT(cinfo, JERR_FILE_WRITE); 00151 } 00152 00153 00154 /* 00155 * Prepare for output to a stdio stream. 00156 * The caller must have already opened the stream, and is responsible 00157 * for closing it after finishing compression. 00158 */ 00159 00160 GLOBAL(void) 00161 jpeg_ostream_dest (j_compress_ptr cinfo, ostream * outfile) 00162 { 00163 my_dest_ptr dest; 00164 00165 /* The destination object is made permanent so that multiple JPEG images 00166 * can be written to the same file without re-executing jpeg_stdio_dest. 00167 * This makes it dangerous to use this manager and a different destination 00168 * manager serially with the same JPEG object, because their private object 00169 * sizes may be different. Caveat programmer. 00170 */ 00171 if (cinfo->dest == NULL) { /* first time for this JPEG object? */ 00172 cinfo->dest = (struct jpeg_destination_mgr *) 00173 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, 00174 sizeof(my_destination_mgr)); 00175 } 00176 00177 dest = (my_dest_ptr) cinfo->dest; 00178 dest->pub.init_destination = init_destination; 00179 dest->pub.empty_output_buffer = empty_output_buffer; 00180 dest->pub.term_destination = term_destination; 00181 dest->outfile = outfile; 00182 } 00183 00184 00185 00186 // 00187 // The rest of the code in this file is new to Panda. 00188 // 00189 00190 //////////////////////////////////////////////////////////////////// 00191 // Function: PNMFileTypeJPG::Writer::Constructor 00192 // Access: Public 00193 // Description: 00194 //////////////////////////////////////////////////////////////////// 00195 PNMFileTypeJPG::Writer:: 00196 Writer(PNMFileType *type, ostream *file, bool owns_file) : 00197 PNMWriter(type, file, owns_file) 00198 { 00199 } 00200 00201 00202 //////////////////////////////////////////////////////////////////// 00203 // Function: PNMFileTypeJPG::Writer::write_data 00204 // Access: Public, Virtual 00205 // Description: Writes out an entire image all at once, including the 00206 // header, based on the image data stored in the given 00207 // _x_size * _y_size array and alpha pointers. (If the 00208 // image type has no alpha channel, alpha is ignored.) 00209 // Returns the number of rows correctly written. 00210 // 00211 // It is the user's responsibility to fill in the header 00212 // data via calls to set_x_size(), set_num_channels(), 00213 // etc., or copy_header_from(), before calling 00214 // write_data(). 00215 // 00216 // It is important to delete the PNMWriter class after 00217 // successfully writing the data. Failing to do this 00218 // may result in some data not getting flushed! 00219 // 00220 // Derived classes need not override this if they 00221 // instead provide supports_streaming() and write_row(), 00222 // below. 00223 //////////////////////////////////////////////////////////////////// 00224 int PNMFileTypeJPG::Writer:: 00225 write_data(xel *array, xelval *) { 00226 if (_y_size<=0 || _x_size<=0) { 00227 return 0; 00228 } 00229 00230 /* This struct contains the JPEG compression parameters and pointers to 00231 * working space (which is allocated as needed by the JPEG library). 00232 * It is possible to have several such structures, representing multiple 00233 * compression/decompression processes, in existence at once. We refer 00234 * to any one struct (and its associated working data) as a "JPEG object". 00235 */ 00236 struct jpeg_compress_struct cinfo; 00237 /* This struct represents a JPEG error handler. It is declared separately 00238 * because applications often want to supply a specialized error handler 00239 * (see the second half of this file for an example). But here we just 00240 * take the easy way out and use the standard error handler, which will 00241 * print a message on stderr and call exit() if compression fails. 00242 * Note that this struct must live as long as the main JPEG parameter 00243 * struct, to avoid dangling-pointer problems. 00244 */ 00245 struct jpeg_error_mgr jerr; 00246 /* More stuff */ 00247 JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ 00248 int row_stride; /* physical row width in image buffer */ 00249 00250 /* Step 1: allocate and initialize JPEG compression object */ 00251 00252 /* We have to set up the error handler first, in case the initialization 00253 * step fails. (Unlikely, but it could happen if you are out of memory.) 00254 * This routine fills in the contents of struct jerr, and returns jerr's 00255 * address which we place into the link field in cinfo. 00256 */ 00257 cinfo.err = jpeg_std_error(&jerr); 00258 00259 /* Now we can initialize the JPEG compression object. */ 00260 jpeg_create_compress(&cinfo); 00261 00262 /* Step 2: specify data destination (eg, a file) */ 00263 /* Note: steps 2 and 3 can be done in either order. */ 00264 jpeg_ostream_dest(&cinfo, _file); 00265 00266 /* Step 3: set parameters for compression */ 00267 00268 /* First we supply a description of the input image. 00269 * Four fields of the cinfo struct must be filled in: 00270 */ 00271 cinfo.image_width = _x_size; /* image width and height, in pixels */ 00272 cinfo.image_height = _y_size; 00273 if (is_grayscale()) { 00274 cinfo.input_components = 1; 00275 cinfo.in_color_space = JCS_GRAYSCALE; 00276 } else { 00277 cinfo.input_components = 3; 00278 cinfo.in_color_space = JCS_RGB; 00279 } 00280 /* Now use the library's routine to set default compression parameters. 00281 * (You must set at least cinfo.in_color_space before calling this, 00282 * since the defaults depend on the source color space.) 00283 */ 00284 jpeg_set_defaults(&cinfo); 00285 /* Now you can set any non-default parameters you wish to. 00286 * Here we just illustrate the use of quality (quantization table) scaling: 00287 */ 00288 jpeg_set_quality(&cinfo, jpeg_quality, TRUE /* limit to baseline-JPEG values */); 00289 00290 /* Step 4: Start compressor */ 00291 00292 /* TRUE ensures that we will write a complete interchange-JPEG file. 00293 * Pass TRUE unless you are very sure of what you're doing. 00294 */ 00295 jpeg_start_compress(&cinfo, TRUE); 00296 00297 /* Step 5: while (scan lines remain to be written) */ 00298 /* jpeg_write_scanlines(...); */ 00299 00300 /* Here we use the library's state variable cinfo.next_scanline as the 00301 * loop counter, so that we don't have to keep track ourselves. 00302 * To keep things simple, we pass one scanline per call; you can pass 00303 * more if you wish, though. 00304 */ 00305 row_stride = _x_size * cinfo.input_components; /* JSAMPLEs per row in image_buffer */ 00306 00307 int x = 0; 00308 JSAMPROW row = new JSAMPLE[row_stride]; 00309 while (cinfo.next_scanline < cinfo.image_height) { 00310 /* jpeg_write_scanlines expects an array of pointers to scanlines. 00311 * Here the array is only one element long, but you could pass 00312 * more than one scanline at a time if that's more convenient. 00313 */ 00314 for (int i = 0; i < row_stride; i += cinfo.input_components) { 00315 if (cinfo.input_components == 1) { 00316 row[i] = (JSAMPLE)(MAXJSAMPLE * PPM_GETB(array[x])/_maxval); 00317 } else { 00318 row[i] = (JSAMPLE)(MAXJSAMPLE * PPM_GETR(array[x])/_maxval); 00319 row[i+1] = (JSAMPLE)(MAXJSAMPLE * PPM_GETG(array[x])/_maxval); 00320 row[i+2] = (JSAMPLE)(MAXJSAMPLE * PPM_GETB(array[x])/_maxval); 00321 } 00322 x++; 00323 } 00324 //row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride]; 00325 //(void) jpeg_write_scanlines(&cinfo, row_pointer, 1); 00326 row_pointer[0] = row; 00327 (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); 00328 } 00329 delete row; 00330 00331 /* Step 6: Finish compression */ 00332 00333 jpeg_finish_compress(&cinfo); 00334 00335 /* Step 7: release JPEG compression object */ 00336 00337 /* This is an important step since it will release a good deal of memory. */ 00338 jpeg_destroy_compress(&cinfo); 00339 00340 return _y_size; 00341 }