# HG changeset patch # User Claus Gittinger # Date 1503856750 -7200 # Node ID e533a09c2c1d0afbadea34010b37f64057db0e15 # Parent 2ec7424998e424e39af331f0a95f325a04fd078b #BUGFIX by cg class: TIFFReader class definition added: #decodeMetaTags: #decodePhotoshopImageResourceBlock: #loadFullResolutionImage: #readAdobeDeflateTiffImageData #readSingleTagFrom: #readTagsFrom: #readTiledNewJPEGTiffImageData comment/format in: #readDoubles: changed:16 methods class: TIFFReader class comment/format in: #documentation changed: #initialize #isValidImageFile: diff -r 2ec7424998e4 -r e533a09c2c1d TIFFReader.st --- a/TIFFReader.st Sun Aug 27 16:35:52 2017 +0200 +++ b/TIFFReader.st Sun Aug 27 19:59:10 2017 +0200 @@ -16,9 +16,26 @@ ImageReader subclass:#TIFFReader instanceVariableNames:'planarConfiguration subFileType stripOffsets rowsPerStrip fillOrder compression group3options predictor stripByteCounts - currentOffset stripOffsetsPos stripByteCountsPos bitsPerSamplePos - colorMapPos orientation isBigTiff' - classVariableNames:'Verbose' + currentOffset stripOffsetsPos stripByteCountsPos stripRowCounts + bitsPerSamplePos colorMapPos orientation isBigTiff tileOffsets + tileByteCounts tileWidth tileLength sampleFormat minSampleValue + maxSampleValue subIfds decodeMetaTags loadFullResolutionImage + isDNGImage' + classVariableNames:'Verbose COMPRESSION_NONE COMPRESSION_CCITTRLE + COMPRESSION_CCITTFAX3 COMPRESSION_CCITTFAX4 COMPRESSION_LZW + COMPRESSION_OJPEG COMPRESSION_JPEG COMPRESSION_ADOBE_DEFLATE + COMPRESSION_JBIG_T85 COMPRESSION_JBIG_T43 COMPRESSION_NEXT + COMPRESSION_CCITTRLEW COMPRESSION_PACKBITS + COMPRESSION_THUNDERSCAN COMPRESSION_IT8CTPAD COMPRESSION_IT8LW + COMPRESSION_IT8MP COMPRESSION_IT8BL COMPRESSION_PIXARFILM + COMPRESSION_PIXARLOG COMPRESSION_DEFLATE COMPRESSION_DCS + COMPRESSION_JBIG COMPRESSION_JPEG2000 COMPRESSION_NIKON_NEF + COMPRESSION_JBIG2 COMPRESSION_NEXT_JPEG SAMPLEFORMAT_UINT + SAMPLEFORMAT_INT SAMPLEFORMAT_IEEEFP SAMPLEFORMAT_VOID + SAMPLEFORMAT_COMPLEXINT SAMPLEFORMAT_COMPLEXIEEEFP + COMPRESSION_SGILOG COMPRESSION_SGILOG24 PLANARCONFIG_CONTIG + PLANARCONFIG_SEPARATE FILETYPE_MASK_REDUCEDIMAGE + FILETYPE_MASK_PAGE FILETYPE_MASK_MASK' poolDictionaries:'' category:'Graphics-Images-Readers' ! @@ -64,6 +81,7 @@ It should write (at least) mono, 8-bit palette and 24 bit rgb formats. - bigTiff is supported + - some dng tags are supported More formats will come... (will they ever be needed?) @@ -96,14 +114,590 @@ "install myself in the Image classes fileFormat table for the `.tiff' and `.tif' extensions." - MIMETypes defineImageType:'image/tiff' suffix:'tif' reader:self. + MIMETypes defineImageType:'image/tiff' suffix:'tif' reader:self info:'tiff image'. MIMETypes defineImageType:nil suffix:'tiff' reader:self. + MIMETypes defineImageType:'image/x-adobe-dng' suffix:'dng' reader:self info:'digital negative image'. + + COMPRESSION_NONE := 1. + COMPRESSION_CCITTRLE := 2. + COMPRESSION_CCITTFAX3 := 3. + COMPRESSION_CCITTFAX4 := 4. + COMPRESSION_LZW := 5. + COMPRESSION_OJPEG := 6. "/ (old style jpeg) + COMPRESSION_JPEG := 7. "/ (new style jpeg) + COMPRESSION_ADOBE_DEFLATE := 8. + COMPRESSION_JBIG_T85 := 9. "/ (ITU-T T85) + COMPRESSION_JBIG_T43 := 10. "/ (ITU-T T43) + + COMPRESSION_NEXT := 32766. "/ (NeXT 2-bit encoding) + COMPRESSION_CCITTRLEW := 32771. + COMPRESSION_PACKBITS := 32773. + COMPRESSION_THUNDERSCAN := 32809. "/ (ThunderScan 4-bit encoding) + COMPRESSION_NEXT_JPEG := 32865. "/ (NeXT jpeg encoding) + COMPRESSION_IT8CTPAD := 32895. + COMPRESSION_IT8LW := 32896. + COMPRESSION_IT8MP := 32897. + COMPRESSION_IT8BL := 32898. + COMPRESSION_PIXARFILM := 32908. + COMPRESSION_PIXARLOG := 32909. "/ (Pixar companded 11-bit ZIP encoding) + COMPRESSION_DEFLATE := 32946. "/ (PKZIP-style Deflate encoding) + COMPRESSION_DCS := 32947. "/ (kodac) + COMPRESSION_JBIG := 34661. + COMPRESSION_SGILOG := 34676. "/ (SGI 32-bit Log Luminance encoding) + COMPRESSION_SGILOG24 := 34677. "/ (SGI 24-bit Log Luminance encoding) + COMPRESSION_JPEG2000 := 34712. "/ JPEG2000 + COMPRESSION_NIKON_NEF := 34713. + COMPRESSION_JBIG2 := 34715. + + SAMPLEFORMAT_UINT := 1. "/ !!unsigned integer data + SAMPLEFORMAT_INT := 2. "/ !!signed integer data + SAMPLEFORMAT_IEEEFP := 3. "/ !!IEEE floating point data + SAMPLEFORMAT_VOID := 4. "/ !!untyped data + SAMPLEFORMAT_COMPLEXINT := 5. "/ !!complex signed int + SAMPLEFORMAT_COMPLEXIEEEFP := 6. "/ !!complex ieee floating + + PLANARCONFIG_CONTIG := 1. + PLANARCONFIG_SEPARATE := 2. + + FILETYPE_MASK_REDUCEDIMAGE := 1. + FILETYPE_MASK_PAGE := 2. + FILETYPE_MASK_MASK := 4. + +"/ TYPE_NOTYPE := 0. "/ placeholder +"/ TYPE_BYTE := 1. "/ 8-bit unsigned integer +"/ TYPE_ASCII := 2. "/ 8-bit bytes w/ last byte null +"/ TYPE_SHORT := 3. "/ 16-bit unsigned integer +"/ TYPE_LONG := 4. "/ 32-bit unsigned integer +"/ TYPE_RATIONAL := 5. "/ 64-bit unsigned fraction +"/ TYPE_SBYTE := 6. "/ !!8-bit signed integer +"/ TYPE_UNDEFINED := 7. "/ !!8-bit untyped data +"/ TYPE_SSHORT := 8. "/ !!16-bit signed integer +"/ TYPE_SLONG := 9. "/ !!32-bit signed integer +"/ TYPE_SRATIONAL := 10. "/ !!64-bit signed fraction +"/ TYPE_FLOAT := 11. "/ !!32-bit IEEE floating point +"/ TYPE_DOUBLE := 12. "/ !!64-bit IEEE floating point +"/ TYPE_IFD := 13. "/ %32-bit unsigned integer (offset) +"/ TYPE_LONG8 := 16. "/ BigTIFF 64-bit unsigned integer +"/ TYPE_SLONG8 := 17. "/ BigTIFF 64-bit signed integer +"/ TYPE_IFD8 := 18. "/ BigTIFF 64-bit unsigned integer (offset) + + "/ + "/ TIFF tags + "/ + +"/ #define TIFFTAG_SUBFILETYPE 254 /* subfile data descriptor */ +"/ #define FILETYPE_REDUCEDIMAGE 0x1 /* reduced resolution version */ +"/ #define FILETYPE_PAGE 0x2 /* one page of many */ +"/ #define FILETYPE_MASK 0x4 /* transparency mask */ +"/ #define TIFFTAG_OSUBFILETYPE 255 /* +kind of data in subfile */ +"/ #define OFILETYPE_IMAGE 1 /* full resolution image data */ +"/ #define OFILETYPE_REDUCEDIMAGE 2 /* reduced size image data */ +"/ #define OFILETYPE_PAGE 3 /* one page of many */ +"/ #define TIFFTAG_IMAGEWIDTH 256 /* image width in pixels */ +"/ #define TIFFTAG_IMAGELENGTH 257 /* image height in pixels */ +"/ #define TIFFTAG_BITSPERSAMPLE 258 /* bits per channel (sample) */ +"/ #define TIFFTAG_COMPRESSION 259 /* data compression technique */ +"/ #define COMPRESSION_NONE 1 /* dump mode */ +"/ #define COMPRESSION_CCITTRLE 2 /* CCITT modified Huffman RLE */ +"/ #define COMPRESSION_CCITTFAX3 3 /* CCITT Group 3 fax encoding */ +"/ #define COMPRESSION_CCITT_T4 3 /* CCITT T.4 (TIFF 6 name) */ +"/ #define COMPRESSION_CCITTFAX4 4 /* CCITT Group 4 fax encoding */ +"/ #define COMPRESSION_CCITT_T6 4 /* CCITT T.6 (TIFF 6 name) */ +"/ #define COMPRESSION_LZW 5 /* Lempel-Ziv & Welch */ +"/ #define COMPRESSION_OJPEG 6 /* !!6.0 JPEG */ +"/ #define COMPRESSION_JPEG 7 /* %JPEG DCT compression */ +"/ #define COMPRESSION_T85 9 /* !!TIFF/FX T.85 JBIG compression */ +"/ #define COMPRESSION_T43 10 /* !!TIFF/FX T.43 colour by layered JBIG compression */ +"/ #define COMPRESSION_NEXT 32766 /* NeXT 2-bit RLE */ +"/ #define COMPRESSION_CCITTRLEW 32771 /* #1 w/ word alignment */ +"/ #define COMPRESSION_PACKBITS 32773 /* Macintosh RLE */ +"/ #define COMPRESSION_THUNDERSCAN 32809 /* ThunderScan RLE */ +"/ /* codes 32895-32898 are reserved for ANSI IT8 TIFF/IT */ +"/ #define COMPRESSION_DCS 32947 /* Kodak DCS encoding */ +"/ #define COMPRESSION_JBIG 34661 /* ISO JBIG */ +"/ #define COMPRESSION_SGILOG 34676 /* SGI Log Luminance RLE */ +"/ #define COMPRESSION_SGILOG24 34677 /* SGI Log 24-bit packed */ +"/ #define COMPRESSION_JP2000 34712 /* Leadtools JPEG2000 */ +"/ #define COMPRESSION_LZMA 34925 /* LZMA2 */ +"/ #define TIFFTAG_PHOTOMETRIC 262 /* photometric interpretation */ +"/ #define PHOTOMETRIC_MINISWHITE 0 /* min value is white */ +"/ #define PHOTOMETRIC_MINISBLACK 1 /* min value is black */ +"/ #define PHOTOMETRIC_RGB 2 /* RGB color model */ +"/ #define PHOTOMETRIC_PALETTE 3 /* color map indexed */ +"/ #define PHOTOMETRIC_MASK 4 /* $holdout mask */ +"/ #define PHOTOMETRIC_SEPARATED 5 /* !!color separations */ +"/ #define PHOTOMETRIC_YCBCR 6 /* !!CCIR 601 */ +"/ #define PHOTOMETRIC_CIELAB 8 /* !!1976 CIE L*a*b* */ +"/ #define PHOTOMETRIC_ICCLAB 9 /* ICC L*a*b* [Adobe TIFF Technote 4] */ +"/ #define PHOTOMETRIC_ITULAB 10 /* ITU L*a*b* */ +"/ #define PHOTOMETRIC_CFA 32803 /* color filter array */ +"/ #define PHOTOMETRIC_LOGL 32844 /* CIE Log2(L) */ +"/ #define PHOTOMETRIC_LOGLUV 32845 /* CIE Log2(L) (u',v') */ +"/ #define TIFFTAG_THRESHHOLDING 263 /* +thresholding used on data */ +"/ #define THRESHHOLD_BILEVEL 1 /* b&w art scan */ +"/ #define THRESHHOLD_HALFTONE 2 /* or dithered scan */ +"/ #define THRESHHOLD_ERRORDIFFUSE 3 /* usually floyd-steinberg */ +"/ #define TIFFTAG_CELLWIDTH 264 /* +dithering matrix width */ +"/ #define TIFFTAG_CELLLENGTH 265 /* +dithering matrix height */ +"/ #define TIFFTAG_FILLORDER 266 /* data order within a byte */ +"/ #define FILLORDER_MSB2LSB 1 /* most significant -> least */ +"/ #define FILLORDER_LSB2MSB 2 /* least significant -> most */ +"/ #define TIFFTAG_DOCUMENTNAME 269 /* name of doc. image is from */ +"/ #define TIFFTAG_IMAGEDESCRIPTION 270 /* info about image */ +"/ #define TIFFTAG_MAKE 271 /* scanner manufacturer name */ +"/ #define TIFFTAG_MODEL 272 /* scanner model name/number */ +"/ #define TIFFTAG_STRIPOFFSETS 273 /* offsets to data strips */ +"/ #define TIFFTAG_ORIENTATION 274 /* +image orientation */ +"/ #define ORIENTATION_TOPLEFT 1 /* row 0 top, col 0 lhs */ +"/ #define ORIENTATION_TOPRIGHT 2 /* row 0 top, col 0 rhs */ +"/ #define ORIENTATION_BOTRIGHT 3 /* row 0 bottom, col 0 rhs */ +"/ #define ORIENTATION_BOTLEFT 4 /* row 0 bottom, col 0 lhs */ +"/ #define ORIENTATION_LEFTTOP 5 /* row 0 lhs, col 0 top */ +"/ #define ORIENTATION_RIGHTTOP 6 /* row 0 rhs, col 0 top */ +"/ #define ORIENTATION_RIGHTBOT 7 /* row 0 rhs, col 0 bottom */ +"/ #define ORIENTATION_LEFTBOT 8 /* row 0 lhs, col 0 bottom */ +"/ #define TIFFTAG_SAMPLESPERPIXEL 277 /* samples per pixel */ +"/ #define TIFFTAG_ROWSPERSTRIP 278 /* rows per strip of data */ +"/ #define TIFFTAG_STRIPBYTECOUNTS 279 /* bytes counts for strips */ +"/ #define TIFFTAG_MINSAMPLEVALUE 280 /* +minimum sample value */ +"/ #define TIFFTAG_MAXSAMPLEVALUE 281 /* +maximum sample value */ +"/ #define TIFFTAG_XRESOLUTION 282 /* pixels/resolution in x */ +"/ #define TIFFTAG_YRESOLUTION 283 /* pixels/resolution in y */ +"/ #define TIFFTAG_PLANARCONFIG 284 /* storage organization */ +"/ #define PLANARCONFIG_CONTIG 1 /* single image plane */ +"/ #define PLANARCONFIG_SEPARATE 2 /* separate planes of data */ +"/ #define TIFFTAG_PAGENAME 285 /* page name image is from */ +"/ #define TIFFTAG_XPOSITION 286 /* x page offset of image lhs */ +"/ #define TIFFTAG_YPOSITION 287 /* y page offset of image lhs */ +"/ #define TIFFTAG_FREEOFFSETS 288 /* +byte offset to free block */ +"/ #define TIFFTAG_FREEBYTECOUNTS 289 /* +sizes of free blocks */ +"/ #define TIFFTAG_GRAYRESPONSEUNIT 290 /* $gray scale curve accuracy */ +"/ #define GRAYRESPONSEUNIT_10S 1 /* tenths of a unit */ +"/ #define GRAYRESPONSEUNIT_100S 2 /* hundredths of a unit */ +"/ #define GRAYRESPONSEUNIT_1000S 3 /* thousandths of a unit */ +"/ #define GRAYRESPONSEUNIT_10000S 4 /* ten-thousandths of a unit */ +"/ #define GRAYRESPONSEUNIT_100000S 5 /* hundred-thousandths */ +"/ #define TIFFTAG_GRAYRESPONSECURVE 291 /* $gray scale response curve */ +"/ #define TIFFTAG_GROUP3OPTIONS 292 /* 32 flag bits */ +"/ #define TIFFTAG_T4OPTIONS 292 /* TIFF 6.0 proper name alias */ +"/ #define GROUP3OPT_2DENCODING 0x1 /* 2-dimensional coding */ +"/ #define GROUP3OPT_UNCOMPRESSED 0x2 /* data not compressed */ +"/ #define GROUP3OPT_FILLBITS 0x4 /* fill to byte boundary */ +"/ #define TIFFTAG_GROUP4OPTIONS 293 /* 32 flag bits */ +"/ #define TIFFTAG_T6OPTIONS 293 /* TIFF 6.0 proper name */ +"/ #define GROUP4OPT_UNCOMPRESSED 0x2 /* data not compressed */ +"/ #define TIFFTAG_RESOLUTIONUNIT 296 /* units of resolutions */ +"/ #define RESUNIT_NONE 1 /* no meaningful units */ +"/ #define RESUNIT_INCH 2 /* english */ +"/ #define RESUNIT_CENTIMETER 3 /* metric */ +"/ #define TIFFTAG_PAGENUMBER 297 /* page numbers of multi-page */ +"/ #define TIFFTAG_COLORRESPONSEUNIT 300 /* $color curve accuracy */ +"/ #define COLORRESPONSEUNIT_10S 1 /* tenths of a unit */ +"/ #define COLORRESPONSEUNIT_100S 2 /* hundredths of a unit */ +"/ #define COLORRESPONSEUNIT_1000S 3 /* thousandths of a unit */ +"/ #define COLORRESPONSEUNIT_10000S 4 /* ten-thousandths of a unit */ +"/ #define COLORRESPONSEUNIT_100000S 5 /* hundred-thousandths */ +"/ #define TIFFTAG_TRANSFERFUNCTION 301 /* !!colorimetry info */ +"/ #define TIFFTAG_SOFTWARE 305 /* name & release */ +"/ #define TIFFTAG_DATETIME 306 /* creation date and time */ +"/ #define TIFFTAG_ARTIST 315 /* creator of image */ +"/ #define TIFFTAG_HOSTCOMPUTER 316 /* machine where created */ +"/ #define TIFFTAG_PREDICTOR 317 /* prediction scheme w/ LZW */ +"/ #define PREDICTOR_NONE 1 /* no prediction scheme used */ +"/ #define PREDICTOR_HORIZONTAL 2 /* horizontal differencing */ +"/ #define PREDICTOR_FLOATINGPOINT 3 /* floating point predictor */ +"/ #define TIFFTAG_WHITEPOINT 318 /* image white point */ +"/ #define TIFFTAG_PRIMARYCHROMATICITIES 319 /* !!primary chromaticities */ +"/ #define TIFFTAG_COLORMAP 320 /* RGB map for palette image */ +"/ #define TIFFTAG_HALFTONEHINTS 321 /* !!highlight+shadow info */ +"/ #define TIFFTAG_TILEWIDTH 322 /* !!tile width in pixels */ +"/ #define TIFFTAG_TILELENGTH 323 /* !!tile height in pixels */ +"/ #define TIFFTAG_TILEOFFSETS 324 /* !!offsets to data tiles */ +"/ #define TIFFTAG_TILEBYTECOUNTS 325 /* !!byte counts for tiles */ +"/ #define TIFFTAG_BADFAXLINES 326 /* lines w/ wrong pixel count */ +"/ #define TIFFTAG_CLEANFAXDATA 327 /* regenerated line info */ +"/ #define CLEANFAXDATA_CLEAN 0 /* no errors detected */ +"/ #define CLEANFAXDATA_REGENERATED 1 /* receiver regenerated lines */ +"/ #define CLEANFAXDATA_UNCLEAN 2 /* uncorrected errors exist */ +"/ #define TIFFTAG_CONSECUTIVEBADFAXLINES 328 /* max consecutive bad lines */ +"/ #define TIFFTAG_SUBIFD 330 /* subimage descriptors */ +"/ #define TIFFTAG_INKSET 332 /* !!inks in separated image */ +"/ #define INKSET_CMYK 1 /* !!cyan-magenta-yellow-black color */ +"/ #define INKSET_MULTIINK 2 /* !!multi-ink or hi-fi color */ +"/ #define TIFFTAG_INKNAMES 333 /* !!ascii names of inks */ +"/ #define TIFFTAG_NUMBEROFINKS 334 /* !!number of inks */ +"/ #define TIFFTAG_DOTRANGE 336 /* !!0% and 100% dot codes */ +"/ #define TIFFTAG_TARGETPRINTER 337 /* !!separation target */ +"/ #define TIFFTAG_EXTRASAMPLES 338 /* !!info about extra samples */ +"/ #define EXTRASAMPLE_UNSPECIFIED 0 /* !!unspecified data */ +"/ #define EXTRASAMPLE_ASSOCALPHA 1 /* !!associated alpha data */ +"/ #define EXTRASAMPLE_UNASSALPHA 2 /* !!unassociated alpha data */ +"/ #define TIFFTAG_SAMPLEFORMAT 339 /* !!data sample format */ +"/ #define SAMPLEFORMAT_UINT 1 /* !!unsigned integer data */ +"/ #define SAMPLEFORMAT_INT 2 /* !!signed integer data */ +"/ #define SAMPLEFORMAT_IEEEFP 3 /* !!IEEE floating point data */ +"/ #define SAMPLEFORMAT_VOID 4 /* !!untyped data */ +"/ #define SAMPLEFORMAT_COMPLEXINT 5 /* !!complex signed int */ +"/ #define SAMPLEFORMAT_COMPLEXIEEEFP 6 /* !!complex ieee floating */ +"/ #define TIFFTAG_SMINSAMPLEVALUE 340 /* !!variable MinSampleValue */ +"/ #define TIFFTAG_SMAXSAMPLEVALUE 341 /* !!variable MaxSampleValue */ +"/ #define TIFFTAG_CLIPPATH 343 /* %ClipPath +"/ [Adobe TIFF technote 2] */ +"/ #define TIFFTAG_XCLIPPATHUNITS 344 /* %XClipPathUnits +"/ [Adobe TIFF technote 2] */ +"/ #define TIFFTAG_YCLIPPATHUNITS 345 /* %YClipPathUnits +"/ [Adobe TIFF technote 2] */ +"/ #define TIFFTAG_INDEXED 346 /* %Indexed +"/ [Adobe TIFF Technote 3] */ +"/ #define TIFFTAG_JPEGTABLES 347 /* %JPEG table stream */ +"/ #define TIFFTAG_OPIPROXY 351 /* %OPI Proxy [Adobe TIFF technote] */ +"/ /* Tags 400-435 are from the TIFF/FX spec */ +"/ #define TIFFTAG_GLOBALPARAMETERSIFD 400 /* !! */ +"/ #define TIFFTAG_PROFILETYPE 401 /* !! */ +"/ #define PROFILETYPE_UNSPECIFIED 0 /* !! */ +"/ #define PROFILETYPE_G3_FAX 1 /* !! */ +"/ #define TIFFTAG_FAXPROFILE 402 /* !! */ +"/ #define FAXPROFILE_S 1 /* !!TIFF/FX FAX profile S */ +"/ #define FAXPROFILE_F 2 /* !!TIFF/FX FAX profile F */ +"/ #define FAXPROFILE_J 3 /* !!TIFF/FX FAX profile J */ +"/ #define FAXPROFILE_C 4 /* !!TIFF/FX FAX profile C */ +"/ #define FAXPROFILE_L 5 /* !!TIFF/FX FAX profile L */ +"/ #define FAXPROFILE_M 6 /* !!TIFF/FX FAX profile LM */ +"/ #define TIFFTAG_CODINGMETHODS 403 /* !!TIFF/FX coding methods */ +"/ #define CODINGMETHODS_T4_1D (1 << 1) /* !!T.4 1D */ +"/ #define CODINGMETHODS_T4_2D (1 << 2) /* !!T.4 2D */ +"/ #define CODINGMETHODS_T6 (1 << 3) /* !!T.6 */ +"/ #define CODINGMETHODS_T85 (1 << 4) /* !!T.85 JBIG */ +"/ #define CODINGMETHODS_T42 (1 << 5) /* !!T.42 JPEG */ +"/ #define CODINGMETHODS_T43 (1 << 6) /* !!T.43 colour by layered JBIG */ +"/ #define TIFFTAG_VERSIONYEAR 404 /* !!TIFF/FX version year */ +"/ #define TIFFTAG_MODENUMBER 405 /* !!TIFF/FX mode number */ +"/ #define TIFFTAG_DECODE 433 /* !!TIFF/FX decode */ +"/ #define TIFFTAG_IMAGEBASECOLOR 434 /* !!TIFF/FX image base colour */ +"/ #define TIFFTAG_T82OPTIONS 435 /* !!TIFF/FX T.82 options */ +"/ /* +"/ * Tags 512-521 are obsoleted by Technical Note #2 which specifies a +"/ * revised JPEG-in-TIFF scheme. +"/ */ +"/ #define TIFFTAG_JPEGPROC 512 /* !!JPEG processing algorithm */ +"/ #define JPEGPROC_BASELINE 1 /* !!baseline sequential */ +"/ #define JPEGPROC_LOSSLESS 14 /* !!Huffman coded lossless */ +"/ #define TIFFTAG_JPEGIFOFFSET 513 /* !!pointer to SOI marker */ +"/ #define TIFFTAG_JPEGIFBYTECOUNT 514 /* !!JFIF stream length */ +"/ #define TIFFTAG_JPEGRESTARTINTERVAL 515 /* !!restart interval length */ +"/ #define TIFFTAG_JPEGLOSSLESSPREDICTORS 517 /* !!lossless proc predictor */ +"/ #define TIFFTAG_JPEGPOINTTRANSFORM 518 /* !!lossless point transform */ +"/ #define TIFFTAG_JPEGQTABLES 519 /* !!Q matrix offsets */ +"/ #define TIFFTAG_JPEGDCTABLES 520 /* !!DCT table offsets */ +"/ #define TIFFTAG_JPEGACTABLES 521 /* !!AC coefficient offsets */ +"/ #define TIFFTAG_YCBCRCOEFFICIENTS 529 /* !!RGB -> YCbCr transform */ +"/ #define TIFFTAG_YCBCRSUBSAMPLING 530 /* !!YCbCr subsampling factors */ +"/ #define TIFFTAG_YCBCRPOSITIONING 531 /* !!subsample positioning */ +"/ #define YCBCRPOSITION_CENTERED 1 /* !!as in PostScript Level 2 */ +"/ #define YCBCRPOSITION_COSITED 2 /* !!as in CCIR 601-1 */ +"/ #define TIFFTAG_REFERENCEBLACKWHITE 532 /* !!colorimetry info */ +"/ #define TIFFTAG_STRIPROWCOUNTS 559 /* !!TIFF/FX strip row counts */ +"/ #define TIFFTAG_XMLPACKET 700 /* %XML packet +"/ [Adobe XMP Specification, +"/ January 2004 */ +"/ #define TIFFTAG_OPIIMAGEID 32781 /* %OPI ImageID +"/ [Adobe TIFF technote] */ + +"/ /* tags 32952-32956 are private tags registered to Island Graphics */ +"/ #define TIFFTAG_REFPTS 32953 /* image reference points */ +"/ #define TIFFTAG_REGIONTACKPOINT 32954 /* region-xform tack point */ +"/ #define TIFFTAG_REGIONWARPCORNERS 32955 /* warp quadrilateral */ +"/ #define TIFFTAG_REGIONAFFINE 32956 /* affine transformation mat */ + +"/ /* tags 32995-32999 are private tags registered to SGI */ +"/ #define TIFFTAG_MATTEING 32995 /* $use ExtraSamples */ +"/ #define TIFFTAG_DATATYPE 32996 /* $use SampleFormat */ +"/ #define TIFFTAG_IMAGEDEPTH 32997 /* z depth of image */ +"/ #define TIFFTAG_TILEDEPTH 32998 /* z depth/data tile */ + +"/ /* tags 33300-33309 are private tags registered to Pixar */ +"/ /* +"/ * TIFFTAG_PIXAR_IMAGEFULLWIDTH and TIFFTAG_PIXAR_IMAGEFULLLENGTH +"/ * are set when an image has been cropped out of a larger image. +"/ * They reflect the size of the original uncropped image. +"/ * The TIFFTAG_XPOSITION and TIFFTAG_YPOSITION can be used +"/ * to determine the position of the smaller image in the larger one. +"/ */ +"/ #define TIFFTAG_PIXAR_IMAGEFULLWIDTH 33300 /* full image size in x */ +"/ #define TIFFTAG_PIXAR_IMAGEFULLLENGTH 33301 /* full image size in y */ +"/ /* Tags 33302-33306 are used to identify special image modes and data +"/ * used by Pixar's texture formats. +"/ */ +"/ #define TIFFTAG_PIXAR_TEXTUREFORMAT 33302 /* texture map format */ +"/ #define TIFFTAG_PIXAR_WRAPMODES 33303 /* s & t wrap modes */ +"/ #define TIFFTAG_PIXAR_FOVCOT 33304 /* cotan(fov) for env. maps */ +"/ #define TIFFTAG_PIXAR_MATRIX_WORLDTOSCREEN 33305 +"/ #define TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA 33306 + +"/ /* tag 33405 is a private tag registered to Eastman Kodak */ +"/ #define TIFFTAG_WRITERSERIALNUMBER 33405 /* device serial number */ + +"/ #define TIFFTAG_CFAREPEATPATTERNDIM 33421 /* dimensions of CFA pattern */ +"/ #define TIFFTAG_CFAPATTERN 33422 /* color filter array pattern */ +"/ /* tag 33432 is listed in the 6.0 spec w/ unknown ownership */ +"/ #define TIFFTAG_COPYRIGHT 33432 /* copyright string */ +"/ /* IPTC TAG from RichTIFF specifications */ +"/ #define TIFFTAG_RICHTIFFIPTC 33723 +"/ /* 34016-34029 are reserved for ANSI IT8 TIFF/IT */ +"/ #define TIFFTAG_STONITS 37439 /* Sample value to Nits */ + +"/ /* tag 34929 is a private tag registered to FedEx */ +"/ #define TIFFTAG_FEDEX_EDR 34929 /* unknown use */ +"/ #define TIFFTAG_INTEROPERABILITYIFD 40965 /* Pointer to Interoperability private directory */ + + "/ + "/ Adobe Digital Negative (DNG) format tags + "/ + +"/ #define TIFFTAG_DNGVERSION 50706 /* &DNG version number */ +"/ #define TIFFTAG_DNGBACKWARDVERSION 50707 /* &DNG compatibility version */ +"/ #define TIFFTAG_UNIQUECAMERAMODEL 50708 /* &name for the camera model */ +"/ #define TIFFTAG_LOCALIZEDCAMERAMODEL 50709 /* &localized camera model name */ +"/ #define TIFFTAG_CFAPLANECOLOR 50710 /* &CFAPattern->LinearRaw space mapping */ +"/ #define TIFFTAG_CFALAYOUT 50711 /* &spatial layout of the CFA */ +"/ #define TIFFTAG_LINEARIZATIONTABLE 50712 /* &lookup table description */ +"/ #define TIFFTAG_BLACKLEVELREPEATDIM 50713 /* &repeat pattern size for the BlackLevel tag */ +"/ #define TIFFTAG_BLACKLEVEL 50714 /* &zero light encoding level */ +"/ #define TIFFTAG_BLACKLEVELDELTAH 50715 /* &zero light encoding level differences (columns) */ +"/ #define TIFFTAG_BLACKLEVELDELTAV 50716 /* &zero light encoding level differences (rows) */ +"/ #define TIFFTAG_WHITELEVEL 50717 /* &fully saturated encoding level */ +"/ #define TIFFTAG_DEFAULTSCALE 50718 /* &default scale factors */ +"/ #define TIFFTAG_DEFAULTCROPORIGIN 50719 /* &origin of the final image area */ +"/ #define TIFFTAG_DEFAULTCROPSIZE 50720 /* &size of the final image area */ +"/ #define TIFFTAG_COLORMATRIX1 50721 /* &XYZ->reference color space transformation matrix 1 */ +"/ #define TIFFTAG_COLORMATRIX2 50722 /* &XYZ->reference color space transformation matrix 2 */ +"/ #define TIFFTAG_CAMERACALIBRATION1 50723 /* &calibration matrix 1 */ +"/ #define TIFFTAG_CAMERACALIBRATION2 50724 /* &calibration matrix 2 */ +"/ #define TIFFTAG_REDUCTIONMATRIX1 50725 /* &dimensionality reduction matrix 1 */ +"/ #define TIFFTAG_REDUCTIONMATRIX2 50726 /* &dimensionality reduction matrix 2 */ +"/ #define TIFFTAG_ANALOGBALANCE 50727 /* &gain applied the stored raw values*/ +"/ #define TIFFTAG_ASSHOTNEUTRAL 50728 /* &selected white balance in linear reference space */ +"/ #define TIFFTAG_ASSHOTWHITEXY 50729 /* &selected white balance in x-y chromaticity coordinates */ +"/ #define TIFFTAG_BASELINEEXPOSURE 50730 /* &how much to move the zero point */ +"/ #define TIFFTAG_BASELINENOISE 50731 /* &relative noise level */ +"/ #define TIFFTAG_BASELINESHARPNESS 50732 /* &relative amount of sharpening */ +"/ #define TIFFTAG_BAYERGREENSPLIT 50733 /* &how closely the values of the green pixels in the blue/green rows track the values of the green pixels in the red/green rows */ +"/ #define TIFFTAG_LINEARRESPONSELIMIT 50734 /* &non-linear encoding range */ +"/ #define TIFFTAG_CAMERASERIALNUMBER 50735 /* &camera's serial number */ +"/ #define TIFFTAG_LENSINFO 50736 /* info about the lens */ +"/ #define TIFFTAG_CHROMABLURRADIUS 50737 /* &chroma blur radius */ +"/ #define TIFFTAG_ANTIALIASSTRENGTH 50738 /* &relative strength of the camera's anti-alias filter */ +"/ #define TIFFTAG_SHADOWSCALE 50739 /* &used by Adobe Camera Raw */ +"/ #define TIFFTAG_DNGPRIVATEDATA 50740 /* &manufacturer's private data */ +"/ #define TIFFTAG_MAKERNOTESAFETY 50741 /* &whether the EXIF MakerNote tag is safe to preserve along with the rest of the EXIF data */ +"/ #define TIFFTAG_CALIBRATIONILLUMINANT1 50778 /* &illuminant 1 */ +"/ #define TIFFTAG_CALIBRATIONILLUMINANT2 50779 /* &illuminant 2 */ +"/ #define TIFFTAG_BESTQUALITYSCALE 50780 /* &best quality multiplier */ +"/ #define TIFFTAG_RAWDATAUNIQUEID 50781 /* &unique identifier for the raw image data */ +"/ #define TIFFTAG_ORIGINALRAWFILENAME 50827 /* &file name of the original raw file */ +"/ #define TIFFTAG_ORIGINALRAWFILEDATA 50828 /* &contents of the original raw file */ +"/ #define TIFFTAG_ACTIVEAREA 50829 /* &active (non-masked) pixels of the sensor */ +"/ #define TIFFTAG_MASKEDAREAS 50830 /* &list of coordinates of fully masked pixels */ +"/ #define TIFFTAG_ASSHOTICCPROFILE 50831 /* &these two tags used to */ +"/ #define TIFFTAG_ASSHOTPREPROFILEMATRIX 50832 /* map cameras's color space into ICC profile space */ +"/ #define TIFFTAG_CURRENTICCPROFILE 50833 /* & */ +"/ #define TIFFTAG_CURRENTPREPROFILEMATRIX 50834 /* & */ + +"/ /* tag 65535 is an undefined tag used by Eastman Kodak */ +"/ #define TIFFTAG_DCSHUESHIFTVALUES 65535 /* hue shift correction data */ +"/ +"/ /* +"/ * The following are ``pseudo tags'' that can be used to control +"/ * codec-specific functionality. These tags are not written to file. +"/ * Note that these values start at 0xffff+1 so that they'll never +"/ * collide with Aldus-assigned tags. +"/ * +"/ * If you want your private pseudo tags ``registered'' (i.e. added to +"/ * this file), please post a bug report via the tracking system at +"/ * http://www.remotesensing.org/libtiff/bugs.html with the appropriate +"/ * C definitions to add. +"/ */ +"/ #define TIFFTAG_FAXMODE 65536 /* Group 3/4 format control */ +"/ #define FAXMODE_CLASSIC 0x0000 /* default, include RTC */ +"/ #define FAXMODE_NORTC 0x0001 /* no RTC at end of data */ +"/ #define FAXMODE_NOEOL 0x0002 /* no EOL code at end of row */ +"/ #define FAXMODE_BYTEALIGN 0x0004 /* byte align row */ +"/ #define FAXMODE_WORDALIGN 0x0008 /* word align row */ +"/ #define FAXMODE_CLASSF FAXMODE_NORTC /* TIFF Class F */ +"/ #define TIFFTAG_JPEGQUALITY 65537 /* Compression quality level */ +"/ /* Note: quality level is on the IJG 0-100 scale. Default value is 75 */ +"/ #define TIFFTAG_JPEGCOLORMODE 65538 /* Auto RGB<=>YCbCr convert? */ +"/ #define JPEGCOLORMODE_RAW 0x0000 /* no conversion (default) */ +"/ #define JPEGCOLORMODE_RGB 0x0001 /* do auto conversion */ +"/ #define TIFFTAG_JPEGTABLESMODE 65539 /* What to put in JPEGTables */ +"/ #define JPEGTABLESMODE_QUANT 0x0001 /* include quantization tbls */ +"/ #define JPEGTABLESMODE_HUFF 0x0002 /* include Huffman tbls */ +"/ /* Note: default is JPEGTABLESMODE_QUANT | JPEGTABLESMODE_HUFF */ +"/ #define TIFFTAG_FAXFILLFUNC 65540 /* G3/G4 fill function */ +"/ #define TIFFTAG_PIXARLOGDATAFMT 65549 /* PixarLogCodec I/O data sz */ +"/ #define PIXARLOGDATAFMT_8BIT 0 /* regular u_char samples */ +"/ #define PIXARLOGDATAFMT_8BITABGR 1 /* ABGR-order u_chars */ +"/ #define PIXARLOGDATAFMT_11BITLOG 2 /* 11-bit log-encoded (raw) */ +"/ #define PIXARLOGDATAFMT_12BITPICIO 3 /* as per PICIO (1.0==2048) */ +"/ #define PIXARLOGDATAFMT_16BIT 4 /* signed short samples */ +"/ #define PIXARLOGDATAFMT_FLOAT 5 /* IEEE float samples */ +"/ /* 65550-65556 are allocated to Oceana Matrix */ +"/ #define TIFFTAG_DCSIMAGERTYPE 65550 /* imager model & filter */ +"/ #define DCSIMAGERMODEL_M3 0 /* M3 chip (1280 x 1024) */ +"/ #define DCSIMAGERMODEL_M5 1 /* M5 chip (1536 x 1024) */ +"/ #define DCSIMAGERMODEL_M6 2 /* M6 chip (3072 x 2048) */ +"/ #define DCSIMAGERFILTER_IR 0 /* infrared filter */ +"/ #define DCSIMAGERFILTER_MONO 1 /* monochrome filter */ +"/ #define DCSIMAGERFILTER_CFA 2 /* color filter array */ +"/ #define DCSIMAGERFILTER_OTHER 3 /* other filter */ +"/ #define TIFFTAG_DCSINTERPMODE 65551 /* interpolation mode */ +"/ #define DCSINTERPMODE_NORMAL 0x0 /* whole image, default */ +"/ #define DCSINTERPMODE_PREVIEW 0x1 /* preview of image (384x256) */ +"/ #define TIFFTAG_DCSBALANCEARRAY 65552 /* color balance values */ +"/ #define TIFFTAG_DCSCORRECTMATRIX 65553 /* color correction values */ +"/ #define TIFFTAG_DCSGAMMA 65554 /* gamma value */ +"/ #define TIFFTAG_DCSTOESHOULDERPTS 65555 /* toe & shoulder points */ +"/ #define TIFFTAG_DCSCALIBRATIONFD 65556 /* calibration file desc */ +"/ /* Note: quality level is on the ZLIB 1-9 scale. Default value is -1 */ +"/ #define TIFFTAG_ZIPQUALITY 65557 /* compression quality level */ +"/ #define TIFFTAG_PIXARLOGQUALITY 65558 /* PixarLog uses same scale */ +"/ /* 65559 is allocated to Oceana Matrix */ +"/ #define TIFFTAG_DCSCLIPRECTANGLE 65559 /* area of image to acquire */ +"/ #define TIFFTAG_SGILOGDATAFMT 65560 /* SGILog user data format */ +"/ #define SGILOGDATAFMT_FLOAT 0 /* IEEE float samples */ +"/ #define SGILOGDATAFMT_16BIT 1 /* 16-bit samples */ +"/ #define SGILOGDATAFMT_RAW 2 /* uninterpreted data */ +"/ #define SGILOGDATAFMT_8BIT 3 /* 8-bit RGB monitor values */ +"/ #define TIFFTAG_SGILOGENCODE 65561 /* SGILog data encoding control*/ +"/ #define SGILOGENCODE_NODITHER 0 /* do not dither encoded values*/ +"/ #define SGILOGENCODE_RANDITHER 1 /* randomly dither encd values */ +"/ #define TIFFTAG_LZMAPRESET 65562 /* LZMA2 preset (compression level) */ +"/ #define TIFFTAG_PERSAMPLE 65563 /* interface for per sample tags */ +"/ #define PERSAMPLE_MERGED 0 /* present as a single value */ +"/ #define PERSAMPLE_MULTI 1 /* present as multiple values */ + + "/ + "/ EXIF tags + "/ +"/ #define EXIFTAG_EXPOSURETIME 33434 /* Exposure time */ +"/ #define EXIFTAG_FNUMBER 33437 /* F number */ +"/ #define EXIFTAG_EXPOSUREPROGRAM 34850 /* Exposure program */ +"/ #define EXIFTAG_SPECTRALSENSITIVITY 34852 /* Spectral sensitivity */ +"/ #define EXIFTAG_ISOSPEEDRATINGS 34855 /* ISO speed rating */ +"/ #define EXIFTAG_OECF 34856 /* Optoelectric conversion factor */ +"/ #define EXIFTAG_EXIFVERSION 36864 /* Exif version */ +"/ #define EXIFTAG_DATETIMEORIGINAL 36867 /* Date and time of original data generation */ +"/ #define EXIFTAG_DATETIMEDIGITIZED 36868 /* Date and time of digital data generation */ +"/ #define EXIFTAG_COMPONENTSCONFIGURATION 37121 /* Meaning of each component */ +"/ #define EXIFTAG_COMPRESSEDBITSPERPIXEL 37122 /* Image compression mode */ +"/ #define EXIFTAG_SHUTTERSPEEDVALUE 37377 /* Shutter speed */ +"/ #define EXIFTAG_APERTUREVALUE 37378 /* Aperture */ +"/ #define EXIFTAG_BRIGHTNESSVALUE 37379 /* Brightness */ +"/ #define EXIFTAG_EXPOSUREBIASVALUE 37380 /* Exposure bias */ +"/ #define EXIFTAG_MAXAPERTUREVALUE 37381 /* Maximum lens aperture */ +"/ #define EXIFTAG_SUBJECTDISTANCE 37382 /* Subject distance */ +"/ #define EXIFTAG_METERINGMODE 37383 /* Metering mode */ +"/ #define EXIFTAG_LIGHTSOURCE 37384 /* Light source */ +"/ #define EXIFTAG_FLASH 37385 /* Flash */ +"/ #define EXIFTAG_FOCALLENGTH 37386 /* Lens focal length */ +"/ #define EXIFTAG_SUBJECTAREA 37396 /* Subject area */ +"/ #define EXIFTAG_MAKERNOTE 37500 /* Manufacturer notes */ +"/ #define EXIFTAG_USERCOMMENT 37510 /* User comments */ +"/ #define EXIFTAG_SUBSECTIME 37520 /* DateTime subseconds */ +"/ #define EXIFTAG_SUBSECTIMEORIGINAL 37521 /* DateTimeOriginal subseconds */ +"/ #define EXIFTAG_SUBSECTIMEDIGITIZED 37522 /* DateTimeDigitized subseconds */ +"/ #define EXIFTAG_FLASHPIXVERSION 40960 /* Supported Flashpix version */ +"/ #define EXIFTAG_COLORSPACE 40961 /* Color space information */ +"/ #define EXIFTAG_PIXELXDIMENSION 40962 /* Valid image width */ +"/ #define EXIFTAG_PIXELYDIMENSION 40963 /* Valid image height */ +"/ #define EXIFTAG_RELATEDSOUNDFILE 40964 /* Related audio file */ +"/ #define EXIFTAG_FLASHENERGY 41483 /* Flash energy */ +"/ #define EXIFTAG_SPATIALFREQUENCYRESPONSE 41484 /* Spatial frequency response */ +"/ #define EXIFTAG_FOCALPLANEXRESOLUTION 41486 /* Focal plane X resolution */ +"/ #define EXIFTAG_FOCALPLANEYRESOLUTION 41487 /* Focal plane Y resolution */ +"/ #define EXIFTAG_FOCALPLANERESOLUTIONUNIT 41488 /* Focal plane resolution unit */ +"/ #define EXIFTAG_SUBJECTLOCATION 41492 /* Subject location */ +"/ #define EXIFTAG_EXPOSUREINDEX 41493 /* Exposure index */ +"/ #define EXIFTAG_SENSINGMETHOD 41495 /* Sensing method */ +"/ #define EXIFTAG_FILESOURCE 41728 /* File source */ +"/ #define EXIFTAG_SCENETYPE 41729 /* Scene type */ +"/ #define EXIFTAG_CFAPATTERN 41730 /* CFA pattern */ +"/ #define EXIFTAG_CUSTOMRENDERED 41985 /* Custom image processing */ +"/ #define EXIFTAG_EXPOSUREMODE 41986 /* Exposure mode */ +"/ #define EXIFTAG_WHITEBALANCE 41987 /* White balance */ +"/ #define EXIFTAG_DIGITALZOOMRATIO 41988 /* Digital zoom ratio */ +"/ #define EXIFTAG_FOCALLENGTHIN35MMFILM 41989 /* Focal length in 35 mm film */ +"/ #define EXIFTAG_SCENECAPTURETYPE 41990 /* Scene capture type */ +"/ #define EXIFTAG_GAINCONTROL 41991 /* Gain control */ +"/ #define EXIFTAG_CONTRAST 41992 /* Contrast */ +"/ #define EXIFTAG_SATURATION 41993 /* Saturation */ +"/ #define EXIFTAG_SHARPNESS 41994 /* Sharpness */ +"/ #define EXIFTAG_DEVICESETTINGDESCRIPTION 41995 /* Device settings description */ +"/ #define EXIFTAG_SUBJECTDISTANCERANGE 41996 /* Subject distance range */ +"/ #define EXIFTAG_GAINCONTROL 41991 /* Gain control */ +"/ #define EXIFTAG_GAINCONTROL 41991 /* Gain control */ +"/ #define EXIFTAG_IMAGEUNIQUEID 42016 /* Unique image ID */ + " self initialize " - "Modified: 1.2.1997 / 15:00:01 / cg" + "Modified: / 27-08-2017 / 15:29:24 / cg" ! ! !TIFFReader class methodsFor:'testing'! @@ -116,33 +710,67 @@ ! isValidImageFile:aFileName - "return true, if aFileName contains a GIF image" - - |inStream char1 char2 version| + "return true, if aFileName contains a TIFF image" + + |inStream bytes1_2 byte3 byte4 versionLow versionHi| inStream := self streamReadingFile:aFileName. inStream isNil ifTrue:[^ false]. - char1 := inStream next. - char2 := inStream next. - - ((char1 ~~ char2) or:[(char1 ~~ $I) and:[char1 ~~ $M]]) ifTrue:[ - inStream close. - ^ false + bytes1_2 := inStream next:2. + byte3 := inStream nextByte. + byte4 := inStream nextByte. + inStream close. + + ((bytes1_2 = 'II' "tiff") or:[bytes1_2 = 'PE' "mdi"]) ifTrue:[ + "/ intel byte order (lsb) + versionLow := byte3. versionHi := byte4. + ] ifFalse:[ + ((bytes1_2 = 'MM' "tiff") or:[bytes1_2 = 'EP' "mdi"]) ifTrue:[ + "/ motorola byte order (msb) + versionLow := byte4. versionHi := byte3. + ] ifFalse:[ + ^ false + ]. + ]. + versionHi == 0 ifTrue:[ + (versionLow == 42) ifTrue:[^ true]. "/ tiff + (versionLow == 43) ifTrue:[^ true]. "/ bigtiff ]. - - inStream binary. - version := inStream nextInt16MSB:(char1 == $M). - inStream close. - - "/ 43 is bigTiff - ^ (version == 42) or:[ (version == 43) ] - - "Modified: / 25-08-2017 / 08:39:20 / cg" + ^ false. + + "Modified: / 26-08-2017 / 15:31:08 / cg" +! ! + +!TIFFReader methodsFor:'accessing'! + +decodeMetaTags:aBoolean + "by default, extra meta tags (photoshop) are not decoded; + set to true to get them in metatags" + + decodeMetaTags := aBoolean. + + "Modified (comment): / 27-08-2017 / 18:37:04 / cg" +! + +loadFullResolutionImage:aBoolean + "by default, the full-resolution dng image is not decoded; + set to true to get it in the imageSequence" + + loadFullResolutionImage := aBoolean. + + "Created: / 27-08-2017 / 18:41:48 / cg" ! ! !TIFFReader methodsFor:'private-data reading'! +readAdobeDeflateTiffImageData + ^ self readDeflateTiffImageData + + "Created: / 26-08-2017 / 14:44:35 / cg" + "Modified: / 27-08-2017 / 18:55:11 / cg" +! + readCCITT3RLETiffImageData ^ self fileFormatError:'ccitt G3 mod Huffman (rle) compression not implemented' @@ -162,12 +790,13 @@ stripNr "{ Class: SmallInteger }" offset "{ Class: SmallInteger }" row "{ Class: SmallInteger }" - bytesPerStrip "{ Class: SmallInteger }" | + bytesPerStrip "{ Class: SmallInteger }" + count dstIndex| nPlanes := samplesPerPixel. (nPlanes ~~ 1) ifTrue:[ (nPlanes == 2) ifTrue:[ - (planarConfiguration ~~ 2) ifTrue:[ + (planarConfiguration ~~ PLANARCONFIG_SEPARATE) ifTrue:[ ^ self fileFormatError:'only separate planes are supported'. ]. 'TIFFReader [info]: ignoring alpha plane' infoPrintCR. @@ -176,6 +805,9 @@ ^ self fileFormatError:'only monochrome/greyscale ccitt3supported'. ]. ]. + stripRowCounts notNil ifTrue:[ + ^ self fileFormatError:'stripRowCounts not supported'. + ]. "/ (rowsPerStrip ~~ 1) ifTrue:[ "/ ^ self fileFormatError:'currently require rowsPerStrip to be 1'. @@ -194,38 +826,54 @@ "/ if the number of rows per strip is unknown (-1), "/ make it one big strip and decompress that rowsPerStrip = 16rFFFFFFFF ifTrue:[ - compressedStrip := ByteArray uninitializedNew:(stripByteCounts sum). + self assert:(stripByteCounts size == 1). + count := stripByteCounts sum. + compressedStrip := ByteArray uninitializedNew:count. self positionToStrip:1. - inStream nextBytes:(compressedStrip size) into:compressedStrip. - self class - decompressCCITT3From:compressedStrip - into:data - startingAt:1 - count:compressedStrip size. + + (inStream nextBytes:count into:compressedStrip) == count ifFalse:[ + self error:'short read' + ]. + + compressedStrip := compressedStrip copyFrom:16r227. + + dstIndex := self class + _decompressCCITT3From:compressedStrip + count:count + into:data + startingAt:1. ^ self ]. compressedStrip := ByteArray uninitializedNew:bytesPerRow. offset := 1. - stripNr := 0. + stripNr := 1. row := 1. bytesPerStrip := bytesPerRow * rowsPerStrip. [row <= height] whileTrue:[ + self positionToStrip:stripNr. + count := stripByteCounts at:stripNr. + (inStream nextBytes:count into:compressedStrip) == count ifFalse:[ + self error:'short read' + ]. + dstIndex := self class + _decompressCCITT3From:compressedStrip + count:count + into:data + startingAt:offset + count:width. "/ is this correct? - I think, that should be width*rowsPerStrip + offset := offset + bytesPerStrip. + row := row + rowsPerStrip. stripNr := stripNr + 1. - self positionToStrip:stripNr. - inStream nextBytes:(stripByteCounts at:stripNr) into:compressedStrip. - self class - decompressCCITT3From:compressedStrip - into:data - startingAt:offset - count:width. - offset := offset + bytesPerStrip. - row := row + rowsPerStrip ] - "Modified: / 25-08-2017 / 11:09:02 / cg" + " + TIFFReader fromFile:'/Users/cg/DownloadsUnsaved/image_software/libtiffpic/g3test.tif' + " + + "Modified: / 27-08-2017 / 15:37:51 / cg" ! readCCITTGroup4TiffImageData @@ -245,9 +893,137 @@ ! readDeflateTiffImageData - ^ self fileFormatError:'deflate compression not implemented'. - - "Modified: / 3.2.1998 / 18:04:54 / cg" + |bytesPerRowIn bytesPerRow nPlanes overAllBytes + bytesPerStrip "{ Class: SmallInteger }" + nBytes "{ Class: SmallInteger }" + stripNr "{ Class: SmallInteger }" + offset "{ Class: SmallInteger }" + row "{ Class: SmallInteger }" + zlibReader nread msb + convertFloats convertDoubles conversionBuffer| + + nPlanes := samplesPerPixel. + convertFloats := convertDoubles := false. + + (nPlanes >= 3) ifTrue:[ + bytesPerRowIn := width * ((bitsPerSample sum + 7) // 8). + (bitsPerSample conform:[:each | each == 8]) ifTrue:[ + sampleFormat == SAMPLEFORMAT_UINT ifFalse:[ + ^ self fileFormatError:'unsupported sample format'. + ]. + ] ifFalse:[ + sampleFormat == SAMPLEFORMAT_IEEEFP ifTrue:[ + nPlanes == 3 ifTrue:[ + (bitsPerSample conform:[:each | each == 64]) ifTrue:[ + convertDoubles := true. + bytesPerRow := width * nPlanes. + bitsPerSample := #(8 8 8). + ] ifFalse:[ + (bitsPerSample conform:[:each | each == 32]) ifTrue:[ + convertFloats := true. + bytesPerRow := width * nPlanes. + bitsPerSample := #(8 8 8). + ] ifFalse:[ + ^ self fileFormatError:'only 64/64/64 bits/sample are supported with IEEE_FP samples'. + ]. + ]. + ] ifFalse:[ + ^ self fileFormatError:'only support 3 planes with IEEE_FP sample format'. + ] + ] ifFalse:[ + ^ self fileFormatError:'unsupported sample format'. + ]. + ] + ] ifFalse:[ + (nPlanes == 2) ifTrue:[ + (planarConfiguration ~~ PLANARCONFIG_SEPARATE) ifTrue:[ + ^ self fileFormatError:'only separate planes are supported'. + ]. + 'TIFFReader [info]: ignoring alpha plane' infoPrintCR. + nPlanes := 1 + ]. + (nPlanes == 1) ifFalse:[ + ^ self fileFormatError:'unsupported nPlanes: ' , nPlanes printString, '; only 3-sample rgb / monochrome supported'. + ]. + bytesPerRowIn := (width * (bitsPerSample at:1) + 7) // 8. + ]. + stripRowCounts notNil ifTrue:[ + ^ self fileFormatError:'stripRowCounts not supported'. + ]. + + "/ 'TIFFReader: decompressing Deflate ...' infoPrintNL. + + bytesPerRow isNil ifTrue:[ bytesPerRow := bytesPerRowIn ]. + + overAllBytes := bytesPerRow * height. + data := ByteArray new:overAllBytes. + (convertFloats or:[convertDoubles]) ifTrue:[ + conversionBuffer := ByteArray new:(bytesPerRowIn * rowsPerStrip). + ]. + + offset := 1. + stripNr := 0. + + row := 1. + bytesPerStrip := bytesPerRow * rowsPerStrip. + + [row <= height] whileTrue:[ + stripNr := stripNr + 1. + self positionToStrip:stripNr. + nBytes := stripByteCounts at:stripNr. + + zlibReader := ZipStream readOpenAsZipStreamOn:inStream suppressHeaderAndChecksum:false. + zlibReader binary. + + conversionBuffer notNil ifTrue:[ + nread := zlibReader next:nBytes into:conversionBuffer startingAt:1. + msb := (byteOrder == #msb). + convertFloats ifTrue:[ + |i| + + self assert:(nread \\ 4) == 0. + i := 0. + 1 to:nread-1 by:4 do:[:iF | + |dVal byteVal| + dVal := conversionBuffer floatAt:iF MSB:msb. + "/ rescale from 0..1 to 0..255 + byteVal := (dVal * 255) asInteger clampBetween:0 and:255. + data at:offset+i put:byteVal. + i := i + 1. + ]. + ] ifFalse:[ + convertDoubles ifTrue:[ + |i| + + self assert:(nread \\ 8) == 0. + i := 0. + 1 to:nread-1 by:8 do:[:iF | + |dVal byteVal| + dVal := conversionBuffer doubleAt:iF MSB:msb. + "/ rescale from 0..1 to 0..255 + byteVal := (dVal * 255) asInteger clampBetween:0 and:255. + data at:offset+i put:byteVal. + i := i + 1. + ]. + ] + ]. + ] ifFalse:[ + nread := zlibReader next:nBytes into:data startingAt:offset. + ]. + + offset := offset + bytesPerStrip. + row := row + rowsPerStrip + ]. + + (predictor ~~ 1) ifTrue:[ + (predictor == 2) ifTrue:[ + self class decodeDelta:nPlanes in:data width:width height:height + ] ifFalse:[ + ^ self fileFormatError:'unsupported predictor' + ]. + ] + + "Modified: / 27-08-2017 / 15:38:08 / cg" ! readJBIGTiffImageData @@ -257,9 +1033,24 @@ ! readJPEGTiffImageData - ^ self fileFormatError:'jpeg compression not implemented'. - - "Modified: / 3.2.1998 / 18:05:12 / cg" + |nBytes compressedData| + + stripByteCounts size == 1 ifTrue:[ + "/ single strip + self positionToStrip:1. + nBytes := stripByteCounts at:1. + compressedData := ByteArray uninitializedNew:nBytes. + (inStream nextBytes:nBytes into:compressedData) == nBytes ifFalse:[ self error:'short read' ]. + "/ pngOrJPGImage := JPEGReader fromStream:compressedData readStream. + "/ self halt. + ]. + stripRowCounts notNil ifTrue:[ + ^ self fileFormatError:'stripRowCounts not supported'. + ]. + + ^ self fileFormatError:'jpeg (old) compression not implemented'. + + "Modified: / 27-08-2017 / 15:38:23 / cg" ! readLZWTiffImageData @@ -286,7 +1077,7 @@ bytesPerRow := width * samplesPerPixel. ] ifFalse:[ (nPlanes == 2) ifTrue:[ - (planarConfiguration ~~ 2) ifTrue:[ + (planarConfiguration ~~ PLANARCONFIG_SEPARATE) ifTrue:[ ^ self fileFormatError:'only separate planes are supported'. ]. 'TIFFReader [info]: ignoring alpha plane' infoPrintCR. @@ -297,6 +1088,9 @@ ]. bytesPerRow := (width * (bitsPerSample at:1) + 7) // 8. ]. + stripRowCounts notNil ifTrue:[ + ^ self fileFormatError:'stripRowCounts not supported'. + ]. "/ 'TIFFReader: decompressing LZW ...' infoPrintNL. @@ -321,7 +1115,7 @@ compressedStrip := ByteArray uninitializedNew:nBytes. prevSize := nBytes ]. - inStream nextBytes:nBytes into:compressedStrip. + (inStream nextBytes:nBytes into:compressedStrip) == nBytes ifFalse:[ self fileFormatError:'short file' ]. self class decompressLZWFrom:compressedStrip count:nBytes into:data startingAt:offset. @@ -329,11 +1123,15 @@ row := row + rowsPerStrip ]. - (predictor == 2) ifTrue:[ - self class decodeDelta:nPlanes in:data width:width height:height + predictor ~~ 1 ifTrue:[ + (predictor == 2) ifTrue:[ + self class decodeDelta:nPlanes in:data width:width height:height + ] ifFalse:[ + self fileFormatError:'unsupported predictor' + ] ] - "Modified: / 25-08-2017 / 10:09:03 / cg" + "Modified: / 27-08-2017 / 15:38:30 / cg" ! readNeXTJPEGTiffImageData @@ -359,9 +1157,7 @@ stripNr "{ Class: SmallInteger }" offset "{ Class: SmallInteger }" row "{ Class: SmallInteger }" - nBytes "{ Class: SmallInteger }" - nDecompressedBytes "{ Class: SmallInteger }" - bitsPerPixel overAllBytes buffer| + nBytes "{ Class: SmallInteger }" bitsPerPixel overAllBytes buffer| nPlanes := samplesPerPixel. @@ -370,7 +1166,7 @@ or rgb - if non separate planes and no alpha" (nPlanes == 2) ifTrue:[ - (planarConfiguration ~~ 2) ifTrue:[ + (planarConfiguration ~~ PLANARCONFIG_SEPARATE) ifTrue:[ ^ self fileFormatError:'with alpha, only separate planes supported'. ]. 'TIFFReader [info]: ignoring alpha plane' infoPrintCR. @@ -380,7 +1176,7 @@ samplesPerPixel := 1. ] ifFalse:[ (nPlanes == 3) ifTrue:[ - (planarConfiguration ~~ 1) ifTrue:[ + (planarConfiguration ~~ PLANARCONFIG_CONTIG) ifTrue:[ ^ self fileFormatError:'only non separate planes supported'. ]. bitsPerSample ~= #(8 8 8) ifTrue:[ @@ -394,6 +1190,9 @@ bitsPerPixel := bitsPerSample at:1. ] ]. + stripRowCounts notNil ifTrue:[ + ^ self fileFormatError:'stripRowCounts not supported'. + ]. bitsPerRow := width * bitsPerPixel. bytesPerRow := bitsPerRow // 8. @@ -409,12 +1208,11 @@ ]. offset := 1. - stripNr := 0. + stripNr := 1. buffer := nil. row := 1. [row <= height] whileTrue:[ - stripNr := stripNr + 1. nBytes := stripByteCounts at:stripNr. self positionToStrip:stripNr. @@ -422,15 +1220,18 @@ "/ realloc buffer := ByteArray uninitializedNew:nBytes. ]. - inStream nextBytes:nBytes into:buffer. - nDecompressedBytes := self class decompressPackBitsFrom:buffer at:1 to:data at:offset count:nBytes. + (inStream nextBytes:nBytes into:buffer) == nBytes ifFalse:[ + self fileFormatError:'short file read' + ]. + self class decompressTiffPackBitsFrom:buffer to:data at:offset count:(bytesPerRow * rowsPerStrip). "/ nDecompressedBytes := self class decompressPackBits:nBytes from:buffer to:data startingAt:offset. - offset := offset + nDecompressedBytes. - row := row + rowsPerStrip + offset := offset + (bytesPerRow * rowsPerStrip). + row := row + rowsPerStrip. + stripNr := stripNr + 1. ] - "Modified: / 25-08-2017 / 02:02:20 / cg" + "Modified: / 27-08-2017 / 15:38:37 / cg" ! readPixarFilmTiffImageData @@ -471,7 +1272,7 @@ nPlanes := samplesPerPixel. (nPlanes == 2) ifTrue:[ - (planarConfiguration ~~ 2) ifTrue:[ + (planarConfiguration ~~ PLANARCONFIG_SEPARATE) ifTrue:[ ^ self fileFormatError:'only separate planes are supported'. ]. 'TIFFReader [info]: ignoring alpha plane' infoPrintCR. @@ -483,6 +1284,10 @@ (bitsPerSample at:1) == 4 ifFalse:[ ^ self fileFormatError:('unsupported bitsPerSample: %1 (only 4 supported)' bindWith:(bitsPerSample at:1)). ]. + stripRowCounts notNil ifTrue:[ + ^ self fileFormatError:'stripRowCounts not supported'. + ]. + bytesPerRow := (width * (bitsPerSample at:1) + 7) // 8. "/ 'TIFFReader: decompressing ThunderScan ...' infoPrintNL. @@ -586,79 +1391,103 @@ ^ self fileFormatError:('unsupported predictor: %1' bindWith:predictor). ]. - "Modified: / 25-08-2017 / 17:43:00 / cg" + "Modified: / 27-08-2017 / 15:38:47 / cg" ! readTiffImageData - (compression == 1) ifTrue:[ - ^ self readUncompressedTiffImageData. + (compression == COMPRESSION_NONE " 1 " ) ifTrue:[ + self readUncompressedTiffImageData. + ^ self ]. - (compression == 2) ifTrue:[ - ^ self readCCITT3RLETiffImageData. + (compression == COMPRESSION_CCITTRLE " 2 ") ifTrue:[ + self readCCITT3RLETiffImageData. + ^ self ]. - (compression == 3) ifTrue:[ - ^ self readCCITTGroup3TiffImageData. + (compression == COMPRESSION_CCITTFAX3 " 3 ") ifTrue:[ + self readCCITTGroup3TiffImageData. + ^ self ]. - (compression == 4) ifTrue:[ - ^ self readCCITTGroup4TiffImageData. + (compression == COMPRESSION_CCITTFAX4 " 4 ") ifTrue:[ + self readCCITTGroup4TiffImageData. + ^ self ]. - (compression == 5) ifTrue:[ - ^ self readLZWTiffImageData. + (compression == COMPRESSION_LZW " 5 ") ifTrue:[ + self readLZWTiffImageData. + ^ self ]. - (compression == 6) ifTrue:[ - ^ self readJPEGTiffImageData. + (compression == COMPRESSION_OJPEG " 6 ") ifTrue:[ + self readJPEGTiffImageData. + ^ self + ]. + (compression == COMPRESSION_JPEG " 7 ") ifTrue:[ + self readNewJPEGTiffImageData. + ^ self ]. - (compression == 7) ifTrue:[ - ^ self readNewJPEGTiffImageData. + (compression == COMPRESSION_ADOBE_DEFLATE " 8 ") ifTrue:[ + self readAdobeDeflateTiffImageData. + ^ self ]. - (compression == 32766) ifTrue:[ - ^ self readNeXTRLE2TiffImageData. + (compression == COMPRESSION_NEXT " 32766 ") ifTrue:[ + self readNeXTRLE2TiffImageData. + ^ self ]. - (compression == 32771) ifTrue:[ - ^ self readCCITTRLEWTiffImageData. + (compression == COMPRESSION_CCITTRLEW " 32771 ") ifTrue:[ + self readCCITTRLEWTiffImageData. + ^ self ]. - (compression == 32773) ifTrue:[ - ^ self readPackbitsTiffImageData. + (compression == COMPRESSION_PACKBITS " 32773 ") ifTrue:[ + self readPackbitsTiffImageData. + ^ self ]. - (compression == 32809) ifTrue:[ - ^ self readThunderScanTiffImageData. + (compression == COMPRESSION_THUNDERSCAN " 32809 ") ifTrue:[ + self readThunderScanTiffImageData. + ^ self ]. - (compression == 32908) ifTrue:[ - ^ self readPixarFilmTiffImageData. + (compression == COMPRESSION_PIXARFILM " 32908 ") ifTrue:[ + self readPixarFilmTiffImageData. + ^ self ]. - (compression == 32909) ifTrue:[ - ^ self readPixarLogTiffImageData. + (compression == COMPRESSION_PIXARLOG " 32909 ") ifTrue:[ + self readPixarLogTiffImageData. + ^ self ]. - (compression == 32946) ifTrue:[ - ^ self readDeflateTiffImageData. + (compression == COMPRESSION_DEFLATE " 32946 ") ifTrue:[ + self readDeflateTiffImageData. + ^ self ]. - (compression == 32947) ifTrue:[ - ^ self readDCSTiffImageData. + (compression == COMPRESSION_DCS " 32947 ") ifTrue:[ + self readDCSTiffImageData. + ^ self ]. - (compression == 32865) ifTrue:[ - ^ self readNeXTJPEGTiffImageData. - ]. - (compression == 34661) ifTrue:[ - ^ self readJBIGTiffImageData. + (compression == COMPRESSION_NEXT_JPEG " 32865 ") ifTrue:[ + self readNeXTJPEGTiffImageData. + ^ self ]. - (compression == 34676) ifTrue:[ - ^ self readSGI32TiffImageData. + (compression == COMPRESSION_JBIG " 34661 ") ifTrue:[ + self readJBIGTiffImageData. + ^ self ]. - (compression == 34677) ifTrue:[ - ^ self readSGI24TiffImageData. + (compression == COMPRESSION_SGILOG " 34676 ") ifTrue:[ + self readSGI32TiffImageData. + ^ self ]. - - ^ self fileFormatError:('compression type ' , compression printString , ' not known'). + (compression == COMPRESSION_SGILOG24 " 34677 ") ifTrue:[ + self readSGI24TiffImageData. + ^ self + ]. + + self fileFormatError:('compression type ' , compression printString , ' not known'). "Created: / 11-04-1997 / 00:19:44 / cg" - "Modified: / 25-08-2017 / 11:17:25 / cg" + "Modified: / 26-08-2017 / 21:46:56 / cg" ! readTiledJPEGTiffImageData - ^ self fileFormatError:'jpeg compression not implemented (in tile mode)'. + ^ self fileFormatError:'tiled jpeg (old) compression not implemented'. "Created: / 25-08-2017 / 16:27:28 / cg" + "Modified: / 26-08-2017 / 13:39:04 / cg" ! readTiledLZWTiffImageData @@ -667,21 +1496,34 @@ "Created: / 25-08-2017 / 01:05:13 / cg" ! +readTiledNewJPEGTiffImageData + ^ self fileFormatError:'tiled new jpeg compression not implemented'. + + "Created: / 26-08-2017 / 13:37:51 / cg" +! + readTiledTiffImageData - (compression == 1) ifTrue:[ - ^ self readTiledUncompressedTiffImageData. + (compression == COMPRESSION_NONE " 1 ") ifTrue:[ + self readTiledUncompressedTiffImageData. + ^ self ]. - (compression == 5) ifTrue:[ - ^ self readTiledLZWTiffImageData. + (compression == COMPRESSION_LZW " 5 ") ifTrue:[ + self readTiledLZWTiffImageData. + ^ self ]. - (compression == 6) ifTrue:[ - ^ self readTiledJPEGTiffImageData. + (compression == COMPRESSION_OJPEG " 6 ") ifTrue:[ + self readTiledJPEGTiffImageData. + ^ self ]. - - ^ self fileFormatError:('compression type ' , compression printString , ' not supported (in tile mode)'). + (compression == COMPRESSION_JPEG " 7 ") ifTrue:[ + self readTiledNewJPEGTiffImageData. + ^ self + ]. + + self fileFormatError:('tiled compression type ' , compression printString , ' not supported'). "Created: / 25-08-2017 / 00:19:14 / cg" - "Modified: / 25-08-2017 / 16:27:40 / cg" + "Modified: / 26-08-2017 / 13:39:15 / cg" ! readTiledUncompressedTiffImageData @@ -703,20 +1545,14 @@ imageOffset "{ Class: SmallInteger }" tileOffset "{ Class: SmallInteger }" dataOffset "{ Class: SmallInteger }" - tilePos tile - tileWidth tileLength tileOffsets tileByteCounts| - - tileWidth := metaData at:#TileWidth. - tileLength := metaData at:#TileLength. - tileOffsets := metaData at:#TileOffsets. - tileByteCounts := metaData at:#TileByteCounts. + tilePos tile tH tW tb| nPlanes := samplesPerPixel. "/ not all formats are supported here, (nPlanes == 2) ifTrue:[ - (planarConfiguration ~~ 2) ifTrue:[ + (planarConfiguration ~~ PLANARCONFIG_SEPARATE) ifTrue:[ ^ self fileFormatError:'with alpha, only separate planes supported'. ]. 'TIFFReader [info]: ignoring alpha plane' infoPrintCR. @@ -726,7 +1562,7 @@ samplesPerPixel := 1. ] ifFalse:[ (nPlanes == 4) ifTrue:[ - (planarConfiguration ~~ 1) ifTrue:[ + (planarConfiguration ~~ PLANARCONFIG_CONTIG) ifTrue:[ ^ self fileFormatError:'only non separate planes supported'. ]. bitsPerSample ~= #(8 8 8 8) ifTrue:[ @@ -735,7 +1571,7 @@ bitsPerPixel := 32. ] ifFalse:[ (nPlanes == 3) ifTrue:[ - (planarConfiguration ~~ 1) ifTrue:[ + (planarConfiguration ~~ PLANARCONFIG_CONTIG) ifTrue:[ ^ self fileFormatError:'only non separate planes supported'. ]. bitsPerSample ~= #(8 8 8) ifTrue:[ @@ -750,18 +1586,15 @@ ] ] ]. + stripRowCounts notNil ifTrue:[ + ^ self fileFormatError:'stripRowCounts not supported'. + ]. bitsPerRow := width * bitsPerPixel. - bytesPerRow := bitsPerRow // 8. - ((bitsPerRow \\ 8) ~~ 0) ifTrue:[ - bytesPerRow := bytesPerRow + 1 - ]. + bytesPerRow := (bitsPerRow + 7) // 8. bitsPerTileRow := tileWidth * bitsPerPixel. - bytesPerTileRow := bitsPerTileRow // 8. - ((bitsPerTileRow \\ 8) ~~ 0) ifTrue:[ - bytesPerTileRow := bytesPerTileRow + 1 - ]. + bytesPerTileRow := (bitsPerTileRow + 7) // 8. overAllBytes := bytesPerRow * height. data := ByteArray new:overAllBytes. @@ -771,6 +1604,10 @@ y := 0. imageRowOffset := 1. [ y < height ] whileTrue:[ + tH := tileLength. + (y+tileLength) > height ifTrue:[ + tH := height - y. + ]. x := 0. imageOffset := imageRowOffset. [ x < width ] whileTrue:[ @@ -788,8 +1625,14 @@ "/ copy the tile. tileOffset := 1. dataOffset := imageOffset. - 1 to:tileLength do:[:yT | - data replaceFrom:dataOffset to:dataOffset+bytesPerTileRow-1 with:tile startingAt:tileOffset. + tW := tileWidth. + tb := bytesPerTileRow. + (x+tileWidth) > width ifTrue:[ + tW := width-x. + tb := ((bitsPerPixel * bitsPerPixel) + 7) // 8. + ]. + 1 to:tH do:[:yT | + data replaceFrom:dataOffset to:dataOffset+tb-1 with:tile startingAt:tileOffset. dataOffset := dataOffset + bytesPerRow. tileOffset := tileOffset + bytesPerTileRow. ]. @@ -798,14 +1641,15 @@ "/ row := row + rowsPerStrip. where := where + nBytes. - x := x + tileWidth. + x := x + tW. imageOffset := imageOffset + bytesPerTileRow. ]. - y := y + tileLength. - imageRowOffset := imageRowOffset + (bytesPerRow*tileLength). + y := y + tH. + imageRowOffset := imageRowOffset + (bytesPerRow*tH). ]. "Created: / 25-08-2017 / 00:22:31 / cg" + "Modified: / 27-08-2017 / 15:39:02 / cg" ! readUncompressedTiffImageData @@ -826,7 +1670,7 @@ "/ not all formats are supported here, (nPlanes == 2) ifTrue:[ - (planarConfiguration ~~ 2) ifTrue:[ + (planarConfiguration ~~ PLANARCONFIG_SEPARATE) ifTrue:[ ^ self fileFormatError:'with alpha, only separate planes supported'. ]. 'TIFFReader [info]: ignoring alpha plane' infoPrintCR. @@ -836,22 +1680,26 @@ samplesPerPixel := 1. ] ifFalse:[ (nPlanes == 4) ifTrue:[ - (planarConfiguration ~~ 1) ifTrue:[ + (planarConfiguration ~~ PLANARCONFIG_CONTIG) ifTrue:[ ^ self fileFormatError:'only non separate planes supported'. ]. bitsPerSample ~= #(8 8 8 8) ifTrue:[ - ^ self fileFormatError:'only 8/8/8/8 cmyk images supported'. + bitsPerSample ~= #(16 16 16 16) ifTrue:[ + ^ self fileFormatError:'only 8/8/8/8 and 16/16/16/16 images supported'. + ]. ]. - bitsPerPixel := 32. + bitsPerPixel := bitsPerSample sum. ] ifFalse:[ (nPlanes == 3) ifTrue:[ (planarConfiguration ~~ 1) ifTrue:[ ^ self fileFormatError:'only non separate planes supported'. ]. bitsPerSample ~= #(8 8 8) ifTrue:[ - ^ self fileFormatError:'only 8/8/8 rgb images supported (is: ' , bitsPerSample printString , ')'. + bitsPerSample ~= #(16 16 16) ifTrue:[ + ^ self fileFormatError:'only 8/8/8 and 16/16/16 images supported; is: ' , bitsPerSample printString. + ]. ]. - bitsPerPixel := 24 + bitsPerPixel := bitsPerSample sum. ] ifFalse:[ (nPlanes ~~ 1) ifTrue:[ ^ self fileFormatError:('unsupported format: nplanes=' , nPlanes printString). @@ -860,6 +1708,9 @@ ] ] ]. + stripRowCounts notNil ifTrue:[ + ^ self fileFormatError:'stripRowCounts not supported'. + ]. bitsPerRow := width * bitsPerPixel. bytesPerRow := bitsPerRow // 8. @@ -900,11 +1751,171 @@ where := where + nBytes. ]. - "Modified: / 12.8.1998 / 13:57:14 / cg" + "Modified: / 27-08-2017 / 15:39:09 / cg" ! ! !TIFFReader methodsFor:'private-reading'! +decodePhotoshopImageResourceBlock:bytes + "8BIM is the signature for Photoshop Image Resource Block (IRB). + See http://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577409_38034. + + This kind of information could be found in images such as TIFF, JPEG, Photoshop native image format etc. + It could also be found in non-image documents such as in PDF. + The structure of the IRB is as follows: + Each IRB block starts with 4 bytes signature which translates to string '8BIM.' + After that, is a 2 bytes unique identifier denoting the kind of resource for this IRB. + For example: + 0x040c for thumbnail; + 0x041a for slices; + 0x0408 for grid information; + 0x040f for ICC Profile etc. + + After the identifier is a variable length string for name. + The first byte of the string tells the length of the string (excluding the first length byte). + After the first byte comes the string itself. + There is a requirement that the length of the whole string (including the length byte) should be even. + Otherwise, pad one more byte after the string. + + The next 4 bytes specifies the size of the actual data for this resource block followed by the data with the specified length. + The total length of the data also should be an even number. So if the size of the data is odd, pad another one byte. + This finishes a whole 8BIM. + + There could be more than one IRBs but they all conform to the same structure as described above. + How to interpret the data depends on the unique identifier. + + Now let's see how the IRBs are include in images. + For a JPEG image, metadata could be present as one of the application (APPn) segment. + Since different application could use the same APPn segment to store it's own metadata, + there must be some kind of identifier to let the image reader know what kind of information is contained inside the APPn. + Photoshop uses APP13 as it's IRB container and the APP13 contains 'Photoshop 3.0' as it's identifier. + + For TIFF image which is tag based and arranged in a directory structure. + There is a private tag 16r8649 called 'PHOTOSHOP' to insert IRB information. + + 0x03E8 (Obsolete--Photoshop 2.0 only ) Contains five 2-byte values: number of channels, rows, columns, depth, and mode + 0x03E9 Macintosh print manager print info record + 0x03EA Macintosh page format information. No longer read by Photoshop. (Obsolete) + 0x03EB Obsolete--Photoshop 2.0 only ) Indexed color table + 0x03ED ResolutionInfo structure. See Appendix A in Photoshop API Guide.pdf. + 0x03EE Names of the alpha channels as a series of Pascal strings. + 0x03EF (Obsolete) See ID 1077DisplayInfo structure. See Appendix A in Photoshop API Guide.pdf. + 0x03F0 The caption as a Pascal string. + 0x03F1 Border information. Contains a fixed number (2 bytes real, 2 bytes fraction) for the border width, and 2 bytes for border units (1 = inches, 2 = cm, 3 = points, 4 = picas, 5 = columns). + 0x03F2 Background color. See See Color structure. + 0x03F3 Print flags. A series of one-byte boolean values (see Page Setup dialog): labels, crop marks, color bars, registration marks, negative, flip, interpolate, caption, print flags. + 0x03F4 Grayscale and multichannel halftoning information + 0x03F5 Color halftoning information + 0x03F6 Duotone halftoning information + 0x03F7 Grayscale and multichannel transfer function + 0x03F8 Color transfer functions + 0x03F9 Duotone transfer functions + 0x03FA Duotone image information + 0x03FB Two bytes for the effective black and white values for the dot range + 0x03FC (Obsolete) + 0x03FD EPS options + 0x03FE Quick Mask information. 2 bytes containing Quick Mask channel ID; 1- byte boolean indicating whether the mask was initially empty. + 0x03FF (Obsolete) + 0x0400 Layer state information. 2 bytes containing the index of target layer (0 = bottom layer). + 0x0401 Working path (not saved). See See Path resource format. + 0x0402 Layers group information. 2 bytes per layer containing a group ID for the dragging groups. Layers in a group have the same group ID. + 0x0403 (Obsolete) + 0x0404 IPTC-NAA record. Contains the File Info... information. See the documentation in the IPTC folder of the Documentation folder. + 0x0405 Image mode for raw format files + 0x0406 JPEG quality. Private. + 0x0408 (Photoshop 4.0) Grid and guides information. See See Grid and guides resource format. + 0x0409 (Photoshop 4.0) Thumbnail resource for Photoshop 4.0 only. See See Thumbnail resource format. + 0x040A (Photoshop 4.0) Copyright flag. Boolean indicating whether image is copyrighted. Can be set via Property suite or by user in File Info... + 0x040B (Photoshop 4.0) URL. Handle of a text string with uniform resource locator. Can be set via Property suite or by user in File Info... + 0x040C (Photoshop 5.0) Thumbnail resource (supersedes resource 1033). See See Thumbnail resource format. + 0x040D (Photoshop 5.0) Global Angle. 4 bytes that contain an integer between 0 and 359, which is the global lighting angle for effects layer. If not present, assumed to be 30. + 0x040E (Obsolete) See ID 1073 below. (Photoshop 5.0) Color samplers resource. See See Color samplers resource format. + 0x040F (Photoshop 5.0) ICC Profile. The raw bytes of an ICC (International Color Consortium) format profile. See ICC1v42_2006-05.pdf in the Documentation folder and icProfileHeader.h in Sample Code\Common\Includes . + 0x0410 (Photoshop 5.0) Watermark. One byte. + 0x0411 (Photoshop 5.0) ICC Untagged Profile. 1 byte that disables any assumed profile handling when opening the file. 1 = intentionally untagged. + 0x0412 (Photoshop 5.0) Effects visible. 1-byte global flag to show/hide all the effects layer. Only present when they are hidden. + 0x0413 (Photoshop 5.0) Spot Halftone. 4 bytes for version, 4 bytes for length, and the variable length data. + 0x0414 (Photoshop 5.0) Document-specific IDs seed number. 4 bytes: Base value, starting at which layer IDs will be generated (or a greater value if existing IDs already exceed it). Its purpose is to avoid the case where we add layers, flatten, save, open, and then add more layers that end up with the same IDs as the first set. + 0x0415 (Photoshop 5.0) Unicode Alpha Names. Unicode string + 0x0416 (Photoshop 6.0) Indexed Color Table Count. 2 bytes for the number of colors in table that are actually defined + 0x0417 (Photoshop 6.0) Transparency Index. 2 bytes for the index of transparent color, if any. + 0x0419 (Photoshop 6.0) Global Altitude. 4 byte entry for altitude + 0x041A (Photoshop 6.0) Slices. See See Slices resource format. + 0x041B (Photoshop 6.0) Workflow URL. Unicode string + 0x041C (Photoshop 6.0) Jump To XPEP. 2 bytes major version, 2 bytes minor version, 4 bytes count. Following is repeated for count: 4 bytes block size, 4 bytes key, if key = 'jtDd' , then next is a Boolean for the dirty flag; otherwise it's a 4 byte entry for the mod date. + 0x041D (Photoshop 6.0) Alpha Identifiers. 4 bytes of length, followed by 4 bytes each for every alpha identifier. + 0x041E (Photoshop 6.0) URL List. 4 byte count of URLs, followed by 4 byte long, 4 byte ID, and Unicode string for each count. + 0x0421 (Photoshop 6.0) Version Info. 4 bytes version, 1 byte hasRealMergedData , Unicode string: writer name, Unicode string: reader name, 4 bytes file version. + 0x0422 (Photoshop 7.0) EXIF data 1. See http://www.kodak.com/global/plugins/acrobat/en/service/digCam/exifStandard2.pdf + 0x0423 (Photoshop 7.0) EXIF data 3. See http://www.kodak.com/global/plugins/acrobat/en/service/digCam/exifStandard2.pdf + 0x0424 (Photoshop 7.0) XMP metadata. File info as XML description. See http://www.adobe.com/devnet/xmp/ + 0x0425 (Photoshop 7.0) Caption digest. 16 bytes: RSA Data Security, MD5 message-digest algorithm + 0x0426 (Photoshop 7.0) Print scale. 2 bytes style (0 = centered, 1 = size to fit, 2 = user defined). 4 bytes x location (floating point). 4 bytes y location (floating point). 4 bytes scale (floating point) + 0x0428 (Photoshop CS) Pixel Aspect Ratio. 4 bytes (version = 1 or 2), 8 bytes double, x / y of a pixel. Version 2, attempting to correct values for NTSC and PAL, previously off by a factor of approx. 5%. + 0x0429 (Photoshop CS) Layer Comps. 4 bytes (descriptor version = 16), Descriptor (see See Descriptor structure) + 0x042A (Photoshop CS) Alternate Duotone Colors. 2 bytes (version = 1), 2 bytes count, following is repeated for each count: [ Color: 2 bytes for space followed by 4 * 2 byte color component ], following this is another 2 byte count, usually 256, followed by Lab colors one byte each for L, a, b. This resource is not read or used by Photoshop. + 0x042B (Photoshop CS)Alternate Spot Colors. 2 bytes (version = 1), 2 bytes channel count, following is repeated for each count: 4 bytes channel ID, Color: 2 bytes for space followed by 4 * 2 byte color component. This resource is not read or used by Photoshop. + 0x042D (Photoshop CS2) Layer Selection ID(s). 2 bytes count, following is repeated for each count: 4 bytes layer ID + 0x042E (Photoshop CS2) HDR Toning information + 0x042F (Photoshop CS2) Print info + 0x0430 (Photoshop CS2) Layer Group(s) Enabled ID. 1 byte for each layer in the document, repeated by length of the resource. NOTE: Layer groups have start and end markers + 0x0431 (Photoshop CS3) Color samplers resource. Also see ID 1038 for old format. See See Color samplers resource format. + 0x0432 (Photoshop CS3) Measurement Scale. 4 bytes (descriptor version = 16), Descriptor (see See Descriptor structure) + 0x0433 (Photoshop CS3) Timeline Information. 4 bytes (descriptor version = 16), Descriptor (see See Descriptor structure) + 0x0434 (Photoshop CS3) Sheet Disclosure. 4 bytes (descriptor version = 16), Descriptor (see See Descriptor structure) + 0x0435 (Photoshop CS3) DisplayInfo structure to support floating point clors. Also see ID 1007. See Appendix A in Photoshop API Guide.pdf . + 0x0436 (Photoshop CS3) Onion Skins. 4 bytes (descriptor version = 16), Descriptor (see See Descriptor structure) + 0x0438 (Photoshop CS4) Count Information. 4 bytes (descriptor version = 16), Descriptor (see See Descriptor structure) Information about the count in the document. See the Count Tool. + 0x043A (Photoshop CS5) Print Information. 4 bytes (descriptor version = 16), Descriptor (see See Descriptor structure) Information about the current print settings in the document. The color management options. + 0x043B (Photoshop CS5) Print Style. 4 bytes (descriptor version = 16), Descriptor (see See Descriptor structure) Information about the current print style in the document. The printing marks, labels, ornaments, etc. + 0x043C (Photoshop CS5) Macintosh NSPrintInfo. Variable OS specific info for Macintosh. NSPrintInfo. It is recommened that you do not interpret or use this data. + 0x043D (Photoshop CS5) Windows DEVMODE. Variable OS specific info for Windows. DEVMODE. It is recommened that you do not interpret or use this data. + 0x043E (Photoshop CS6) Auto Save File Path. Unicode string. It is recommened that you do not interpret or use this data. + 0x043F (Photoshop CS6) Auto Save Format. Unicode string. It is recommened that you do not interpret or use this data. + 0x0440 (Photoshop CC) Path Selection State. 4 bytes (descriptor version = 16), Descriptor (see See Descriptor structure) Information about the current path selection state. + 0x07D0-0x0BB6 Path Information (saved paths). See See Path resource format. + 0x0BB7 Name of clipping path. See See Path resource format. + 0x0BB8 (Photoshop CC) Origin Path Info. 4 bytes (descriptor version = 16), Descriptor (see See Descriptor structure) Information about the origin path data. + 0x0FA0-0x1387 Plug-In resource(s). Resources added by a plug-in. See the plug-in API found in the SDK documentation + 0x1B58 Image Ready variables. XML representation of variables definition + 0x1B59 Image Ready data sets + 0x1B5A Image Ready default selected state + 0x1B5B Image Ready 7 rollover expanded state + 0x1B5C Image Ready rollover expanded state + 0x1B5D Image Ready save layer settings + 0x1B5E Image Ready version + 0x1F40 (Photoshop CS3) Lightroom workflow, if present the document is in the middle of a Lightroom workflow. + 0x2710 Print flags information. 2 bytes version ( = 1), 1 byte center crop marks, 1 byte ( = 0), 4 bytes bleed width value, 2 bytes bleed width scale. + " + + |s id name len resource record| + + record := OrderedCollection new. + + s := bytes readStream. + [s atEnd] whileFalse:[ + (s next:4) asString = '8BIM' ifTrue:[ + id := s nextUnsignedInt16MSB. + name := s upTo:0. + name size odd ifFalse:[ s next ]. "/ padding + len := s nextUnsignedInt32MSB. + resource := s next:len. + Verbose == true ifTrue:[ + Transcript showCR:(' 8BIM-%1: %2' bindWith:(id hexPrintString:4) with:resource). + ]. + record add:(Dictionary new + at:#id put:id; + at:#name put:name; + at:#resource put:resource; + yourself). + ]. + ]. + metaData at:#'PhotoshopIRB' put:record. + + "Created: / 27-08-2017 / 17:12:25 / cg" + "Modified: / 27-08-2017 / 18:14:56 / cg" +! + decodeTiffTag:tagType numberType:numberType length:length |offset value valueArray val scaleFactor rV gV bV @@ -1071,19 +2082,50 @@ "/ JBIG2 -> 34715 compression := value. - Verbose == true ifTrue:[ - Logger info:' compression: %1' with:value + Verbose == true ifTrue:[ + |s| + s := (Dictionary withKeyValuePairs: + #( (1 uncompressed) + (2 CCITTRLE) + (3 CCITTFAX3) + (4 CCITTFAX4) + (5 LZW) + (6 OJPEG) + (7 JPEG) + (8 ADOBE_DEFLATE) + (9 JBIG_T85) + (10 JBIG_T43) + (32766 NEXT) + (32771 CCITTRLEW) + (32773 PACKBITS) + (32809 THUNDERSCAN) + (32895 IT8CTPAD) + (32896 IT8LW) + (32897 IT8MP) + (32898 IT8BL) + (32908 PIXARFILM) + (32909 PIXARLOG) + (32946 DEFLATE) + (32947 DCS) + (34661 JBIG) + (34676 SGI32) + (34677 SGI24) + (34712 JPEG2000) + (34713 NIKON_NEF) + (34715 JBIG2) + )) at:value ifAbsent:'???'. + Logger info:' compression: %1 (=%2)' with:value with:s. ]. ^ self ]. (tagType == 262) ifTrue:[ "photometric" - |p| + |p| (value between:0 and:10) ifTrue:[ p := - #( + #( whiteIs0 "/ 0 - grayscale or monochrome; faxes blackIs0 "/ 1 - grayscale or monochrome; faxes rgb "/ 2 @@ -1110,9 +2152,9 @@ p := #LinearRaw "/ camera rw format ]. ]. - photometric := p. + photometric := p. Verbose == true ifTrue:[ - Logger info:' photometric: %1 (%2)' with:photometric with:value + Logger info:' photometric: %1 (=%2)' with:value with:photometric ]. ^ self ]. @@ -1132,7 +2174,6 @@ "CellWidth" "/ 'cellWidth ' print. value printNewline. metaData at:#CellWidth put:value. - ^ self ]. (tagType == 265) ifTrue:[ @@ -1144,27 +2185,33 @@ (tagType == 266) ifTrue:[ "fillOrder" (value == 1) ifTrue:[ - fillOrder := #msb + fillOrder := #msb ] ifFalse:[ - (value == 2) ifTrue:[ - fillOrder := #lsb - ] ifFalse:[ - fillOrder := nil - ] + (value == 2) ifTrue:[ + fillOrder := #lsb + ] ifFalse:[ + fillOrder := nil + ] ]. - "/ 'fillorder ' print. fillOrder printNewline. + Verbose == true ifTrue:[ + Logger info:' fillorder: %1' with:value + ]. ^ self ]. (tagType == 269) ifTrue:[ "documentName - info only" - "/ 'documentName ' print. value printNewline. metaData at:#DocumentName put:value. + Verbose == true ifTrue:[ + Logger info:' documentName: %1' with:value + ]. ^ self ]. (tagType == 270) ifTrue:[ "imageDescription - info only" - "/ 'imageDescription ' print. value printNewline. metaData at:#ImageDescription put:value. + Verbose == true ifTrue:[ + Logger info:' imageDescription: %1' with:value + ]. ^ self ]. (tagType == 271) ifTrue:[ @@ -1179,7 +2226,7 @@ "model - info only" metaData at:#Model put:value. Verbose == true ifTrue:[ - Logger info:' model: %1' with:value + Logger info:' model: %1' with:value ]. ^ self ]. @@ -1196,17 +2243,17 @@ orientation := #( nil "/ 1 normal (topLeft) - unsupported "/ 2 horizontal flip - unsupported "/ 3 horizontal & vertical flip + hFlip "/ 2 horizontal flip + hvFlip "/ 3 horizontal & vertical flip vFlip "/ 4 vertical flip - unsupported "/ 5 rot 90' counter clock-wise - unsupported "/ 6 rot 90' clock-wise - unsupported "/ 7 rot 90' & flip - unsupported "/ 8 rot 90' ccw & flip + rot90ccw "/ 5 rot 90' counter clock-wise + rot90 "/ 6 rot 90' clock-wise + rot90flip "/ 7 rot 90' & flip + rot90ccwFlip "/ 8 rot 90' ccw & flip ) at:value ifAbsent:#unsupported. metaData at:#Orientation put:value. Verbose == true ifTrue:[ - Logger info:' orientation: %1' with:value + Logger info:' orientation: %1 (=%2)' with:value with:(orientation ? #normal) ]. ^ self ]. @@ -1236,20 +2283,26 @@ ^ self ]. (tagType == 280) ifTrue:[ - "/ 'minSampleValue ' print. value printNewline. + "/ minSampleValue metaData at:#MinSampleValue put:value. + Verbose == true ifTrue:[ + Logger info:' minSampleValue: %1' with:value + ]. ^ self ]. (tagType == 281) ifTrue:[ - "/ 'maxSampleValue ' print. value printNewline. + "/ maxSampleValue metaData at:#MaxSampleValue put:value. + Verbose == true ifTrue:[ + Logger info:' maxSampleValue: %1' with:value + ]. ^ self ]. (tagType == 282) ifTrue:[ "/ xResolution metaData at:#ResolutionX put:value. Verbose == true ifTrue:[ - Logger info:' xResolution: %1' with:value + Logger info:' xResolution: %1 (%2)' with:value with:value asFloat ]. ^ self ]. @@ -1257,16 +2310,16 @@ "/ yResolution metaData at:#ResolutionY put:value. Verbose == true ifTrue:[ - Logger info:' yResolution: %1' with:value + Logger info:' yResolution: %1 (%2)' with:value with:value asFloat ]. ^ self ]. (tagType == 284) ifTrue:[ (value == 1) ifTrue:[ - planarConfiguration := 1 + planarConfiguration := PLANARCONFIG_CONTIG ] ifFalse:[ (value == 2) ifTrue:[ - planarConfiguration := 2 + planarConfiguration := PLANARCONFIG_SEPARATE ] ifFalse:[ planarConfiguration := nil ] @@ -1282,13 +2335,19 @@ ^ self ]. (tagType == 286) ifTrue:[ - "/ 'xPosition ' print. value printNewline. + "/ xPosition metaData at:#PositionX put:value. + Verbose == true ifTrue:[ + Logger info:' xPosition: %1' with:value + ]. ^ self ]. (tagType == 287) ifTrue:[ - "/ 'yPosition ' print. value printNewline. + "/ yPosition metaData at:#PositionY put:value. + Verbose == true ifTrue:[ + Logger info:' yPosition: %1' with:value + ]. ^ self ]. (tagType == 288) ifTrue:[ @@ -1316,15 +2375,19 @@ "/ FILLBITS -> 4 group3options := value. - "/ 'group3options ' print. group3options printNewline. + Verbose == true ifTrue:[ + Logger info:' group3options: %1' with:value + ]. ^ self ]. (tagType == 293) ifTrue:[ "/ group4options (now called T6Options) "/ UNCOMPRESSED -> 2 - "group4options := value." - "/ 'group4options ' print. value printNewline. + "/ group4options := value. + Verbose == true ifTrue:[ + Logger info:' group4options: %1' with:value + ]. ^ self ]. (tagType == 296) ifTrue:[ @@ -1352,6 +2415,9 @@ (tagType == 297) ifTrue:[ "/ 'pageNumber ' print. value printNewline. metaData at:#PageNumber put:value. + Verbose == true ifTrue:[ + Logger info:' PageNumber: %1' with:value + ]. ^ self ]. ]. @@ -1369,38 +2435,38 @@ ]. (tagType == 305) ifTrue:[ "software - info only" - metaData at:#Software put:value asString. + metaData at:#Software put:value. Verbose == true ifTrue:[ - Logger info:' software: %1' with:value asString + Logger info:' software: %1' with:value ]. ^ self ]. (tagType == 306) ifTrue:[ "dateTime - info only" - metaData at:#DateTime put:value asString. + metaData at:#DateTime put:value. Verbose == true ifTrue:[ - Logger info:' dateTime: %1' with:value asString + Logger info:' dateTime: %1' with:value ]. ^ self ]. (tagType == 315) ifTrue:[ "artist - info only" - metaData at:#Artist put:value asString. + metaData at:#Artist put:value. Verbose == true ifTrue:[ - Logger info:' artist: %1' with:value asString + Logger info:' artist: %1' with:value ]. ^ self ]. (tagType == 316) ifTrue:[ "host computer - info only" - metaData at:#HostComputer put:value asString. + metaData at:#HostComputer put:value. Verbose == true ifTrue:[ - Logger info:' host: %1' with:value asString + Logger info:' host: %1' with:value ]. ^ self ]. (tagType == 317) ifTrue:[ - "/ 'predictor ' print. predictor printNewline. + "/ predictor "/ 1 -> no predictor "/ 2 -> horiz. difference (see tiff spec 6.0) "/ 3 -> flt pnt (see adobe tech notes) @@ -1409,15 +2475,18 @@ "/ 34894 -> flt pnt x2 "/ 34895 -> flt pnt x4 predictor := value. + Verbose == true ifTrue:[ + Logger info:' predictor: %1' with:value + ]. ^ self ]. (tagType == 318) ifTrue:[ - "/ 'whitePoint ' print. value printNewline. + "/ whitePoint metaData at:#WhitePoint put:value. ^ self ]. (tagType == 319) ifTrue:[ - "/ 'primaryChromatics ' print. value printNewline. + "/ primaryChromatics metaData at:#PrimaryChromatics put:value. ^ self ]. @@ -1447,66 +2516,95 @@ i3 := i3 + 1. ]. colorMap := MappedPalette redVector:rV greenVector:gV blueVector:bV. + Verbose == true ifTrue:[ + Logger info:' colormap: ...' + ]. ^ self ]. (tagType == 321) ifTrue:[ - "/ 'halftonehints' print. value printNewline. + "/ halftonehints metaData at:#HalftoneHints put:value. ^ self ]. (tagType == 322) ifTrue:[ - "/ 'tilewidth' print. value printNewline. - metaData at:#TileWidth put:value. + "/ tilewidth + tileWidth := value. + Verbose == true ifTrue:[ + Logger info:' tileWidth: %1' with:value + ]. + (tileWidth \\ 16) == 0 ifFalse:[ + Logger warning:'TIFFReader: tile width is not a multiple of 16'. + ]. ^ self ]. (tagType == 323) ifTrue:[ - "/ 'tilelength' print. value printNewline. - metaData at:#TileLength put:value. + "/ tilelength (height) + tileLength := value. + Verbose == true ifTrue:[ + Logger info:' tileLength: %1' with:value + ]. + (tileLength \\ 16) == 0 ifFalse:[ + Logger warning:'TIFFReader: tile height is not a multiple of 16'. + ]. ^ self ]. (tagType == 324) ifTrue:[ - "/ 'tileoffsets' print. value printNewline. - metaData at:#TileOffsets put:valueArray. + "/ tileoffsets + tileOffsets := valueArray. + Verbose == true ifTrue:[ + Logger info:' tileOffsets: %1' with:valueArray + ]. ^ self ]. (tagType == 325) ifTrue:[ - "/ 'tilebytecounts' print. value printNewline. - metaData at:#TileByteCounts put:valueArray. + "/ tilebytecounts + tileByteCounts := valueArray. + Verbose == true ifTrue:[ + Logger info:' tileByteCounts: %1' with:valueArray + ]. ^ self ]. (tagType == 326) ifTrue:[ - "/ 'badFaxLines' print. value printNewline. + "/ badFaxLines + Verbose == true ifTrue:[ + Logger info:' badFaxLines: %1' with:valueArray + ]. ^ self ]. (tagType == 327) ifTrue:[ "CleanFaxData" - - "/ 'cleanfaxdata' print. value printNewline. - "/ (value == 0) ifTrue:[ - "/ 'no lines with incorrect pixel counts' printNewline - "/ ] ifFalse:[ - "/ (value == 1) ifTrue:[ - "/ 'incorrect lines were regenerated' printNewline - "/ ] ifFalse:[ - "/ (value == 2) ifTrue:[ - "/ 'incorrect lines were not regenerated' printNewline - "/ ] ifFalse:[ - "/ 'cleanfaxdata invalid' printNewline - "/ ] - "/ ] - "/ ]. - + Verbose == true ifTrue:[ + "/ 'cleanfaxdata' print. value printNewline. + "/ (value == 0) ifTrue:[ + "/ 'no lines with incorrect pixel counts' printNewline + "/ ] ifFalse:[ + "/ (value == 1) ifTrue:[ + "/ 'incorrect lines were regenerated' printNewline + "/ ] ifFalse:[ + "/ (value == 2) ifTrue:[ + "/ 'incorrect lines were not regenerated' printNewline + "/ ] ifFalse:[ + "/ 'cleanfaxdata invalid' printNewline + "/ ] + "/ ] + "/ ]. + Logger info:' cleanfaxdata: %1' with:value + ]. ^ self ]. (tagType == 328) ifTrue:[ - "/ 'consecutiveBadFaxLines' print. value printNewline. + "/ consecutiveBadFaxLines + Verbose == true ifTrue:[ + Logger info:' consecutiveBadFaxLines: %1' with:valueArray + ]. ^ self ]. (tagType == 330) ifTrue:[ "/ subifd Verbose == true ifTrue:[ - Logger info:' subifd: %1' with:value + Logger info:' subifd: %1' with:valueArray ]. + subIfds := valueArray. ^ self ]. (tagType == 332) ifTrue:[ @@ -1532,18 +2630,35 @@ ]. (tagType == 338) ifTrue:[ "/ 'extrasamples' print. value printNewline. + Verbose == true ifTrue:[ + Logger info:' extrasamples: %1' with:value + ]. ^ self ]. (tagType == 339) ifTrue:[ "/ 'sample format' print. value printNewline. + Verbose == true ifTrue:[ + Logger info:' sample format: %1 (=%2)' + with:value + with:(#( uint int float undef ) at:value ifAbsent:'???') + ]. + sampleFormat := value. ^ self ]. (tagType == 340) ifTrue:[ "/ 'min sample value' print. value printNewline. + Verbose == true ifTrue:[ + Logger info:' min sample value: %1' with:value + ]. + minSampleValue := value. ^ self ]. (tagType == 341) ifTrue:[ "/ 'max sample value' print. value printNewline. + Verbose == true ifTrue:[ + Logger info:' max sample value: %1' with:value + ]. + maxSampleValue := value. ^ self ]. (tagType == 342) ifTrue:[ @@ -1562,10 +2677,18 @@ "/ 'yclip path units' print. value printNewline. ^ self ]. + (tagType == 346) ifTrue:[ + "/ 'indexed' print. value printNewline. + ^ self + ]. (tagType == 347) ifTrue:[ "/ 'jpegtables' print. value printNewline. ^ self ]. + (tagType == 351) ifTrue:[ + "/ opiproxy + ^ self + ]. ]. (tagType between:400 and:499) ifTrue:[ @@ -1672,14 +2795,20 @@ ^ self ]. (tagType == 559) ifTrue:[ - "/ 'stripRowCounts' print. value printNewline. + "/ stripRowCounts + "/ Defined in the Mixed Raster Content part of RFC 2301, + "/ used to replace RowsPerStrip for IFDs with variable-sized strips. + Verbose == true ifTrue:[ + Logger info:' stripRowCounts: %1' with:valueArray + ]. + stripRowCounts := valueArray. ^ self ]. ]. (tagType between:700 and:799) ifTrue:[ (tagType == 700) ifTrue:[ - "XMLPACKET" + "XMP metadata (xml)" "/ In TIFF files, the XML Packet containing XMP metadata is pointed to "/ by an entry in the Image File Directory (IFD). That entry has a Tag @@ -1693,6 +2822,17 @@ ]. ]. + (tagType between:18000 and:18999) ifTrue:[ + (tagType == 18246) ifTrue:[ + "/ Image Rating by windows + ^ self + ]. + (tagType == 18249) ifTrue:[ + "/ Image Rating Percent by windows + ^ self + ]. + ]. + (tagType between:32000 and:32999) ifTrue:[ (tagType == 32781) ifTrue:[ "/'imageid' print. value printNewline. @@ -1727,16 +2867,26 @@ "/ 'matteing' print. value printNewline. ^ self ]. + (tagType == 32996) ifTrue:[ - "/ 'datatype' print. value printNewline. + "/ datatype + Verbose == true ifTrue:[ + Logger info:' datatype: %1' with:value + ]. ^ self ]. (tagType == 32997) ifTrue:[ - "/ 'imagedepth' print. value printNewline. + "/ imagedepth + Verbose == true ifTrue:[ + Logger info:' imagedepth: %1' with:value + ]. ^ self ]. (tagType == 32998) ifTrue:[ - "/ 'tiledepth' print. value printNewline. + "/ tiledepth + Verbose == true ifTrue:[ + Logger info:' tiledepth: %1' with:value + ]. ^ self ]. ]. @@ -1758,7 +2908,24 @@ ^ self ]. - "/ unknown + (tagType == 33421) ifTrue:[ + "/ CFARepeatPatternDim - For camera raw files from sensors with CFA overlay + Verbose == true ifTrue:[ + Logger info:' CFARepeatPatternDim: %1' with:value + ]. + ^ self + ]. + (tagType == 33422) ifTrue:[ + "/ CFAPattern - For camera raw files from sensors with CFA overlay + Verbose == true ifTrue:[ + Logger info:' CFAPattern: %1' with:value + ]. + ^ self + ]. + (tagType == 33423) ifTrue:[ + "/ BatteryLevel - Encodes camera battery level at time of image capture + ^ self + ]. (tagType == 33432) ifTrue:[ "/ 'copyright' print. value printNewline. ^ self @@ -1773,12 +2940,89 @@ "/ 'RICHTIFFIPTC' print. value printNewline. ^ self ]. + + + (tagType == 33920) ifTrue:[ + "/ 'geotiff IntergraphMatrixTag' print. value printNewline. + ^ self + ]. + (tagType == 33922) ifTrue:[ + "/ 'geotiff ModelTiepointTag' print. value printNewline. + ^ self + ]. + ]. - + (tagType between:34000 and:34999) ifTrue:[ - "/ Private Texas instruments - (tagType == 34232) ifTrue:[ - "/ 'sequence frame count' print. value printNewline. + (tagType == 34016) ifTrue:[ + "/ Site + Verbose == true ifTrue:[ + Logger info:' site: %1' with:value + ]. + ^ self + ]. + (tagType == 34017) ifTrue:[ + "/ colorSequence + ^ self + ]. + (tagType == 34018) ifTrue:[ + "/ it8header + ^ self + ]. + (tagType == 34019) ifTrue:[ + "/ rasterPadding + ^ self + ]. + (tagType == 34020) ifTrue:[ + "/ bitsPerRunLength + ^ self + ]. + (tagType == 34021) ifTrue:[ + "/ bitsPerExtendedRunLength + ^ self + ]. + (tagType == 34022) ifTrue:[ + "/ colorTable + ^ self + ]. + (tagType == 34023) ifTrue:[ + "/ imageColorIndicator + ^ self + ]. + (tagType == 34024) ifTrue:[ + "/ backgroundColorIndicator + ^ self + ]. + (tagType == 34025) ifTrue:[ + "/ imageColorValue + ^ self + ]. + (tagType == 34026) ifTrue:[ + "/ backgroundColorValue + ^ self + ]. + (tagType == 34027) ifTrue:[ + "/ pixelIntensityRange + ^ self + ]. + (tagType == 34028) ifTrue:[ + "/ transparencyIndicator + ^ self + ]. + (tagType == 34029) ifTrue:[ + "/ colorCharacterization + ^ self + ]. + (tagType == 34030) ifTrue:[ + "/ hcUsage + ^ self + ]. + (tagType == 34031) ifTrue:[ + "/ trapIndicator + ^ self + ]. + (tagType == 34032) ifTrue:[ + "/ cmykEquivalent ^ self ]. @@ -1788,11 +3032,28 @@ ^ self ]. + (tagType == 34264) ifTrue:[ + "/ 'geotiff ModelTransformationTag' print. value printNewline. + ^ self + ]. "/ private Photoshop (tagType == 34377) ifTrue:[ - "/ 'photoshop RICHTIFFIPTC' print. value printNewline. + "/ RICHTIFFIPTC + "/ IPTC (International Press Telecommunications Council) metadata. + "/ (see http://www.iptc.org/std/photometadata/specification/IPTC-PhotoMetadata) + Verbose == true ifTrue:[ + Logger info:' RICHTIFFIPTC: %1' with:value + ]. + decodeMetaTags == true ifTrue:[ + self decodePhotoshopImageResourceBlock:value. + ] ifFalse:[ + Verbose == true ifTrue:[ + Logger info:' skipped decoding of IPTC-PhotoMetadata' + ]. + ]. ^ self ]. + (tagType == 34665) ifTrue:[ "/ EXIFIFD Verbose == true ifTrue:[ @@ -1809,11 +3070,26 @@ "/ 'ImageLayer' print. value printNewline. ^ self ]. + + (tagType == 34735) ifTrue:[ + "/ 'geotiff GeoKeyDirectoryTag' print. value printNewline. + ^ self + ]. + (tagType == 34736) ifTrue:[ + "/ 'geotiff GeoDoubleParamsTag' print. value printNewline. + ^ self + ]. + (tagType == 34737) ifTrue:[ + "/ 'geotiff GeoAsciiParamsTag' print. value printNewline. + ^ self + ]. + + (tagType == 34859) ifTrue:[ "/ '???' print. value printNewline. - Verbose == true ifTrue:[ - Logger info:' ?: %1' with:value - ]. + "/ Verbose == true ifTrue:[ + "/ Logger info:' ?: %1' with:value + "/ ]. ^ self ]. @@ -1861,6 +3137,9 @@ (tagType between:42000 and:42999) ifTrue:[ (tagType == 42112) ifTrue:[ "/ 'GDAL_METADATA' print. value printNewline. + Verbose == true ifTrue:[ + Logger info:' GDAL_METADATA: %1' with:value + ]. ^ self ]. ]. @@ -1872,6 +3151,7 @@ Verbose == true ifTrue:[ Logger info:' DNGVersion: %1' with:value ]. + isDNGImage := true. ^ self ]. (tagType == 50707) ifTrue:[ @@ -1881,14 +3161,14 @@ (tagType == 50708) ifTrue:[ "/ UniqueCameraModel Verbose == true ifTrue:[ - Logger info:' UniqueCameraModel: %1' with:value asString + Logger info:' UniqueCameraModel: %1' with:value ]. ^ self ]. (tagType == 50709) ifTrue:[ "/ LocalizedCameraModel Verbose == true ifTrue:[ - Logger info:' LocalizedCameraModel: %1' with:value asString + Logger info:' LocalizedCameraModel: %1' with:value ]. ^ self ]. @@ -1995,7 +3275,7 @@ (tagType == 50735) ifTrue:[ "/ 'CameraSerialNumber' print. value printNewline. Verbose == true ifTrue:[ - Logger info:' CameraSerialNumber: %1' with:value asString + Logger info:' CameraSerialNumber: %1' with:value ]. ^ self ]. @@ -2023,6 +3303,7 @@ "/ 'MakerNoteSafety' print. value printNewline. ^ self ]. + (tagType == 50778) ifTrue:[ "/ 'CalibrationIlluminant1' print. value printNewline. ^ self @@ -2039,6 +3320,7 @@ "/ 'RawDataUniqueID' print. value printNewline. ^ self ]. + (tagType == 50827) ifTrue:[ "/ 'OriginalRawFileName' print. value printNewline. ^ self @@ -2053,7 +3335,7 @@ 'TIFFReader [warning]: unknown tag type ' errorPrint. tagType errorPrintCR "Modified (format): / 23-05-2017 / 16:12:58 / mawalch" - "Modified (format): / 25-08-2017 / 17:02:57 / cg" + "Modified: / 27-08-2017 / 19:57:55 / cg" ! positionToStrip:stripNr @@ -2071,9 +3353,14 @@ |oldPos offset bytes nInline| - n == 0 ifTrue:[^ '']. - nInline := isBigTiff ifTrue:[8] ifFalse:[4]. + + n == 0 ifTrue:[ + "/ even in this case, one WORD is to be skipped. + inStream skip:nInline. + ^ '' + ]. + bytes := (isSigned ifTrue:[Array] ifFalse:[ByteArray]) new:n. (n <= nInline) ifTrue:[ isSigned ifTrue:[ @@ -2097,7 +3384,7 @@ ]. ^ bytes - "Modified: / 24-08-2017 / 23:25:30 / cg" + "Modified: / 27-08-2017 / 19:56:23 / cg" ! readChars:n @@ -2105,18 +3392,24 @@ |oldPos offset string nInline| - n == 0 ifTrue:[^ '']. - nInline := isBigTiff ifTrue:[8] ifFalse:[4]. - + + n == 0 ifTrue:[ + "/ even in this case, one WORD is to be skipped. + inStream skip:nInline. + ^ '' + ]. + string := String new:(n - 1). (n <= nInline) ifTrue:[ inStream nextBytes:(n - 1) into:string. + inStream next. "/ skip the 0-byte. + (n < nInline) ifTrue:[ inStream skip:(nInline - n). ] ] ifFalse:[ - offset := inStream nextInt32MSB:(byteOrder ~~ #lsb). + offset := inStream nextInt32MSB:(byteOrder == #msb). oldPos := inStream position. inStream position:offset. inStream nextBytes:(n - 1) into:string. @@ -2124,7 +3417,7 @@ ]. ^ string - "Modified: / 24-08-2017 / 23:25:03 / cg" + "Modified: / 27-08-2017 / 19:55:15 / cg" ! readDoubles:nFloats @@ -2342,6 +3635,42 @@ ^ values "Modified: / 24-08-2017 / 23:33:09 / cg" +! + +readSingleTagFrom:aStream + |msb tagType numberType length| + + msb := (byteOrder == #msb). + + tagType := aStream nextUnsignedInt16MSB:msb. + numberType := aStream nextUnsignedInt16MSB:msb. + + isBigTiff ifFalse:[ + length := aStream nextInt32MSB:msb. + ] ifTrue:[ + length := aStream nextInt64MSB:msb. + ]. + self decodeTiffTag:tagType numberType:numberType length:length. + + "Created: / 26-08-2017 / 11:04:50 / cg" + "Modified (format): / 26-08-2017 / 22:37:58 / cg" +! + +readTagsFrom:aStream + |numberOfTags msb| + + msb := (byteOrder == #msb). + + isBigTiff ifFalse:[ + numberOfTags := aStream nextUnsignedInt16MSB:msb. + ] ifTrue:[ + numberOfTags := aStream nextUnsignedInt64MSB:msb. + ]. + 1 to:numberOfTags do:[:index | + self readSingleTagFrom:aStream. + ]. + + "Created: / 26-08-2017 / 11:03:45 / cg" ! ! !TIFFReader methodsFor:'private-writing'! @@ -2729,14 +4058,8 @@ Leave image description in instance variables. (i.e. to get the image, ask with image)." - |char1 char2 version - numberOfTags "{ Class: SmallInteger }" - tagType "{ Class: SmallInteger }" - numberType "{ Class: SmallInteger }" - length "{ Class: SmallInteger }" - result offset msb - bytesPerRow offset1 offset2 tmp - pos1| + |char1 char2 version offset msb + bytesPerRow img moreIfds| inStream := aStream. aStream binary. @@ -2760,12 +4083,10 @@ ^ self fileFormatError:'not a tiff file'. ] ]. - isBigTiff := false. version := aStream nextUnsignedInt16MSB:msb. (version == 42) ifTrue:[ - offset := aStream nextUnsignedInt32MSB:msb. - aStream position:offset. + isBigTiff := false. ] ifFalse:[ (version == 43) ifTrue:[ |byteSizeOfOffsets always0| @@ -2780,124 +4101,148 @@ always0 == 0 ifFalse:[ ^ self fileFormatError:'version of bigtiff-file not supported'. ]. - offset := aStream nextUnsignedInt64MSB:msb. - aStream position:offset. ] ifFalse:[ ^ self fileFormatError:'version of tiff-file not supported'. ]. ]. - "setup default values" - metaData := TIFFMetaData new. + imageSequence := ImageSequence new. + isDNGImage := false. + + isBigTiff ifFalse:[ + offset := aStream nextUnsignedInt32MSB:msb. + ] ifTrue:[ + offset := aStream nextUnsignedInt64MSB:msb. + ]. + + [ offset ~~ 0 ] whileTrue:[ + Verbose == true ifTrue:[ + Logger info:'------------------ reading image #%1 ------------------' with:imageSequence size+1. + ]. + + aStream position:offset. + + "setup default values" + metaData := TIFFMetaData new. + + compression := 1. "none" + fillOrder := #msb. + planarConfiguration := PLANARCONFIG_CONTIG. + photometric := nil. + bitsPerSample := 1. + samplesPerPixel := 1. + width := height := nil. + stripOffsets := stripByteCounts := rowsPerStrip := nil. + "resolutionUnit := 2." + predictor := 1. + group3options := nil. + orientation := nil. + subFileType := subIfds := nil. + sampleFormat := minSampleValue := maxSampleValue := nil. + tileWidth := tileLength := tileOffsets := tileByteCounts := nil. + + self readTagsFrom:aStream. + "/ read the next offset now, + "/ because the stream's position will be changed when the image-data is read + isBigTiff ifFalse:[ + offset := aStream nextUnsignedInt32MSB:msb. + ] ifTrue:[ + offset := aStream nextUnsignedInt64MSB:msb. + ]. + + "check for required tags" + width isNil ifTrue:[ ^ self fileFormatError:'missing width tag' ]. + height isNil ifTrue:[ ^ self fileFormatError:'missing length tag' ]. + photometric isNil ifTrue:[ ^ self fileFormatError:'missing photometric tag' ]. + + "given all the information, read the bits" + tileWidth notNil ifTrue:[ + tileOffsets := tileOffsets ? stripOffsets. + tileByteCounts := tileByteCounts ? stripByteCounts. + (tileOffsets notNil + and:[tileLength notNil + and:[tileByteCounts notNil ]] + ) ifFalse:[ + ^ self fileFormatError:'missing stripOffsets (or tileOffsets)'. + ]. + self reportDimension. + self readTiledTiffImageData. + ] ifFalse:[ + stripByteCounts isNil ifTrue:[ + stripOffsets size == 1 ifTrue:[ + stripByteCounts := Array with:(self bitsPerPixel // 8) * width * height + ] ifFalse:[ + ^ self fileFormatError:'missing stripByteCounts'. + ]. + ]. + rowsPerStrip isNil ifTrue:[ + rowsPerStrip := height + ]. + self reportDimension. + self readTiffImageData. + ]. - compression := 1. "none" - fillOrder := #msb. - planarConfiguration := 1. - photometric := nil. - bitsPerSample := 1. - samplesPerPixel := 1. - width := nil. - height := nil. - stripOffsets := nil. - rowsPerStrip := nil. - "resolutionUnit := 2." - predictor := 1. - orientation := nil. - - (version == 42) ifTrue:[ - numberOfTags := aStream nextUnsignedInt16MSB:msb. - - 1 to:numberOfTags do:[:index | - tagType := aStream nextUnsignedInt16MSB:msb. - numberType := aStream nextUnsignedInt16MSB:msb. - length := aStream nextInt32MSB:msb. - self decodeTiffTag:tagType numberType:numberType length:length - ]. - offset := aStream nextInt32MSB:msb. - ] ifFalse:[ - numberOfTags := aStream nextUnsignedInt64MSB:msb. - - 1 to:numberOfTags do:[:index | - tagType := aStream nextUnsignedInt16MSB:msb. - numberType := aStream nextUnsignedInt16MSB:msb. - length := aStream nextInt64MSB:msb. - pos1 := aStream position. - self decodeTiffTag:tagType numberType:numberType length:length. - ]. - offset := aStream nextInt32MSB:msb. - ]. - (offset ~~ 0) ifTrue:[ - 'TIFFReader [info]: more tags ignored' infoPrintCR - ]. - - "check for required tags" - width isNil ifTrue:[ - ^ self fileFormatError:'missing width tag'. - ]. - - height isNil ifTrue:[ - ^ self fileFormatError:'missing length tag'. - ]. - - photometric isNil ifTrue:[ - ^ self fileFormatError:'missing photometric tag'. + orientation == #unsupported ifTrue:[ + 'TIFFReader [warning]: unsupported orientation' errorPrintCR + ] ifFalse:[ + orientation == #vFlip ifTrue:[ + |tmp offset1 offset2| + + "/ reverse rows to top-to bottom + "/ (oops - depends on side-effecting the data array) + + bytesPerRow := self bytesPerRow. + tmp := ByteArray new:bytesPerRow. + offset1 := 1. + offset2 := (height-1)*bytesPerRow + 1. + 0 to:((height-1)//2) do:[:row | + tmp replaceFrom:1 to:bytesPerRow with:data startingAt:offset1. + data replaceFrom:offset1 to:(offset1+bytesPerRow-1) with:data startingAt:offset2. + data replaceFrom:offset2 to:(offset2+bytesPerRow-1) with:tmp startingAt:1. + offset1 := offset1 + bytesPerRow. + offset2 := offset2 - bytesPerRow. + ]. + ]. + ]. + + "/ fixup photoetric + photometric == #rgb ifTrue:[ + samplesPerPixel == 4 ifTrue:[ + photometric := #rgba + ]. + ]. + + img := self makeImage. + img imageSequence:imageSequence. + imageSequence add:(ImageFrame new image:img). + + offset == 0 ifTrue:[ + moreIfds isNil ifTrue:[ + subIfds notNil ifTrue:[ + (isDNGImage not or:[loadFullResolutionImage == true]) ifTrue:[ + moreIfds := OrderedCollection withAll:subIfds. + subIfds := nil. + ] ifFalse:[ + Verbose == true ifTrue:[ + Logger info:'skip high resolution images (use loadFullResolutionImage is false)' + ]. + ]. + ]. + ]. + moreIfds notEmptyOrNil ifTrue:[ + offset := moreIfds removeFirst + ]. + ]. ]. - "given all the information, read the bits" - stripOffsets isNil ifTrue:[ - (metaData notNil - and:[(metaData includesKey:#TileWidth) - and:[(metaData includesKey:#TileLength) - and:[(metaData includesKey:#TileOffsets) - and:[(metaData includesKey:#TileByteCounts) ]]]] - ) ifFalse:[ - ^ self fileFormatError:'missing stripOffsets or tileOffsets tag'. - ]. - self reportDimension. - result := self readTiledTiffImageData. - ] ifFalse:[ - stripByteCounts isNil ifTrue:[ - stripOffsets size == 1 ifTrue:[ - stripByteCounts := Array with:(self bitsPerPixel // 8) * width * height - ] ifFalse:[ - ^ self fileFormatError:'missing stripByteCounts'. - ]. - ]. - self reportDimension. - rowsPerStrip isNil ifTrue:[ - rowsPerStrip := height - ]. - - result := self readTiffImageData. - ]. - - result isNil ifTrue:[ - "/ unsupported format. - ^ nil - ]. - - orientation == #vFlip ifTrue:[ - "/ reverse rows to top-to bottom - - bytesPerRow := self bytesPerRow. - tmp := ByteArray new:bytesPerRow. - offset1 := 1. - offset2 := (height-1)*bytesPerRow + 1. - 0 to:((height-1)//2) do:[:row | - tmp replaceFrom:1 to:bytesPerRow with:data startingAt:offset1. - data replaceFrom:offset1 to:(offset1+bytesPerRow-1) with:data startingAt:offset2. - data replaceFrom:offset2 to:(offset2+bytesPerRow-1) with:tmp startingAt:1. - offset1 := offset1 + bytesPerRow. - offset2 := offset2 - bytesPerRow. - ]. - ]. - orientation == #unsupported ifTrue:[ - 'TIFFReader [warning]: unsupported orientation' errorPrintCR - ]. - - ^ result - - "Modified: / 25-08-2017 / 10:08:30 / cg" + imageSequence size > 1 ifTrue:[ + Verbose == true ifTrue:[ + Logger info:'read %1 images' with:imageSequence size + ]. + ]. + ^ self + + "Modified: / 27-08-2017 / 18:45:40 / cg" ! ! !TIFFReader methodsFor:'writing'! @@ -2930,7 +4275,7 @@ bitsPerSample := image bitsPerSample. colorMap := image colorMap. - planarConfiguration := 1. + planarConfiguration := PLANARCONFIG_CONTIG. compression := 1. "none" data := image bits. @@ -2990,6 +4335,8 @@ self writeTag:320 "colorMap" ]. self writeLong:0. "end of tags mark" + + "Modified: / 27-08-2017 / 13:36:35 / cg" ! ! !TIFFReader class methodsFor:'documentation'!