00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
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
00080
00081
00082
00083 PNMFileTypeSGI::Writer::
00084 Writer(PNMFileType *type, ostream *file, bool owns_file) :
00085 PNMWriter(type, file, owns_file)
00086 {
00087 }
00088
00089
00090
00091
00092
00093
00094 PNMFileTypeSGI::Writer::
00095 ~Writer() {
00096 if (table!=NULL) {
00097
00098 _file->seekp(table_start);
00099 write_table();
00100 PANDA_FREE_ARRAY(table);
00101 }
00102 }
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114 bool PNMFileTypeSGI::Writer::
00115 supports_write_row() const {
00116 return true;
00117 }
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
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
00153
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
00175
00176 write_table();
00177 }
00178
00179 current_row = _y_size - 1;
00180 return true;
00181 }
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
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);
00231 put_big_long(_file, new_maxval);
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);
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
00345
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]) ) {
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 {
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;
00371 return(out);
00372 }
00373
00374 #endif // HAVE_SGI_RGB