00001 #include "vil_tiff_header.h"
00002 #include <vcl_iostream.h>
00003 #include <vcl_cstdio.h>
00004 #include <vcl_ctime.h>
00005
00006 #if HAS_GEOTIFF
00007 #include <vil/file_formats/vil_geotiff_header.h>
00008 #endif
00009
00010 static vcl_string date_and_time()
00011 {
00012 vcl_time_t clock;
00013 struct vcl_tm *t_m;
00014 clock = vcl_time(NULL);
00015 t_m = vcl_localtime(&clock);
00016 char tmp[20];
00017 char datetime[20];
00018 vcl_strftime(tmp,sizeof(datetime),"%Y-%m-%d %H:%M:%S",t_m);
00019
00020 vcl_sprintf(datetime,"%19s",tmp);
00021 return vcl_string(datetime);
00022 }
00023
00024 static void read_string(TIFF* tif, ttag_t tag, vcl_string& stag, vcl_string const& deflt = "not_defined")
00025 {
00026 char* adr = 0;
00027 TIFFGetField(tif, tag, &adr);
00028 if (adr)
00029 stag = vcl_string(adr);
00030 else
00031 stag = deflt;
00032 }
00033
00034 static void read_short_tag(TIFF* tif, ttag_t tag, ushort_tag& utag, vxl_uint_16 deflt =0)
00035 {
00036 utag.valid = TIFFGetField(tif, tag, &(utag.val))>0;
00037 if (!utag.valid)
00038 utag.val = deflt;
00039 }
00040
00041 static void read_long_tag(TIFF* tif, ttag_t tag, ulong_tag& utag, vxl_uint_32 deflt = 0)
00042 {
00043 utag.valid = TIFFGetField(tif, tag, &(utag.val))>0;
00044 if (!utag.valid)
00045 utag.val = deflt;
00046 }
00047
00048 static void read_float_tag(TIFF* tif, ttag_t tag, float& val, bool& valid, float deflt = 0)
00049 {
00050 valid = TIFFGetField(tif, tag, &(val))>0;
00051 if (!valid)
00052 val = deflt;
00053 }
00054
00055 #if 0 // unused static function
00056
00057 static bool read_long_array(TIFF* tif, ttag_t tag,
00058 vcl_vector<vxl_uint_32>& array)
00059 {
00060 vxl_uint_32 * a;
00061 if (TIFFGetField(tif, tag, &a))
00062 {
00063 for (vxl_uint_32 i=0; i<array.size(); ++i) { array[i]=a[i]; }
00064 return true;
00065 }
00066 else return false;
00067 }
00068 #endif // unused static function
00069
00070 static void write_short_tag(TIFF* tif, ttag_t tag, ushort_tag const& ustag)
00071 {
00072 if (ustag.valid)
00073 TIFFSetField(tif, tag, ustag.val);
00074 }
00075
00076 static void write_long_tag(TIFF* tif, ttag_t tag, ulong_tag const& ultag)
00077 {
00078 if (ultag.valid)
00079 TIFFSetField(tif, tag, ultag.val);
00080 }
00081
00082 #if 0 // not currently used...
00083 static void write_float_tag(TIFF* tif, ttag_t tag, float const val, bool const valid)
00084 {
00085 if (valid)
00086 TIFFSetField(tif, tag, val);
00087 }
00088 #endif
00089
00090 static void write_string(TIFF* tif, ttag_t tag, vcl_string const& stag)
00091 {
00092 TIFFSetField(tif, tag, stag.c_str());
00093 }
00094
00095
00096 bool vil_tiff_header::read_header()
00097 {
00098
00099 #ifdef DEBUG
00100 vcl_cout << date_and_time() << '\n';
00101 #endif
00102
00103
00104 file_is_big_endian_ = TIFFIsByteSwapped(tif_)>0;
00105
00106
00107 #if VXL_BIG_ENDIAN
00108 machine_is_big_endian_ = true;
00109 #else
00110 machine_is_big_endian_ = false;
00111 #endif
00112
00113
00114
00115 read_short_tag(tif_,TIFFTAG_PHOTOMETRIC, photometric);
00116 read_short_tag(tif_,TIFFTAG_PLANARCONFIG, planar_config, 1);
00117 read_short_tag(tif_,TIFFTAG_SAMPLESPERPIXEL, samples_per_pixel, 1);
00118 read_short_tag(tif_,TIFFTAG_BITSPERSAMPLE, bits_per_sample, 8);
00119 is_tiled_flag = TIFFIsTiled(tif_)>0;
00120
00121 read_string(tif_,TIFFTAG_ARTIST , artist);
00122 read_short_tag(tif_,TIFFTAG_CELLLENGTH, cell_length);
00123 read_short_tag(tif_,TIFFTAG_CELLWIDTH, cell_width);
00124 color_map_valid = false;
00125 if (bits_per_sample.valid &&
00126 photometric.valid &&
00127 photometric.val == PHOTOMETRIC_PALETTE)
00128 {
00129 vxl_uint_16* cm[3];
00130 TIFFGetField(tif_,TIFFTAG_COLORMAP, &cm[0], &cm[1], &cm[2]);
00131 unsigned size = 1<<bits_per_sample.val;
00132 color_map.resize(size);
00133 for (unsigned i = 0; i<size; ++i)
00134 {
00135 vcl_vector<vxl_uint_16> rgb(3);
00136 rgb[0]=cm[0][i]; rgb[1]=cm[1][i]; rgb[2]=cm[2][i];
00137 color_map[i] = rgb;
00138 #ifdef DEBUG
00139 vcl_cout << "RGB[" << i << "]=(" << rgb[0] << ' ' << rgb[1] << ' ' << rgb[2] << ")\n";
00140 #endif
00141 }
00142 color_map_valid = true;
00143 }
00144 read_short_tag(tif_,TIFFTAG_COMPRESSION, compression);
00145 read_string(tif_,TIFFTAG_COPYRIGHT, copyright);
00146 read_string(tif_,TIFFTAG_DATETIME,date_time);
00147
00148
00149
00150 vxl_uint_16* sample_info=0;
00151 extra_samples.val=0;
00152 extra_samples.valid = false;
00153 int const ret_extrasamples = TIFFGetField(tif_, TIFFTAG_EXTRASAMPLES, &extra_samples.val, &sample_info);
00154 if (ret_extrasamples && extra_samples.val > 0)
00155 extra_samples.valid = true;
00156
00157 read_short_tag(tif_,TIFFTAG_FILLORDER, fill_order);
00158 vxl_uint_16* gc=0;
00159 TIFFGetField(tif_,TIFFTAG_GRAYRESPONSECURVE, &gc);
00160 read_short_tag(tif_,TIFFTAG_GRAYRESPONSEUNIT, gray_response_unit);
00161 read_string(tif_,TIFFTAG_HOSTCOMPUTER, host_computer);
00162 read_string(tif_,TIFFTAG_IMAGEDESCRIPTION, image_description);
00163 read_long_tag(tif_,TIFFTAG_IMAGELENGTH, image_length);
00164 read_long_tag(tif_,TIFFTAG_IMAGEWIDTH, image_width);
00165 read_string(tif_,TIFFTAG_MAKE, make);
00166 read_short_tag(tif_,TIFFTAG_MAXSAMPLEVALUE, max_sample_value, 255);
00167 read_short_tag(tif_,TIFFTAG_MINSAMPLEVALUE, min_sample_value, 0);
00168 read_string(tif_,TIFFTAG_MODEL, model);
00169 read_short_tag(tif_,TIFFTAG_SUBFILETYPE, subfile_type);
00170 read_short_tag(tif_,TIFFTAG_ORIENTATION, orientation, 1);
00171 read_short_tag(tif_,TIFFTAG_RESOLUTIONUNIT, resolution_unit);
00172 read_long_tag(tif_,TIFFTAG_ROWSPERSTRIP, rows_per_strip);
00173 read_string(tif_,TIFFTAG_SOFTWARE, software);
00174 read_short_tag(tif_,TIFFTAG_SAMPLEFORMAT, sample_format, 1);
00175 strip_byte_counts_valid = false;
00176 if (rows_per_strip.valid)
00177 {
00178 strip_byte_counts_valid =
00179 TIFFGetField(tif_,TIFFTAG_STRIPBYTECOUNTS , &strip_byte_counts)>0;
00180 #ifdef DEBUG
00181
00182 vxl_uint_32 size = strips_per_image();
00183 for (vxl_uint_32 i = 0; i<size; ++i)
00184 vcl_cout << "SBC[" << i << "]=" << strip_byte_counts[i] << '\n';
00185 #endif
00186 }
00187
00188 strip_offsets_valid = false;
00189 #ifdef DEBUG
00190 if (rows_per_strip.valid)
00191 {
00192 strip_offsets_valid =
00193 TIFFGetField(tif_, TIFFTAG_STRIPOFFSETS, &strip_offsets)>0;
00194
00195 vxl_uint_32 size = strips_per_image();
00196 for (vxl_uint_32 i = 0; i<size; ++i)
00197 vcl_cout << "SOFF[" << i << "]=" << strip_offsets[i] << '\n';
00198 }
00199 #endif
00200 read_short_tag(tif_,TIFFTAG_THRESHHOLDING, thresholding);
00201
00202 read_float_tag(tif_, TIFFTAG_XRESOLUTION, x_resolution, x_resolution_valid);
00203 read_float_tag(tif_, TIFFTAG_YRESOLUTION, y_resolution, y_resolution_valid);
00204
00205 read_long_tag(tif_, TIFFTAG_TILEWIDTH, tile_width, 0);
00206 read_long_tag(tif_, TIFFTAG_TILELENGTH, tile_length, 0);
00207
00208 tile_offsets_valid = false;
00209
00210 #ifdef DEBUG
00211 if (tile_width.valid&&tile_length.valid)
00212 {
00213 tile_offsets_valid =
00214 TIFFGetField(tif_, TIFFTAG_TILEOFFSETS, &tile_offsets)>0;
00215
00216 vxl_uint_32 size = tiles_per_image();
00217 for (vxl_uint_32 i = 0; i<size; ++i)
00218 vcl_cout << "TOFF[" << i << "]=" << tile_offsets[i] << '\n';
00219 }
00220 #endif
00221
00222 tile_byte_counts_valid = false;
00223 #ifdef DEBUG
00224 if (tile_width.valid&&tile_length.valid)
00225 {
00226 tile_byte_counts_valid =
00227 TIFFGetField(tif_, TIFFTAG_TILEBYTECOUNTS, &tile_byte_counts)>0;
00228
00229 vxl_uint_32 size = tiles_per_image();
00230 for (vxl_uint_32 i = 0; i<size; ++i)
00231 vcl_cout << "TBC[" << i << "]=" << tile_byte_counts[i] << '\n';
00232 }
00233 #endif
00234 return this->compute_pixel_format();
00235
00236 }
00237
00238
00239
00240 unsigned vil_tiff_header::n_separate_image_planes() const
00241 {
00242 if (planar_config.valid)
00243 {
00244 if (planar_config.val == PLANARCONFIG_SEPARATE)
00245 return samples_per_pixel.val;
00246 else if (planar_config.val == PLANARCONFIG_CONTIG)
00247 return 1;
00248 else
00249 return 0;
00250 }
00251 else
00252 return 0;
00253 }
00254
00255 bool vil_tiff_header::is_tiled() const
00256 {
00257 return is_tiled_flag ||
00258 (tile_width.valid&&tile_length.valid&&tile_width.val>0&&tile_length.val>0);
00259 }
00260
00261 bool vil_tiff_header::is_striped() const
00262 {
00263
00264
00265 return (rows_per_strip.valid && rows_per_strip.val > 0) || !rows_per_strip.valid;
00266 }
00267
00268 #if HAS_GEOTIFF
00269 bool vil_tiff_header::is_GEOTIFF() const
00270 {
00271 short *data;
00272 short count;
00273 return TIFFGetField(tif_, 34735 , &count, &data)!=0;
00274 }
00275 #endif
00276
00277 unsigned vil_tiff_header::encoded_bytes_per_block() const
00278 {
00279 if (is_tiled())
00280 return static_cast<unsigned>(bytes_per_tile());
00281 else if (is_striped())
00282 return static_cast<unsigned>(bytes_per_strip());
00283 else
00284 return 0;
00285 }
00286
00287
00288 unsigned vil_tiff_header::samples_per_line() const
00289 {
00290 if (image_width.valid)
00291 return samples_per_pixel.val*image_width.val;
00292 return 0;
00293 }
00294
00295 vxl_uint_32 vil_tiff_header::bytes_per_line() const
00296 {
00297 unsigned nsamp = this->samples_per_line();
00298 unsigned bits_per_line = bits_per_sample.val*nsamp;
00299 return (bits_per_line + 7)/8;
00300 }
00301
00302 vxl_uint_32 vil_tiff_header::actual_bytes_per_line() const
00303 {
00304 return TIFFScanlineSize(tif_);
00305 }
00306
00307 vxl_uint_32 vil_tiff_header::rows_in_strip() const
00308 {
00309 if (rows_per_strip.valid&&image_length.valid)
00310 {
00311 vxl_uint_32 rps = rows_per_strip.val;
00312 if (rps>image_length.val)
00313 return image_length.val;
00314 return rps;
00315 }
00316 else if (image_length.valid)
00317 {
00318 return image_length.val;
00319 }
00320 return 0;
00321 }
00322
00323
00324 vxl_uint_32 vil_tiff_header::
00325 actual_bytes_per_strip(const vxl_uint_32 strip_index) const
00326 {
00327 if (strip_byte_counts_valid)
00328 return strip_byte_counts[strip_index];
00329 return 0;
00330 }
00331
00332
00333 vxl_uint_32 vil_tiff_header::bytes_per_strip() const
00334 {
00335 return rows_in_strip()*bytes_per_line();
00336 }
00337
00338 vxl_uint_32 vil_tiff_header::bytes_per_tile() const
00339 {
00340 return TIFFTileSize(tif_);
00341 }
00342
00343
00344 vxl_uint_16 vil_tiff_header::n_images()
00345 {
00346 return TIFFNumberOfDirectories(tif_);
00347 }
00348
00349
00350
00351 bool vil_tiff_header::compute_pixel_format()
00352 {
00353
00354
00355 if (!(bits_per_sample.valid) ||
00356 !(planar_config.valid) || !photometric.valid )
00357 {
00358 pix_fmt = VIL_PIXEL_FORMAT_UNKNOWN;
00359 return false;
00360 }
00361
00362 vxl_uint_16 b = bits_per_sample.val;
00363 vxl_uint_16 bbs = bytes_per_sample();
00364 nplanes = 1;
00365
00366 if (samples_per_pixel.val==1)
00367 {
00368
00369 switch (sample_format.val)
00370 {
00371 case 2:
00372 switch (b)
00373 {
00374 case 8:
00375 pix_fmt = VIL_PIXEL_FORMAT_SBYTE;
00376 return true;
00377 case 16:
00378 pix_fmt = VIL_PIXEL_FORMAT_INT_16;
00379 return true;
00380 case 32:
00381 pix_fmt = VIL_PIXEL_FORMAT_INT_32;
00382 return false;
00383 default:
00384 pix_fmt = VIL_PIXEL_FORMAT_UNKNOWN;
00385 return false;
00386 }
00387 case 3:
00388 switch (bbs)
00389 {
00390 case (sizeof(float)):
00391 pix_fmt = VIL_PIXEL_FORMAT_FLOAT;
00392 return true;
00393 case (sizeof(double)):
00394 pix_fmt = VIL_PIXEL_FORMAT_DOUBLE;
00395 return true;
00396 default:
00397 pix_fmt = VIL_PIXEL_FORMAT_UNKNOWN;
00398 return false;
00399 }
00400 case 4:
00401 case 1:
00402 default:
00403 if (b==1){
00404 pix_fmt = VIL_PIXEL_FORMAT_BOOL;
00405 return true;}
00406 else
00407 switch (bbs)
00408 {
00409 case 1:
00410 pix_fmt = VIL_PIXEL_FORMAT_BYTE;
00411 return true;
00412 case 2:
00413 pix_fmt = VIL_PIXEL_FORMAT_UINT_16;
00414 return true;
00415 case 3:
00416 case 4:
00417 pix_fmt = VIL_PIXEL_FORMAT_UINT_32;
00418 return true;
00419 default:
00420 pix_fmt = VIL_PIXEL_FORMAT_UNKNOWN;
00421 return true;
00422 }
00423 }
00424 }
00425
00426
00427
00428
00429 if (samples_per_pixel.val==1 && photometric.val==PHOTOMETRIC_RGB &&
00430 sample_format.val == 1)
00431 switch (bbs)
00432 {
00433 case 1:
00434 pix_fmt = VIL_PIXEL_FORMAT_BYTE;
00435 nplanes = 3;
00436 return false;
00437 case 2:
00438 pix_fmt = VIL_PIXEL_FORMAT_UINT_16;
00439 nplanes = 4;
00440 return false;
00441 default:
00442 pix_fmt = VIL_PIXEL_FORMAT_UNKNOWN;
00443 return false;
00444 }
00445
00446
00447
00448
00449
00450
00451 vxl_uint_16 s = samples_per_pixel.val;
00452 if (samples_per_pixel.val>1 && photometric.val==2 && planar_config.val == 1 )
00453 {
00454 switch (sample_format.val)
00455 {
00456 case 1:
00457 switch (b)
00458 {
00459 case 8:
00460 pix_fmt = VIL_PIXEL_FORMAT_BYTE;
00461 switch (s)
00462 {
00463 case 3:
00464 nplanes = 3;
00465 return true;
00466 case 4:
00467 nplanes = 4;
00468 return true;
00469 default:
00470 pix_fmt = VIL_PIXEL_FORMAT_UNKNOWN;
00471 return false;
00472 }
00473 case 16:
00474 pix_fmt = VIL_PIXEL_FORMAT_UINT_16;
00475 switch (s)
00476 {
00477 case 3:
00478 nplanes = 3;
00479 return true;
00480 case 4:
00481 nplanes = 4;
00482 return true;
00483 default:
00484 pix_fmt = VIL_PIXEL_FORMAT_UNKNOWN;
00485 return false;
00486 }
00487 case 32:
00488 pix_fmt = VIL_PIXEL_FORMAT_UINT_32;
00489 switch (s)
00490 {
00491 case 3:
00492 nplanes = 3;
00493 return true;
00494 case 4:
00495 nplanes = 4;
00496 return false;
00497 default:
00498 pix_fmt = VIL_PIXEL_FORMAT_UNKNOWN;
00499 return false;
00500 }
00501 default:
00502 switch (bbs)
00503 {
00504 case 1:
00505 pix_fmt = VIL_PIXEL_FORMAT_RGB_BYTE;
00506 switch (s)
00507 {
00508 case 3:
00509 nplanes = 3;
00510 return true;
00511 case 4:
00512 nplanes = 4;
00513 return false;
00514 default:
00515 pix_fmt = VIL_PIXEL_FORMAT_UNKNOWN;
00516 return false;
00517 }
00518 case 2:
00519 pix_fmt = VIL_PIXEL_FORMAT_UINT_16;
00520 switch (s)
00521 {
00522 case 3:
00523 nplanes = 3;
00524 return true;
00525 case 4:
00526 nplanes = 4;
00527 return true;
00528 default:
00529 pix_fmt = VIL_PIXEL_FORMAT_UNKNOWN;
00530 return false;
00531 }
00532 case 4:
00533 pix_fmt = VIL_PIXEL_FORMAT_UINT_32;
00534 switch (s)
00535 {
00536 case 3:
00537 nplanes = 3;
00538 return true;
00539 case 4:
00540 nplanes = 4;
00541 return false;
00542 default:
00543 pix_fmt = VIL_PIXEL_FORMAT_UNKNOWN;
00544 return false;
00545 }
00546 default:
00547 pix_fmt = VIL_PIXEL_FORMAT_UNKNOWN;
00548 return false;
00549 }
00550 }
00551 case 2:
00552 pix_fmt = VIL_PIXEL_FORMAT_UNKNOWN;
00553 return false;
00554
00555 case 3:
00556 pix_fmt = VIL_PIXEL_FORMAT_FLOAT;
00557 nplanes = s;
00558 return true;
00559 case 4:
00560 default:
00561 pix_fmt = VIL_PIXEL_FORMAT_UNKNOWN;
00562 return false;
00563 }
00564 }
00565
00566 if (photometric.val==PHOTOMETRIC_MASK)
00567 {
00568 pix_fmt = VIL_PIXEL_FORMAT_UNKNOWN;
00569 return false;
00570 }
00571
00572
00573 if (photometric.val==PHOTOMETRIC_SEPARATED)
00574 {
00575 pix_fmt = VIL_PIXEL_FORMAT_UNKNOWN;
00576 return false;
00577 }
00578
00579 pix_fmt = VIL_PIXEL_FORMAT_UNKNOWN;
00580 return false;
00581 }
00582
00583
00584 bool vil_tiff_header::parse_pixel_format(vil_pixel_format const& fmt)
00585 {
00586
00587 sample_format.val = 1; sample_format.valid = true;
00588 switch ( fmt )
00589 {
00590 case VIL_PIXEL_FORMAT_BOOL:
00591 bits_per_sample.val = 1; bits_per_sample.valid = true;
00592 return true;
00593 case VIL_PIXEL_FORMAT_BYTE:
00594 bits_per_sample.val = 8; bits_per_sample.valid = true;
00595 return true;
00596 case VIL_PIXEL_FORMAT_UINT_16:
00597 bits_per_sample.val = 16; bits_per_sample.valid = true;
00598 return true;
00599 case VIL_PIXEL_FORMAT_UINT_32:
00600 bits_per_sample.val = 32; bits_per_sample.valid = true;
00601 return true;
00602 case VIL_PIXEL_FORMAT_FLOAT:
00603 bits_per_sample.val = 8*sizeof(float); bits_per_sample.valid = true;
00604 sample_format.val = 3;
00605 return true;
00606 case VIL_PIXEL_FORMAT_DOUBLE:
00607 bits_per_sample.val = 8*sizeof(double); bits_per_sample.valid = true;
00608 sample_format.val = 3;
00609 return true;
00610 default:
00611 break;
00612 }
00613 return false;
00614 }
00615
00616
00617
00618 bool vil_tiff_header::set_header(unsigned ni, unsigned nj, unsigned nplns,
00619 vil_pixel_format const& fmt,
00620 const unsigned size_block_i,
00621 const unsigned size_block_j)
00622 {
00623
00624 #if VXL_BIG_ENDIAN
00625 machine_is_big_endian_ = true;
00626 #else
00627 machine_is_big_endian_ = false;
00628 #endif
00629
00630 file_is_big_endian_ = machine_is_big_endian_;
00631 pix_fmt = fmt;
00632 if (!this->parse_pixel_format(fmt))
00633 return false;
00634 nplanes = nplns;
00635
00636 photometric.valid = true;
00637 switch ( nplanes )
00638 {
00639 case 1:
00640 case 2:
00641 photometric.val = 1;
00642 break;
00643 case 3:
00644 case 4:
00645 photometric.val = 2;
00646 break;
00647 default:
00648 return false;
00649 }
00650 image_length.val = nj; image_length.valid = true;
00651 image_width.val = ni; image_width.valid = true;
00652 if (size_block_i>0&&size_block_j>0)
00653 {
00654 is_tiled_flag = true;
00655 tile_width.val = size_block_i; tile_width.valid = true;
00656 tile_length.val = size_block_j; tile_length.valid = true;
00657 }
00658 else
00659 {
00660 is_tiled_flag = false;
00661
00662 unsigned n_rows = size_block_j;
00663 if (n_rows == 0)
00664 n_rows = 1u;
00665 rows_per_strip.val = n_rows; rows_per_strip.valid = true;
00666 }
00667 samples_per_pixel.val = nplanes; samples_per_pixel.valid=true;
00668
00669 planar_config.val = 1; planar_config.valid = true;
00670
00671 orientation.val = ORIENTATION_TOPLEFT; orientation.valid = true;
00672 software = "http://vxl.sourceforge.net/ vil image library";
00673 return true;
00674 }
00675
00676
00677 vil_tiff_header::
00678 vil_tiff_header(TIFF* tif, const unsigned ni, const unsigned nj,
00679 const unsigned nplanes, vil_pixel_format const& fmt,
00680 const unsigned size_block_i, const unsigned size_block_j)
00681 {
00682 tif_ = tif;
00683
00684 format_supported =
00685 this->set_header(ni, nj, nplanes, fmt, size_block_i, size_block_j);
00686 if (!format_supported)
00687 return;
00688 write_short_tag(tif_,TIFFTAG_PHOTOMETRIC, photometric);
00689 write_short_tag(tif_,TIFFTAG_PLANARCONFIG, planar_config);
00690 write_short_tag(tif_,TIFFTAG_SAMPLESPERPIXEL, samples_per_pixel);
00691 write_short_tag(tif_,TIFFTAG_BITSPERSAMPLE, bits_per_sample);
00692 write_string(tif_, TIFFTAG_DATETIME, date_and_time());
00693 write_long_tag(tif_,TIFFTAG_IMAGELENGTH, image_length);
00694 write_long_tag(tif_,TIFFTAG_IMAGEWIDTH, image_width);
00695 write_short_tag(tif_,TIFFTAG_ORIENTATION, orientation);
00696 write_long_tag(tif_,TIFFTAG_ROWSPERSTRIP, rows_per_strip);
00697 write_string(tif_, TIFFTAG_SOFTWARE, software);
00698 write_short_tag(tif_,TIFFTAG_SAMPLEFORMAT, sample_format);
00699 write_long_tag(tif_, TIFFTAG_TILEWIDTH, tile_width);
00700 write_long_tag(tif_, TIFFTAG_TILELENGTH, tile_length);
00701 #if 1 // Handle Alpha channel, assuming it is the last channel
00702 if (nplanes == 2 || nplanes == 4)
00703 {
00704
00705
00706 vxl_uint_32 num_extra_samples = 1;
00707 vxl_uint_16 extra_sample_values[] = { EXTRASAMPLE_ASSOCALPHA };
00708 TIFFSetField(tif_, TIFFTAG_EXTRASAMPLES, num_extra_samples, extra_sample_values);
00709 }
00710 #endif
00711
00712 color_map_valid = false;
00713 grey_response_curve_valid = false;
00714 strip_byte_counts_valid = false;
00715 strip_offsets_valid = false;
00716 tile_offsets_valid = false;
00717 tile_byte_counts_valid = false;
00718 }