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