Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/pnmimagetypes/pnmFileTypeSGIWriter.cxx

Go to the documentation of this file.
00001 // Filename: pnmFileTypeSGIWriter.cxx
00002 // Created by:  drose (17Jun00)
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 "pnmFileTypeSGI.h"
00020 #include "config_pnmimagetypes.h"
00021 #include "sgi.h"
00022 
00023 #include "pnmImage.h"
00024 #include "pnmWriter.h"
00025 
00026 // Much code in this file originally came from from Netpbm,
00027 // specifically pnmtosgi.c.  It has since been fairly heavily
00028 // modified.
00029 
00030 /* pnmtosgi.c - convert portable anymap to SGI image
00031 **
00032 ** Copyright (C) 1994 by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
00033 **
00034 ** Based on the SGI image description v0.9 by Paul Haeberli (paul@sgi.comp)
00035 ** Available via ftp from sgi.com:graphics/SGIIMAGESPEC
00036 **
00037 ** Permission to use, copy, modify, and distribute this software and its
00038 ** documentation for any purpose and without fee is hereby granted, provided
00039 ** that the above copyright notice appear in all copies and that both that
00040 ** copyright notice and this permission notice appear in supporting
00041 ** documentation.  This software is provided "as is" without express or
00042 ** implied warranty.
00043 **
00044 ** 29Jan94: first version
00045 */
00046 
00047 
00048 
00049 #define WORSTCOMPR(x)   (2*(x) + 2)
00050 
00051 
00052 #define MAXVAL_BYTE     255
00053 #define MAXVAL_WORD     65535
00054 
00055 inline void
00056 put_byte(ostream *out_file, unsigned char b) {
00057   out_file->put(b);
00058 }
00059 
00060 static void
00061 put_big_short(ostream *out_file, short s) {
00062     if ( pm_writebigshort( out_file, s ) == -1 )
00063         pm_error( "write error" );
00064 }
00065 
00066 
00067 static void
00068 put_big_long(ostream *out_file, long l) {
00069     if ( pm_writebiglong( out_file, l ) == -1 )
00070         pm_error( "write error" );
00071 }
00072 
00073 
00074 static void
00075 put_short_as_byte(ostream *out_file, short s) {
00076     put_byte(out_file, (unsigned char)s);
00077 }
00078 
00079 
00080 ////////////////////////////////////////////////////////////////////
00081 //     Function: PNMFileTypeSGI::Writer::Constructor
00082 //       Access: Public
00083 //  Description:
00084 ////////////////////////////////////////////////////////////////////
00085 PNMFileTypeSGI::Writer::
00086 Writer(PNMFileType *type, ostream *file, bool owns_file) :
00087   PNMWriter(type, file, owns_file)
00088 {
00089 }
00090 
00091 ////////////////////////////////////////////////////////////////////
00092 //     Function: PNMFileTypeSGI::Writer::Destructor
00093 //       Access: Public, Virtual
00094 //  Description:
00095 ////////////////////////////////////////////////////////////////////
00096 PNMFileTypeSGI::Writer::
00097 ~Writer() {
00098   if (table!=NULL) {
00099     // Rewrite the table with the correct values in it.
00100     _file->seekp(table_start);
00101     write_table();
00102     delete[] table;
00103   }
00104 }
00105 
00106 ////////////////////////////////////////////////////////////////////
00107 //     Function: PNMFileTypeSGI::Writer::supports_write_row
00108 //       Access: Public, Virtual
00109 //  Description: Returns true if this particular PNMWriter supports a
00110 //               streaming interface to writing the data: that is, it
00111 //               is capable of writing the image one row at a time,
00112 //               via repeated calls to write_row().  Returns false if
00113 //               the only way to write from this file is all at once,
00114 //               via write_data().
00115 ////////////////////////////////////////////////////////////////////
00116 bool PNMFileTypeSGI::Writer::
00117 supports_write_row() const {
00118   return true;
00119 }
00120 
00121 ////////////////////////////////////////////////////////////////////
00122 //     Function: PNMFileTypeSGI::Writer::write_header
00123 //       Access: Public, Virtual
00124 //  Description: If supports_write_row(), above, returns true, this
00125 //               function may be called to write out the image header
00126 //               in preparation to writing out the image data one row
00127 //               at a time.  Returns true if the header is
00128 //               successfully written, false if there is an error.
00129 //
00130 //               It is the user's responsibility to fill in the header
00131 //               data via calls to set_x_size(), set_num_channels(),
00132 //               etc., or copy_header_from(), before calling
00133 //               write_header().
00134 ////////////////////////////////////////////////////////////////////
00135 bool PNMFileTypeSGI::Writer::
00136 write_header() {
00137   table = NULL;
00138 
00139   switch (_num_channels) {
00140   case 1:
00141     dimensions = 2;
00142     break;
00143 
00144   case 2:
00145   case 3:
00146   case 4:
00147     dimensions = 3;
00148     break;
00149 
00150   default:
00151     nassertr(false, false);
00152   }
00153 
00154   // For some reason, we have problems with SGI image files whose pixmax value
00155   // is not 255 or 65535.  So, we'll round up when writing.
00156   if( _maxval <= MAXVAL_BYTE ) {
00157     bpc = 1;
00158     new_maxval = MAXVAL_BYTE;
00159   } else if( _maxval <= MAXVAL_WORD ) {
00160     bpc = 2;
00161     new_maxval = MAXVAL_WORD;
00162   } else {
00163     return false;
00164   }
00165 
00166   if( sgi_storage_type != STORAGE_VERBATIM ) {
00167     table = new TabEntry[_num_channels * _y_size];
00168     memset(table, 0, _num_channels * _y_size * sizeof(TabEntry));
00169   }
00170 
00171   write_rgb_header(sgi_imagename.c_str());
00172 
00173   if (table!=NULL) {
00174     table_start = _file->tellp();
00175 
00176     // The first time we write the table, it has zeroes.  We'll correct
00177     // this later.
00178     write_table();
00179   }
00180 
00181   current_row = _y_size - 1;
00182   return true;
00183 }
00184 
00185 
00186 ////////////////////////////////////////////////////////////////////
00187 //     Function: PNMFileTypeSGI::Writer::write_row
00188 //       Access: Public, Virtual
00189 //  Description: If supports_write_row(), above, returns true, this
00190 //               function may be called repeatedly to write the image,
00191 //               one horizontal row at a time, beginning from the top.
00192 //               Returns true if the row is successfully written,
00193 //               false if there is an error.
00194 //
00195 //               You must first call write_header() before writing the
00196 //               individual rows.  It is also important to delete the
00197 //               PNMWriter class after successfully writing the last
00198 //               row.  Failing to do this may result in some data not
00199 //               getting flushed!
00200 ////////////////////////////////////////////////////////////////////
00201 bool PNMFileTypeSGI::Writer::
00202 write_row(xel *row_data, xelval *alpha_data) {
00203   ScanLine channel[4];
00204 
00205   build_scanline(channel, row_data, alpha_data);
00206 
00207   if( bpc == 1 )
00208     write_channels(channel, put_short_as_byte);
00209   else
00210     write_channels(channel, put_big_short);
00211 
00212   for (int i = 0; i < _num_channels; i++) {
00213     delete[] channel[i].data;
00214   }
00215 
00216   current_row--;
00217   return true;
00218 }
00219 
00220 
00221 void PNMFileTypeSGI::Writer::
00222 write_rgb_header(const char *imagename) {
00223     int i;
00224 
00225     put_big_short(_file, SGI_MAGIC);
00226     put_byte(_file, sgi_storage_type);
00227     put_byte(_file, (char)bpc);
00228     put_big_short(_file, dimensions);
00229     put_big_short(_file, _x_size);
00230     put_big_short(_file, _y_size);
00231     put_big_short(_file, _num_channels);
00232     put_big_long(_file, 0);                /* PIXMIN */
00233     put_big_long(_file, new_maxval);           /* PIXMAX */
00234     for( i = 0; i < 4; i++ )
00235         put_byte(_file, 0);
00236     for( i = 0; i < 79 && imagename[i] != '\0'; i++ )
00237         put_byte(_file, imagename[i]);
00238     for(; i < 80; i++ )
00239         put_byte(_file, 0);
00240     put_big_long(_file, CMAP_NORMAL);
00241     for( i = 0; i < 404; i++ )
00242         put_byte(_file, 0);
00243 }
00244 
00245 
00246 void PNMFileTypeSGI::Writer::
00247 write_table() {
00248     int i;
00249     int tabsize = _y_size*_num_channels;
00250 
00251     for( i = 0; i < tabsize; i++ ) {
00252         put_big_long(_file, table[i].start);
00253     }
00254     for( i = 0; i < tabsize; i++ )
00255         put_big_long(_file, table[i].length);
00256 }
00257 
00258 
00259 void PNMFileTypeSGI::Writer::
00260 write_channels(ScanLine channel[], void (*put)(ostream *, short)) {
00261   int i, col;
00262 
00263   for( i = 0; i < _num_channels; i++ ) {
00264     Table(i).start = _file->tellp();
00265     Table(i).length = channel[i].length * bpc;
00266 
00267     for( col = 0; col < channel[i].length; col++ ) {
00268       (*put)(_file, channel[i].data[col]);
00269     }
00270   }
00271 }
00272 
00273 
00274 void PNMFileTypeSGI::Writer::
00275 build_scanline(ScanLine output[], xel *row_data, xelval *alpha_data) {
00276   int col;
00277   ScanElem *temp;
00278 
00279   if( sgi_storage_type != STORAGE_VERBATIM ) {
00280     rletemp = (ScanElem *)alloca(WORSTCOMPR(_x_size) * sizeof(ScanElem));
00281   }
00282   temp = new ScanElem[_x_size];
00283 
00284   if( _num_channels <= 2 ) {
00285     for( col = 0; col < _x_size; col++ )
00286       temp[col] = (ScanElem)
00287         (new_maxval * PPM_GETB(row_data[col]) / _maxval);
00288     temp = compress(temp, output[0]);
00289 
00290     if (_num_channels == 2) {
00291       for( col = 0; col < _x_size; col++ )
00292         temp[col] = (ScanElem)
00293           (new_maxval * alpha_data[col] / _maxval);
00294       temp = compress(temp, output[1]);
00295     }
00296 
00297   } else {
00298     for( col = 0; col < _x_size; col++ )
00299       temp[col] = (ScanElem)
00300         (new_maxval * PPM_GETR(row_data[col]) / _maxval);
00301     temp = compress(temp, output[0]);
00302     for( col = 0; col < _x_size; col++ )
00303       temp[col] = (ScanElem)
00304         (new_maxval * PPM_GETG(row_data[col]) / _maxval);
00305     temp = compress(temp, output[1]);
00306     for( col = 0; col < _x_size; col++ )
00307       temp[col] = (ScanElem)
00308         (new_maxval * PPM_GETB(row_data[col]) / _maxval);
00309     temp = compress(temp, output[2]);
00310     if (_num_channels == 4) {
00311       for( col = 0; col < _x_size; col++ )
00312         temp[col] = (ScanElem)
00313           (new_maxval * alpha_data[col] / _maxval);
00314       temp = compress(temp, output[3]);
00315     }
00316   }
00317 
00318   delete[] temp;
00319 }
00320 
00321 
00322 PNMFileTypeSGI::Writer::ScanElem *PNMFileTypeSGI::Writer::
00323 compress(ScanElem *temp, ScanLine &output) {
00324     int len;
00325 
00326     switch( sgi_storage_type ) {
00327         case STORAGE_VERBATIM:
00328             output.length = _x_size;
00329             output.data = temp;
00330             temp = new ScanElem[_x_size];
00331             break;
00332         case STORAGE_RLE:
00333             len = rle_compress(temp, _x_size);    /* writes result into rletemp */
00334             output.length = len;
00335             output.data = new ScanElem[len];
00336             memcpy(output.data, rletemp, len * sizeof(ScanElem));
00337             break;
00338         default:
00339             pm_error("unknown storage type - can\'t happen");
00340     }
00341     return temp;
00342 }
00343 
00344 
00345 /*
00346 slightly modified RLE algorithm from ppmtoilbm.c
00347 written by Robert A. Knop (rknop@mop.caltech.edu)
00348 */
00349 int PNMFileTypeSGI::Writer::
00350 rle_compress(ScanElem *inbuf, int size) {
00351     int in, out, hold, count;
00352     ScanElem *outbuf = rletemp;
00353 
00354     in=out=0;
00355     while( in<size ) {
00356         if( (in<size-1) && (inbuf[in]==inbuf[in+1]) ) {     /*Begin replicate run*/
00357             for( count=0,hold=in; in<size && inbuf[in]==inbuf[hold] && count<127; in++,count++)
00358                 ;
00359             outbuf[out++]=(ScanElem)(count);
00360             outbuf[out++]=inbuf[hold];
00361         }
00362         else {  /*Do a literal run*/
00363             hold=out; out++; count=0;
00364             while( ((in>=size-2)&&(in<size)) || ((in<size-2) && ((inbuf[in]!=inbuf[in+1])||(inbuf[in]!=inbuf[in+2]))) ) {
00365                 outbuf[out++]=inbuf[in++];
00366                 if( ++count>=127 )
00367                     break;
00368             }
00369             outbuf[hold]=(ScanElem)(count | 0x80);
00370         }
00371     }
00372     outbuf[out++] = (ScanElem)0;     /* terminator */
00373     return(out);
00374 }
00375 

Generated on Fri May 2 00:43:21 2003 for Panda by doxygen1.3