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