#BUGFIX by cg
class: PCXReader
added: #readCompressedDepth24Data
changed:
#readCompressedData
#readCompressedData_2
"
COPYRIGHT (c) 1991 by Claus Gittinger
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
"
"{ Package: 'stx:libview2' }"
"{ NameSpace: Smalltalk }"
ImageReader subclass:#TIFFReader
instanceVariableNames:'planarConfiguration subFileType stripOffsets rowsPerStrip
fillOrder compression group3options predictor stripByteCounts
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 FILLORDER_MSB2LSB
FILLORDER_LSB2MSB'
poolDictionaries:''
category:'Graphics-Images-Readers'
!
Dictionary subclass:#TIFFMetaData
instanceVariableNames:''
classVariableNames:''
poolDictionaries:''
privateIn:TIFFReader
!
!TIFFReader class methodsFor:'documentation'!
copyright
"
COPYRIGHT (c) 1991 by Claus Gittinger
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
"
!
documentation
"
This class knows how to read TIFF files and how to write uncompressed TIFF files.
Implemented & Missing Features:
- Only single image files are supported.
- Not all formats are implemented, and of those that are, not all are tested.
It should read with most rgb, palette, mono and greyscale images,
although the alpha channel is currently not supported and ignored.
It supports reading of uncompressed, LZW, packbits and CCITT-G3 compressed images
JPEG and many other formats are currently not implemented.
- Only writing of uncompressed images is currently implemented.
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?)
TODO (?):
since I don't want to spend all of my life adding more formats here and
reinventing the wheel, this code should be changed to use the tiff library.
That would give us most formats and also writing capabilities for free.
Late note:
I hate C and interfacing to C libraries: it almost always leads to trouble
w.r.t. memory leaks, non-reentrancy, non-interruptability etc.
(we recently fixed a malloc-non-reentrant bug for some architecture...)
So its probably better to do it all in a real programming language ;-)
[author:]
Claus Gittinger
[See also:]
Image Form Icon
BlitImageReader FaceReader GIFReader JPEGReader PBMReader PCXReader
ST80FormReader SunRasterReader TargaReader WindowsIconReader
XBMReader XPMReader XWDReader
"
! !
!TIFFReader class methodsFor:'initialization'!
initialize
"install myself in the Image classes fileFormat table
for the `.tiff' and `.tif' extensions."
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.
FILLORDER_MSB2LSB := 1.
FILLORDER_LSB2MSB := 2.
"/ 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 <dkelly@apago.com) */
"/ #define COMPRESSION_IT8CTPAD 32895 /* IT8 CT w/padding */
"/ #define COMPRESSION_IT8LW 32896 /* IT8 Linework RLE */
"/ #define COMPRESSION_IT8MP 32897 /* IT8 Monochrome picture */
"/ #define COMPRESSION_IT8BL 32898 /* IT8 Binary line art */
"/ /* compression codes 32908-32911 are reserved for Pixar */
"/ #define COMPRESSION_PIXARFILM 32908 /* Pixar companded 10bit LZW */
"/ #define COMPRESSION_PIXARLOG 32909 /* Pixar companded 11bit ZIP */
"/ #define COMPRESSION_DEFLATE 32946 /* Deflate compression */
"/ #define COMPRESSION_ADOBE_DEFLATE 8 /* Deflate compression,
"/ as recognized by Adobe */
"/ /* compression code 32947 is reserved for Oceana Matrix <dev@oceana.com> */
"/ #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 <dkelly@apago.com) */
"/ #define TIFFTAG_IT8SITE 34016 /* site name */
"/ #define TIFFTAG_IT8COLORSEQUENCE 34017 /* color seq. [RGB,CMYK,etc] */
"/ #define TIFFTAG_IT8HEADER 34018 /* DDES Header */
"/ #define TIFFTAG_IT8RASTERPADDING 34019 /* raster scanline padding */
"/ #define TIFFTAG_IT8BITSPERRUNLENGTH 34020 /* # of bits in short run */
"/ #define TIFFTAG_IT8BITSPEREXTENDEDRUNLENGTH 34021/* # of bits in long run */
"/ #define TIFFTAG_IT8COLORTABLE 34022 /* LW colortable */
"/ #define TIFFTAG_IT8IMAGECOLORINDICATOR 34023 /* BP/BL image color switch */
"/ #define TIFFTAG_IT8BKGCOLORINDICATOR 34024 /* BP/BL bg color switch */
"/ #define TIFFTAG_IT8IMAGECOLORVALUE 34025 /* BP/BL image color value */
"/ #define TIFFTAG_IT8BKGCOLORVALUE 34026 /* BP/BL bg color value */
"/ #define TIFFTAG_IT8PIXELINTENSITYRANGE 34027 /* MP pixel intensity value */
"/ #define TIFFTAG_IT8TRANSPARENCYINDICATOR 34028 /* HC transparency switch */
"/ #define TIFFTAG_IT8COLORCHARACTERIZATION 34029 /* color character. table */
"/ #define TIFFTAG_IT8HCUSAGE 34030 /* HC usage indicator */
"/ #define TIFFTAG_IT8TRAPINDICATOR 34031 /* Trapping indicator
"/ (untrapped=0, trapped=1) */
"/ #define TIFFTAG_IT8CMYKEQUIVALENT 34032 /* CMYK color equivalents */
"/ /* tags 34232-34236 are private tags registered to Texas Instruments */
"/ #define TIFFTAG_FRAMECOUNT 34232 /* Sequence Frame Count */
"/ /* tag 34377 is private tag registered to Adobe for PhotoShop */
"/ #define TIFFTAG_PHOTOSHOP 34377
"/ /* tags 34665, 34853 and 40965 are documented in EXIF specification */
"/ #define TIFFTAG_EXIFIFD 34665 /* Pointer to EXIF private directory */
"/ /* tag 34750 is a private tag registered to Adobe? */
"/ #define TIFFTAG_ICCPROFILE 34675 /* ICC profile data */
"/ #define TIFFTAG_IMAGELAYER 34732 /* !!TIFF/FX image layer information */
"/ /* tag 34750 is a private tag registered to Pixel Magic */
"/ #define TIFFTAG_JBIGOPTIONS 34750 /* JBIG options */
"/ #define TIFFTAG_GPSIFD 34853 /* Pointer to GPS private directory */
"/ /* tags 34908-34914 are private tags registered to SGI */
"/ #define TIFFTAG_FAXRECVPARAMS 34908 /* encoded Class 2 ses. parms */
"/ #define TIFFTAG_FAXSUBADDRESS 34909 /* received SubAddr string */
"/ #define TIFFTAG_FAXRECVTIME 34910 /* receive time (secs) */
"/ #define TIFFTAG_FAXDCS 34911 /* encoded fax ses. params, Table 2/T.30 */
"/ /* tags 37439-37443 are registered to SGI <gregl@sgi.com> */
"/ #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 <dev@oceana.com> */
"/ #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 <dev@oceana.com> */
"/ #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: / 28-08-2017 / 00:46:15 / cg"
! !
!TIFFReader class methodsFor:'testing'!
canRepresent:anImage
"return true, if anImage can be represented in my file format.
Any image is supported."
^ true
!
isValidImageFile:aFileName
"return true, if aFileName contains a TIFF image"
|inStream bytes1_2 byte3 byte4 versionLow versionHi|
inStream := self streamReadingFile:aFileName.
inStream isNil ifTrue:[^ 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
].
^ 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'
"Modified: / 3.2.1998 / 18:03:14 / cg"
!
readCCITT3RLEWTiffImageData
^ self fileFormatError:'ccitt G3 mod Huffman (rlew) compression not implemented'.
"Modified: / 3.2.1998 / 18:03:30 / cg"
!
readCCITTGroup3TiffImageData
"not really tested - all I got is a single fax from NeXT step"
|bytesPerRow bitsPerRow compressedStrip nPlanes
stripNr "{ Class: SmallInteger }"
offset "{ Class: SmallInteger }"
row "{ Class: SmallInteger }"
bytesPerStrip "{ Class: SmallInteger }"
count dstIndex|
nPlanes := samplesPerPixel.
(nPlanes ~~ 1) ifTrue:[
(nPlanes == 2) ifTrue:[
(planarConfiguration ~~ PLANARCONFIG_SEPARATE) ifTrue:[
^ self fileFormatError:'only separate planes are supported'.
].
'TIFFReader [info]: ignoring alpha plane' infoPrintCR.
nPlanes := 1
] ifFalse:[
^ 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'.
"/ ].
"/ 'TIFFReader: decompressing CCITT-3 ...' infoPrintNL.
bitsPerRow := width * (bitsPerSample at:1).
bytesPerRow := bitsPerRow // 8.
((bitsPerRow \\ 8) ~~ 0) ifTrue:[
bytesPerRow := bytesPerRow + 1
].
data := ByteArray new:(bytesPerRow * height).
"/ if the number of rows per strip is unknown (-1),
"/ make it one big strip and decompress that
rowsPerStrip = 16rFFFFFFFF ifTrue:[
self assert:(stripByteCounts size == 1).
count := stripByteCounts sum.
compressedStrip := ByteArray uninitializedNew:count.
self positionToStrip:1.
(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 := 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.
]
"
TIFFReader fromFile:'/Users/cg/DownloadsUnsaved/image_software/libtiffpic/g3test.tif'
"
"Modified: / 27-08-2017 / 15:37:51 / cg"
!
readCCITTGroup4TiffImageData
^ self fileFormatError:'ccitt group4 fax compression not implemented'.
"Modified: / 3.2.1998 / 18:04:34 / cg"
!
readCCITTRLEWTiffImageData
^ self fileFormatError:'ccitt mod Huffman (rlew) compression not implemented'
!
readDCSTiffImageData
^ self fileFormatError:'dcs compression not implemented'.
"Modified: / 3.2.1998 / 18:04:44 / cg"
!
readDeflateTiffImageData
self readImageDataUsingDecompresor:
[:inBytes :inCount :outBytes :outOffset :outCount |
|zlibReader|
zlibReader := ZipStream readOpenAsZipStreamOn:(inBytes readStream) suppressHeaderAndChecksum:false.
zlibReader binary.
zlibReader next:outCount into:outBytes startingAt:outOffset.
outCount.
].
"/ |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 (format): / 28-08-2017 / 03:06:39 / cg"
!
readImageDataUsingDecompresor:decompressorBlock
|bytesPerRowIn bytesPerRow nPlanes overAllBytes
nBytes "{ Class: SmallInteger }"
stripNr "{ Class: SmallInteger }"
offset "{ Class: SmallInteger }"
row "{ Class: SmallInteger }"
msb
convert convertFloats convertDoubles convertHalfFloats
swapInt16s convertFillOrder
inBuffer conversionBuffer floats nDecompressed
rowsInThisStrip bytesInThisStrip|
nPlanes := samplesPerPixel.
convert := convertFloats := convertDoubles := convertHalfFloats := false.
swapInt16s := convertFillOrder := false.
(nPlanes >= 3) ifTrue:[
(planarConfiguration ~~ PLANARCONFIG_CONTIG) ifTrue:[
^ self fileFormatError:'only non separate planes are supported with 3 or 4 planes'.
].
(nPlanes > 4) ifTrue:[
photometric == #cmyk ifTrue:[
"/ ignore alpha
'TIFFReader [info]: ignoring alpha plane' infoPrintCR.
nPlanes := samplesPerPixel := 4.
bitsPerSample := bitsPerSample copyTo:4.
].
].
bytesPerRowIn := width * ((bitsPerSample sum + 7) // 8).
sampleFormat == SAMPLEFORMAT_UINT ifTrue:[
(bitsPerSample conform:[:each | each == 8]) ifTrue:[
"/ ok
] ifFalse:[
(bitsPerSample conform:[:each | each == 16]) ifTrue:[
"/ ok
] ifFalse:[
^ self fileFormatError:'only 8 or 16 bits/channel are supported'.
]
].
] ifFalse:[
sampleFormat == SAMPLEFORMAT_IEEEFP ifTrue:[
nPlanes == 3 ifTrue:[
(bitsPerSample conform:[:each | each == 64]) ifTrue:[
convertDoubles := convert := true.
bytesPerRow := width * nPlanes.
bitsPerSample := #(8 8 8).
] ifFalse:[
(bitsPerSample conform:[:each | each == 32]) ifTrue:[
convertFloats := convert := true.
bytesPerRow := width * nPlanes.
bitsPerSample := #(8 8 8).
] ifFalse:[
(bitsPerSample conform:[:each | each == 16]) ifTrue:[
convertHalfFloats := convert := true.
bytesPerRow := width * nPlanes.
bitsPerSample := #(8 8 8).
] ifFalse:[
^ self fileFormatError:'only 16, 32 or 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 with 2 planes'.
].
'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.
(bitsPerSample at:1) == 16 ifTrue:[
byteOrder ~~ #msb ifTrue:[
"/ swapInt16s := true.
].
].
].
fillOrder ~~ #msb ifTrue:[
(bitsPerSample conform:[:n | n == 8]) ifFalse:[
^ self fileFormatError:'unsupported bitsPerSample with lsb fillOrder'
].
convertFillOrder := true.
].
bytesPerRow isNil ifTrue:[ bytesPerRow := bytesPerRowIn ].
overAllBytes := bytesPerRow * height.
data := ByteArray new:overAllBytes.
convert ifTrue:[
conversionBuffer := ByteArray new:(bytesPerRowIn * rowsPerStrip).
].
offset := 1.
stripNr := 1.
row := 1.
msb := (byteOrder == #msb).
[row <= height] whileTrue:[
self positionToStrip:stripNr.
nBytes := stripByteCounts at:stripNr.
rowsInThisStrip := stripRowCounts notNil
ifTrue:[stripRowCounts at:stripNr]
ifFalse:[rowsPerStrip].
bytesInThisStrip := bytesPerRowIn * rowsInThisStrip.
"/ don verify; the last strip is shorter
"/ compression == 1 ifTrue:[
"/ self assert:( nBytes == (bytesPerRowIn * rowsInThisStrip) ).
"/ ].
conversionBuffer notNil ifTrue:[
decompressorBlock notNil ifTrue:[
inBuffer := ByteArray new:nBytes.
(inStream nextBytes:nBytes into:inBuffer startingAt:1) == nBytes ifFalse:[
self fileFormatError:'short read'
].
nDecompressed := decompressorBlock
value:inBuffer value:nBytes
value:conversionBuffer value:1
value:bytesInThisStrip.
] ifFalse:[
(nDecompressed := inStream nextBytes:nBytes into:conversionBuffer startingAt:1) == nBytes ifFalse:[
self fileFormatError:'short read'
].
].
convertFloats ifTrue:[
self assert:(nDecompressed \\ 4) == 0.
floats := FloatArray new:(nDecompressed // 4).
] ifFalse:[
convertDoubles ifTrue:[
self assert:(nDecompressed \\ 8) == 0.
floats := DoubleArray new:(nDecompressed // 8).
] ifFalse:[
convertHalfFloats ifTrue:[
self assert:(nDecompressed \\ 2) == 0.
floats := HalfFloatArray new:(nDecompressed // 2).
].
].
].
floats replaceBytesWith:conversionBuffer.
1 to:floats size do:[:i |
|dVal byteVal|
dVal := floats at:i.
"/ rescale from 0..1 to 0..255
byteVal := (dVal * 255) asInteger clampBetween:0 and:255.
data at:offset+i-1 put:byteVal.
].
] ifFalse:[
decompressorBlock notNil ifTrue:[
inBuffer := ByteArray new:nBytes.
(inStream nextBytes:nBytes into:inBuffer startingAt:1) == nBytes ifFalse:[
self fileFormatError:'short read'
].
nDecompressed := decompressorBlock
value:inBuffer value:nBytes
value:data value:offset
value:bytesInThisStrip.
] ifFalse:[
(inStream nextBytes:nBytes into:data startingAt:offset) == nBytes ifFalse:[
self fileFormatError:'short read'
].
].
].
offset := offset + bytesInThisStrip.
row := row + rowsInThisStrip.
stripNr := stripNr + 1.
].
swapInt16s ifTrue:[
data swapBytes
].
convertFillOrder ifTrue:[
1 to:data size do:[:i |
data at:i put:(data at:i) bitReversed8.
].
].
(predictor ~~ 1) ifTrue:[
(predictor == 2) ifTrue:[
self class decodeDelta:nPlanes in:data width:width height:height
] ifFalse:[
^ self fileFormatError:'unsupported predictor'
].
].
"Created: / 27-08-2017 / 22:48:17 / cg"
"Modified: / 28-08-2017 / 03:41:55 / cg"
!
readJBIGTiffImageData
^ self fileFormatError:'jbig compression not implemented'.
"Modified: / 3.2.1998 / 18:05:04 / cg"
!
readJPEGTiffImageData
|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
self readImageDataUsingDecompresor:
[:inBytes :inCount :outBytes :outOffset :outCount |
self class
decompressLZWFrom:inBytes count:inCount
into:outBytes startingAt:outOffset.
outCount.
].
"/ "read LZW compressed tiff data;
"/ this method only handles 8+8+8 and 8+8+8+8 rgb
"/ and 2bit or 2+2bit greyscale images.
"/ For 2+2bit greyscale images, the alpha plane is ignored.
"/ (maybe other formats work also - but simply not tested)"
"/
"/ |bytesPerRow compressedStrip nPlanes overAllBytes
"/ bytesPerStrip "{ Class: SmallInteger }"
"/ nBytes "{ Class: SmallInteger }"
"/ prevSize "{ Class: SmallInteger }"
"/ stripNr "{ Class: SmallInteger }"
"/ offset "{ Class: SmallInteger }"
"/ row "{ Class: SmallInteger }" |
"/
"/ nPlanes := samplesPerPixel.
"/
"/ (nPlanes >= 3) ifTrue:[
"/ (bitsPerSample conform:[:each | each == 8]) ifFalse:[
"/ ^ self fileFormatError:'only 8/8/8(/8) bits/sample are supported'.
"/ ].
"/ bytesPerRow := width * samplesPerPixel.
"/ ] 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'.
"/ ].
"/ bytesPerRow := (width * (bitsPerSample at:1) + 7) // 8.
"/ ].
"/ stripRowCounts notNil ifTrue:[
"/ ^ self fileFormatError:'stripRowCounts not supported'.
"/ ].
"/
"/ "/ 'TIFFReader: decompressing LZW ...' infoPrintNL.
"/
"/ overAllBytes := bytesPerRow * height.
"/ bytesPerRow == width ifTrue:[
"/ data := ByteArray uninitializedNew:overAllBytes.
"/ ] ifFalse:[
"/ data := ByteArray new:overAllBytes.
"/ ].
"/
"/ offset := 1.
"/ stripNr := 0.
"/
"/ row := 1.
"/ bytesPerStrip := bytesPerRow * rowsPerStrip.
"/ prevSize := 0.
"/ [row <= height] whileTrue:[
"/ stripNr := stripNr + 1.
"/ self positionToStrip:stripNr.
"/ nBytes := stripByteCounts at:stripNr.
"/ (nBytes > prevSize) ifTrue:[
"/ compressedStrip := ByteArray uninitializedNew:nBytes.
"/ prevSize := nBytes
"/ ].
"/ (inStream nextBytes:nBytes into:compressedStrip) == nBytes ifFalse:[ self fileFormatError:'short file' ].
"/ self class
"/ decompressLZWFrom:compressedStrip count: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 / 22:58:36 / cg"
!
readNeXTJPEGTiffImageData
^ self fileFormatError:'next jpeg compression not implemented'.
"Modified: / 3.2.1998 / 18:10:45 / cg"
!
readNeXTRLE2TiffImageData
^ self fileFormatError:'next 2bit rle compression not implemented'.
"Modified: / 3.2.1998 / 18:10:54 / cg"
!
readNewJPEGTiffImageData
^ self fileFormatError:'new jpeg compression not implemented'.
!
readPackbitsTiffImageData
self readImageDataUsingDecompresor:
[:inBytes :inCount :outBytes :outOffset :outCount |
self class decompressTiffPackBitsFrom:inBytes to:outBytes at:outOffset count:outCount.
].
"/ "this has only been tested with monochrome images"
"/
"/ |bytesPerRow bitsPerRow nPlanes
"/ stripNr "{ Class: SmallInteger }"
"/ offset "{ Class: SmallInteger }"
"/ row "{ Class: SmallInteger }"
"/ nBytes "{ Class: SmallInteger }" bitsPerPixel overAllBytes buffer|
"/
"/ nPlanes := samplesPerPixel.
"/
"/ "only support 1-sample/pixel,
"/ with alpha - if separate planes,
"/ or rgb - if non separate planes and no alpha"
"/
"/ (nPlanes == 2) ifTrue:[
"/ (planarConfiguration ~~ PLANARCONFIG_SEPARATE) ifTrue:[
"/ ^ self fileFormatError:'with alpha, only separate planes supported'.
"/ ].
"/ 'TIFFReader [info]: ignoring alpha plane' infoPrintCR.
"/ nPlanes := 1.
"/ bitsPerPixel := bitsPerSample at:1.
"/ bitsPerSample := Array with:bitsPerPixel.
"/ samplesPerPixel := 1.
"/ ] ifFalse:[
"/ (nPlanes == 3) ifTrue:[
"/ (planarConfiguration ~~ PLANARCONFIG_CONTIG) ifTrue:[
"/ ^ self fileFormatError:'only non separate planes supported'.
"/ ].
"/ bitsPerSample ~= #(8 8 8) ifTrue:[
"/ ^ self fileFormatError:'only 8/8/8 rgb images supported'.
"/ ].
"/ bitsPerPixel := 24
"/ ] ifFalse:[
"/ (nPlanes ~~ 1) ifTrue:[
"/ ^ self fileFormatError:('format (nplanes == %1) not supported' bindWith:nPlanes).
"/ ].
"/ bitsPerPixel := bitsPerSample at:1.
"/ ]
"/ ].
"/ stripRowCounts notNil ifTrue:[
"/ ^ self fileFormatError:'stripRowCounts not supported'.
"/ ].
"/
"/ bitsPerRow := width * bitsPerPixel.
"/ bytesPerRow := bitsPerRow // 8.
"/ ((bitsPerRow \\ 8) ~~ 0) ifTrue:[
"/ bytesPerRow := bytesPerRow + 1
"/ ].
"/
"/ overAllBytes := bytesPerRow * height.
"/ bytesPerRow == width ifTrue:[
"/ data := ByteArray uninitializedNew:overAllBytes.
"/ ] ifFalse:[
"/ data := ByteArray new:overAllBytes.
"/ ].
"/
"/ offset := 1.
"/ stripNr := 1.
"/
"/ buffer := nil.
"/ row := 1.
"/ [row <= height] whileTrue:[
"/ nBytes := stripByteCounts at:stripNr.
"/ self positionToStrip:stripNr.
"/
"/ nBytes > buffer size ifTrue:[
"/ "/ realloc
"/ buffer := ByteArray uninitializedNew: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 + (bytesPerRow * rowsPerStrip).
"/ row := row + rowsPerStrip.
"/ stripNr := stripNr + 1.
"/ ]
"Modified: / 28-08-2017 / 00:24:21 / cg"
!
readPixarFilmTiffImageData
^ self fileFormatError:'pixar film compression not implemented'.
"Modified: / 3.2.1998 / 18:11:45 / cg"
!
readPixarLogTiffImageData
^ self fileFormatError:'pixar log compression not implemented'.
"Modified: / 3.2.1998 / 18:11:53 / cg"
!
readSGI24TiffImageData
^ self fileFormatError:'SGI 24-bit Log Luminance encoding not implemented' .
"Created: / 25-08-2017 / 11:17:25 / cg"
!
readSGI32TiffImageData
^ self fileFormatError:'SGI 32-bit Log Luminance encoding not implemented' .
"Created: / 25-08-2017 / 11:17:21 / cg"
!
readThunderScanTiffImageData
|bytesPerRow compressedStrip nPlanes overAllBytes
bytesPerStrip "{ Class: SmallInteger }"
nBytes "{ Class: SmallInteger }"
prevSize "{ Class: SmallInteger }"
stripNr "{ Class: SmallInteger }"
offset "{ Class: SmallInteger }"
row "{ Class: SmallInteger }"
pixelIndex
i even gen highNibble lastPixel d1 d2 d3|
nPlanes := samplesPerPixel.
(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.
].
(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.
overAllBytes := bytesPerRow * height.
bytesPerRow == width ifTrue:[
data := ByteArray uninitializedNew:overAllBytes.
] ifFalse:[
data := ByteArray new:overAllBytes.
].
offset := 1.
stripNr := 0.
gen := [:pixel |
even ifTrue:[
highNibble := pixel.
even := false.
] ifFalse:[
data at:pixelIndex put:((highNibble bitShift:4) bitOr:pixel).
pixelIndex := pixelIndex + 1.
even := true.
].
].
even := true.
lastPixel := 0.
row := 1.
bytesPerStrip := bytesPerRow * rowsPerStrip.
prevSize := 0.
[row <= height] whileTrue:[
stripNr := stripNr + 1.
self positionToStrip:stripNr.
nBytes := stripByteCounts at:stripNr.
(nBytes > prevSize) ifTrue:[
compressedStrip := ByteArray uninitializedNew:nBytes.
prevSize := nBytes
].
(inStream nextBytes:nBytes into:compressedStrip) == nBytes ifFalse:[ self error:'short read' ].
"/ RLE decode... (see http://fileformats.archiveteam.org/wiki/ThunderScan_compression)
i := 1.
pixelIndex := offset.
[i <= nBytes] whileTrue:[
|code|
code := compressedStrip at:i.
i := i + 1.
code >= 2r11000000 ifTrue:[
"/ a single pixel
lastPixel := code bitAnd:2r00111111.
self assert:(lastPixel <= 2r1111).
gen value:lastPixel.
] ifFalse:[
code >= 2r10000000 ifTrue:[
"/ three bit deltas (2 pixels)
d1 := (code rightShift:3) bitAnd:2r111.
d2 := code bitAnd:2r111.
d1 ~~ 4 ifTrue:[
lastPixel := lastPixel + (#(0 1 2 3 0 -3 -2 -1) at:d1+1).
gen value:lastPixel.
].
d2 ~~ 4 ifTrue:[
lastPixel := lastPixel + (#(0 1 2 3 0 -3 -2 -1) at:d2+1).
gen value:lastPixel.
].
] ifFalse:[
code >= 2r01000000 ifTrue:[
"/ two bit deltas (3 pixels)
d1 := (code rightShift:4) bitAnd:2r11.
d2 := (code rightShift:2) bitAnd:2r11.
d3 := code bitAnd:2r11.
d1 ~~ 2 ifTrue:[
lastPixel := lastPixel + (#(0 1 0 -1) at:d1+1).
gen value:lastPixel.
].
d2 ~~ 2 ifTrue:[
lastPixel := lastPixel + (#(0 1 0 -1) at:d2+1).
gen value:lastPixel.
].
d3 ~~ 2 ifTrue:[
lastPixel := lastPixel + (#(0 1 0 -1) at:d3+1).
gen value:lastPixel.
].
] ifFalse:[
code timesRepeat:[ gen value:lastPixel ].
].
].
].
].
"/ self assert:(pixelIndex == (offset + bytesPerStrip)).
offset := offset + bytesPerStrip.
row := row + rowsPerStrip
].
(predictor ~~ 1) ifTrue:[
^ self fileFormatError:('unsupported predictor: %1' bindWith:predictor).
].
"Modified: / 27-08-2017 / 15:38:47 / cg"
!
readTiffImageData
(compression == COMPRESSION_NONE " 1 " ) ifTrue:[
self readUncompressedTiffImageData.
^ self
].
(compression == COMPRESSION_CCITTRLE " 2 ") ifTrue:[
self readCCITT3RLETiffImageData.
^ self
].
(compression == COMPRESSION_CCITTFAX3 " 3 ") ifTrue:[
self readCCITTGroup3TiffImageData.
^ self
].
(compression == COMPRESSION_CCITTFAX4 " 4 ") ifTrue:[
self readCCITTGroup4TiffImageData.
^ self
].
(compression == COMPRESSION_LZW " 5 ") ifTrue:[
self readLZWTiffImageData.
^ self
].
(compression == COMPRESSION_OJPEG " 6 ") ifTrue:[
self readJPEGTiffImageData.
^ self
].
(compression == COMPRESSION_JPEG " 7 ") ifTrue:[
self readNewJPEGTiffImageData.
^ self
].
(compression == COMPRESSION_ADOBE_DEFLATE " 8 ") ifTrue:[
self readAdobeDeflateTiffImageData.
^ self
].
(compression == COMPRESSION_NEXT " 32766 ") ifTrue:[
self readNeXTRLE2TiffImageData.
^ self
].
(compression == COMPRESSION_CCITTRLEW " 32771 ") ifTrue:[
self readCCITTRLEWTiffImageData.
^ self
].
(compression == COMPRESSION_PACKBITS " 32773 ") ifTrue:[
self readPackbitsTiffImageData.
^ self
].
(compression == COMPRESSION_THUNDERSCAN " 32809 ") ifTrue:[
self readThunderScanTiffImageData.
^ self
].
(compression == COMPRESSION_PIXARFILM " 32908 ") ifTrue:[
self readPixarFilmTiffImageData.
^ self
].
(compression == COMPRESSION_PIXARLOG " 32909 ") ifTrue:[
self readPixarLogTiffImageData.
^ self
].
(compression == COMPRESSION_DEFLATE " 32946 ") ifTrue:[
self readDeflateTiffImageData.
^ self
].
(compression == COMPRESSION_DCS " 32947 ") ifTrue:[
self readDCSTiffImageData.
^ self
].
(compression == COMPRESSION_NEXT_JPEG " 32865 ") ifTrue:[
self readNeXTJPEGTiffImageData.
^ self
].
(compression == COMPRESSION_JBIG " 34661 ") ifTrue:[
self readJBIGTiffImageData.
^ self
].
(compression == COMPRESSION_SGILOG " 34676 ") ifTrue:[
self readSGI32TiffImageData.
^ self
].
(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: / 26-08-2017 / 21:46:56 / cg"
!
readTiledJPEGTiffImageData
^ 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
^ self fileFormatError:'tiled LZW data not implemented' .
"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 == COMPRESSION_NONE " 1 ") ifTrue:[
self readTiledUncompressedTiffImageData.
^ self
].
(compression == COMPRESSION_LZW " 5 ") ifTrue:[
self readTiledLZWTiffImageData.
^ self
].
(compression == COMPRESSION_OJPEG " 6 ") ifTrue:[
self readTiledJPEGTiffImageData.
^ self
].
(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: / 26-08-2017 / 13:39:15 / cg"
!
readTiledUncompressedTiffImageData
|bytesPerRow "{ Class: SmallInteger }"
bitsPerRow "{ Class: SmallInteger }"
bytesPerTileRow "{ Class: SmallInteger }"
bitsPerTileRow "{ Class: SmallInteger }"
nPlanes
tileNr "{ Class: SmallInteger }"
"/ offset "{ Class: SmallInteger }"
"/ row "{ Class: SmallInteger }"
nBytes "{ Class: SmallInteger }"
bitsPerPixel "{ Class: SmallInteger }"
overAllBytes "{ Class: SmallInteger }"
where "{ Class: SmallInteger }"
x "{ Class: SmallInteger }"
y "{ Class: SmallInteger }"
imageRowOffset "{ Class: SmallInteger }"
imageOffset "{ Class: SmallInteger }"
tileOffset "{ Class: SmallInteger }"
dataOffset "{ Class: SmallInteger }"
tilePos tile tH tW tb|
nPlanes := samplesPerPixel.
"/ not all formats are supported here,
(nPlanes == 2) ifTrue:[
(planarConfiguration ~~ PLANARCONFIG_SEPARATE) ifTrue:[
^ self fileFormatError:'with alpha, only separate planes supported'.
].
'TIFFReader [info]: ignoring alpha plane' infoPrintCR.
nPlanes := 1.
bitsPerPixel := bitsPerSample at:1.
bitsPerSample := Array with:bitsPerPixel.
samplesPerPixel := 1.
] ifFalse:[
(nPlanes == 4) 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 images supported (is: ' , bitsPerSample printString , ')'.
].
bitsPerPixel := 32.
] ifFalse:[
(nPlanes == 3) ifTrue:[
(planarConfiguration ~~ PLANARCONFIG_CONTIG) ifTrue:[
^ self fileFormatError:'only non separate planes supported'.
].
bitsPerSample ~= #(8 8 8) ifTrue:[
^ self fileFormatError:'only 8/8/8 images supported (is: ' , bitsPerSample printString , ')'.
].
bitsPerPixel := 24
] ifFalse:[
(nPlanes ~~ 1) ifTrue:[
^ self fileFormatError:('unsupported format: nplanes=' , nPlanes printString).
].
bitsPerPixel := bitsPerSample at:1.
]
]
].
stripRowCounts notNil ifTrue:[
^ self fileFormatError:'stripRowCounts not supported'.
].
bitsPerRow := width * bitsPerPixel.
bytesPerRow := (bitsPerRow + 7) // 8.
bitsPerTileRow := tileWidth * bitsPerPixel.
bytesPerTileRow := (bitsPerTileRow + 7) // 8.
overAllBytes := bytesPerRow * height.
data := ByteArray new:overAllBytes.
tileNr := 1.
where := -1.
y := 0.
imageRowOffset := 1.
[ y < height ] whileTrue:[
tH := tileLength.
(y+tileLength) > height ifTrue:[
tH := height - y.
].
x := 0.
imageOffset := imageRowOffset.
[ x < width ] whileTrue:[
nBytes := tileByteCounts at:tileNr.
tilePos := tileOffsets at:tileNr.
tileNr := tileNr + 1.
where ~~ tilePos ifTrue:[
inStream position:tilePos.
where := tilePos.
].
tile := ByteArray new:nBytes.
inStream nextBytes:nBytes into:tile startingAt:1 blockSize:4096.
"/ copy the tile.
tileOffset := 1.
dataOffset := imageOffset.
tW := tileWidth.
tb := bytesPerTileRow.
(x+tileWidth) > width ifTrue:[
tW := width-x.
tb := ((bitsPerPixel * tW) + 7) // 8.
].
1 to:tH do:[:yT |
data replaceFrom:dataOffset to:dataOffset+tb-1 with:tile startingAt:tileOffset.
dataOffset := dataOffset + bytesPerRow.
tileOffset := tileOffset + bytesPerTileRow.
].
"/ offset := offset + nBytes.
"/ row := row + rowsPerStrip.
where := where + nBytes.
x := x + tW.
imageOffset := imageOffset + bytesPerTileRow.
].
y := y + tH.
imageRowOffset := imageRowOffset + (bytesPerRow*tH).
].
"Created: / 25-08-2017 / 00:22:31 / cg"
"Modified: / 28-08-2017 / 01:14:00 / cg"
!
readUncompressedTiffImageData
self readImageDataUsingDecompresor:nil
"/ |bytesPerRow "{ Class: SmallInteger }"
"/ bitsPerRow "{ Class: SmallInteger }"
"/ nPlanes
"/ stripNr "{ Class: SmallInteger }"
"/ offset "{ Class: SmallInteger }"
"/ row "{ Class: SmallInteger }"
"/ nBytes "{ Class: SmallInteger }"
"/ bitsPerPixel
"/ overAllBytes "{ Class: SmallInteger }"
"/ where "{ Class: SmallInteger }"
"/ stripPos
"/ convertFloats convertDoubles convertHalfFloats|
"/
"/ nPlanes := samplesPerPixel.
"/
"/ "/ not all formats are supported here,
"/
"/ (nPlanes == 2) ifTrue:[
"/ (planarConfiguration ~~ PLANARCONFIG_SEPARATE) ifTrue:[
"/ ^ self fileFormatError:'with alpha, only separate planes supported'.
"/ ].
"/ 'TIFFReader [info]: ignoring alpha plane' infoPrintCR.
"/ nPlanes := 1.
"/ bitsPerPixel := bitsPerSample at:1.
"/ bitsPerSample := Array with:bitsPerPixel.
"/ samplesPerPixel := 1.
"/ ] ifFalse:[
"/ (nPlanes == 4) ifTrue:[
"/ (planarConfiguration ~~ PLANARCONFIG_CONTIG) ifTrue:[
"/ ^ self fileFormatError:'only non separate planes supported'.
"/ ].
"/ bitsPerSample ~= #(8 8 8 8) ifTrue:[
"/ bitsPerSample ~= #(16 16 16 16) ifTrue:[
"/ ^ self fileFormatError:'only 8/8/8/8 and 16/16/16/16 images supported'.
"/ ].
"/ ].
"/ bitsPerPixel := bitsPerSample sum.
"/ ] ifFalse:[
"/ (nPlanes == 3) ifTrue:[
"/ (planarConfiguration ~~ 1) ifTrue:[
"/ ^ self fileFormatError:'only non separate planes supported'.
"/ ].
"/ bitsPerSample ~= #(8 8 8) ifTrue:[
"/ bitsPerSample ~= #(16 16 16) ifTrue:[
"/ ^ self fileFormatError:'only 8/8/8 and 16/16/16 images supported; is: ' , bitsPerSample printString.
"/ ].
"/ ].
"/ bitsPerPixel := bitsPerSample sum.
"/ ] ifFalse:[
"/ (nPlanes ~~ 1) ifTrue:[
"/ ^ self fileFormatError:('unsupported format: nplanes=' , nPlanes printString).
"/ ].
"/ bitsPerPixel := bitsPerSample at:1.
"/ ]
"/ ]
"/ ].
"/ stripRowCounts notNil ifTrue:[
"/ ^ self fileFormatError:'stripRowCounts not supported'.
"/ ].
"/
"/ bitsPerRow := width * bitsPerPixel.
"/ bytesPerRow := bitsPerRow // 8.
"/ ((bitsPerRow \\ 8) ~~ 0) ifTrue:[
"/ bytesPerRow := bytesPerRow + 1
"/ ].
"/
"/ overAllBytes := bytesPerRow * height.
"/ bytesPerRow == width ifTrue:[
"/ data := ByteArray uninitializedNew:overAllBytes.
"/ ] ifFalse:[
"/ data := ByteArray new:overAllBytes.
"/ ].
"/
"/ offset := 0.
"/ stripNr := 0.
"/ where := -1.
"/ row := 1.
"/ [row <= height] whileTrue:[
"/ stripNr := stripNr + 1.
"/ nBytes := stripByteCounts at:stripNr.
"/ stripPos := stripOffsets at:stripNr.
"/ where ~~ stripPos ifTrue:[
"/ inStream position:stripPos.
"/ where := stripPos.
"/ ].
"/
"/ offset + nBytes > overAllBytes ifTrue:[
"/ nBytes := overAllBytes - offset.
"/ ].
"/
"/ (inStream nextBytes:nBytes into:data startingAt:offset+1) == nBytes ifFalse:[
"/ ^ self fileFormatError:'short read'.
"/ ].
"/
"/ offset := offset + nBytes.
"/ row := row + rowsPerStrip.
"/ where := where + nBytes.
"/ ].
"Modified: / 27-08-2017 / 22:48:27 / 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
n "{ Class: SmallInteger }"
i2 "{ Class: SmallInteger }"
i3 "{ Class: SmallInteger }" |
Verbose == true ifTrue:[ Logger info:'tiffTag: %1' with:tagType ].
(numberType == 3 "TIFF_SHORT") ifTrue:[
"16 bit ushort"
valueArray := self readShorts:length signed:false.
value := valueArray at:1
] ifFalse:[(numberType == 4 "TIFF_LONG") ifTrue:[
"32 bit uinteger"
valueArray := self readLongs:length signed:false.
value := valueArray at:1
] ifFalse:[(numberType == 2 "TIFF_ASCII") ifTrue:[
"ascii characters"
value := self readChars:length
] ifFalse:[(numberType == 5 "TIFF_RATIONAL") ifTrue:[
"64 (32+32) bit ufraction"
valueArray := self readFracts:length signed:false.
value := valueArray at:1
] ifFalse:[(numberType == 1 "TIFF_BYTE") ifTrue:[
"8bit uinteger"
value := self readBytes:length signed:false
] ifFalse:[(numberType == 6 "TIFF_SBYTE") ifTrue:[
"TIFF6: 8bit signed integer"
value := self readBytes:length signed:true
] ifFalse:[(numberType == 8 "TIFF_SSHORT") ifTrue:[
"TIFF6: 16bit signed integer"
valueArray := self readShorts:length signed:true.
value := valueArray at:1
] ifFalse:[(numberType == 9 "TIFF_SLONG") ifTrue:[
"TIFF6: 32bit signed integer"
valueArray := self readLongs:length signed:true.
value := valueArray at:1
] ifFalse:[(numberType == 10 "TIFF_SRATIONAL") ifTrue:[
"TIFF6: 64 (32+32) bit signed fraction"
valueArray := self readFracts:length signed:true.
value := valueArray at:1
] ifFalse:[(numberType == 11 "TIFF_FLOAT") ifTrue:[
"TIFF6: 32 bit IEEE float"
valueArray := self readFloats:length.
value := valueArray at:1
] ifFalse:[(numberType == 12 "TIFF_DOUBLE") ifTrue:[
"TIFF6: 64 bit IEEE double"
valueArray := self readDoubles:length.
value := valueArray at:1
] ifFalse:[(numberType == 7 "TIFF_UNDEFINED") ifTrue:[
"8bit anything"
value := self readBytes:length signed:false
"/ the following are preps for the propsed bigTiff format
] ifFalse:[(numberType == 16 "TIFF_LONG8") ifTrue:[
"BIGTIFF: 8-byte unsigned integer"
valueArray := self readLong8s:length signed:false.
value := valueArray at:1.
] ifFalse:[(numberType == 17 "TIFF_SLONG8") ifTrue:[
"BIGTIFF: 8-byte signed integer"
valueArray := self readLong8s:length signed:true.
value := valueArray at:1.
] ifFalse:[(numberType == 18 "TIFF_IFD8") ifTrue:[
"BIGTIFF: 8-byte unsigned IFD offset"
valueArray := self readLong8s:length signed:false.
value := valueArray at:1.
] ifFalse:[
isBigTiff ifTrue:[
offset := (inStream nextInt64MSB:(byteOrder ~~ #lsb))
] ifFalse:[
offset := (inStream nextInt32MSB:(byteOrder ~~ #lsb))
]
]]]]]]]]]]]]]]].
(tagType between:200 and:299) ifTrue:[
(tagType == 254) ifTrue:[
"/ New SubfileType
"/ REDUCEDIMAGE -> 1
"/ PAGE -> 2
"/ MASK -> 4
"newSubFileType := value."
"/ 'newSubfiletype ' print. value printNewline.
Verbose == true ifTrue:[
Logger info:' newSubfiletype: %1' with:value
].
^ self
].
(tagType == 255) ifTrue:[
"/ Old SubfileType
"/ IMAGE -> 1
"/ REDUCEDIMAGE -> 2
"/ PAGE -> 3
subFileType := value.
Verbose == true ifTrue:[
Logger info:' oldSubfiletype: %1' with:value
].
^ self
].
(tagType == 256) ifTrue:[
"ImageWidth"
width := value.
Verbose == true ifTrue:[
Logger info:' width: %1' with:value
].
^ self
].
(tagType == 257) ifTrue:[
"ImageHeight"
height := value.
Verbose == true ifTrue:[
Logger info:' height: %1' with:value
].
^ self
].
(tagType == 258) ifTrue:[
"bitspersample"
bitsPerSample := valueArray.
Verbose == true ifTrue:[
Logger info:' bitspersample: %1' with:valueArray
].
^ self
].
(tagType == 259) ifTrue:[
"/ compression
"/ NONE -> 1
"/ CCITTRLE -> 2
"/ CCITTFAX3 -> 3
"/ CCITTFAX4 -> 4
"/ LZW -> 5
"/ OJPEG -> 6 (old style jpeg)
"/ JPEG -> 7 (new style jpeg)
"/ ADOBE_DEFLATE -> 8
"/ JBIG -> 9 (ITU-T T85)
"/ JBIG -> 10 (ITU-T T43)
"/ NEXT -> 32766 (NeXT 2-bit encoding)
"/ CCITTRLEW -> 32771
"/ PACKBITS -> 32773
"/ THUNDERSCAN -> 32809 (ThunderScan 4-bit encoding)
"/ IT8CTPAD -> 32895
"/ IT8LW -> 32896
"/ IT8MP -> 32897
"/ IT8BL -> 32898
"/ PIXARFILM -> 32908
"/ PIXARLOG -> 32909 (Pixar companded 11-bit ZIP encoding)
"/ DEFLATE -> 32946 (PKZIP-style Deflate encoding)
"/ DCS -> 32947 (kodac)
"/ JBIG -> 34661
"/ SGI32 -> 34676 (SGI 32-bit Log Luminance encoding)
"/ SGI24 -> 34677 (SGI 24-bit Log Luminance encoding)
"/ JPEG2000 -> 34712 JPEG2000
"/ NIKON_NEF -> 34713
"/ JBIG2 -> 34715
compression := 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|
(value between:0 and:10) ifTrue:[
p :=
#(
whiteIs0 "/ 0 - grayscale or monochrome; faxes
blackIs0 "/ 1 - grayscale or monochrome; faxes
rgb "/ 2
palette "/ 3
transparencyMask "/ 4
cmyk "/ 5 - color separations
YCbCr "/ 6 - CCIR 601
nil "/ 7
CIElab "/ 8 - 1976 CIE L*a*b*
ICClab "/ 9 - ICC L*a*b*
ITUlab "/ 10 - see ITO-T- Rec T42 (RFC 2301)
) at:(value + 1)
] ifFalse:[
(value == 32803) ifTrue:[
p := #ColorFilterArray "/ camera rw format
].
(value == 32844) ifTrue:[
p := #PixarLogL
].
(value == 32845) ifTrue:[
p := #PixarLogLuv
].
(value == 34892) ifTrue:[
p := #LinearRaw "/ camera rw format
].
].
photometric := p.
Verbose == true ifTrue:[
Logger info:' photometric: %1 (=%2)' with:value with:photometric
].
^ self
].
(tagType == 263) ifTrue:[
"/ Thresholding
"/ BILEVEL -> 1
"/ HALFTONE -> 2
"/ ERRORDIFFUSE -> 3
"thresholding := value."
"/ 'thresholding ' print. value printNewline.
^ self
].
(tagType == 264) ifTrue:[
"CellWidth"
"/ 'cellWidth ' print. value printNewline.
metaData at:#CellWidth put:value.
^ self
].
(tagType == 265) ifTrue:[
"CellLength"
"/ 'cellLength ' print. value printNewline.
metaData at:#CellLength put:value.
^ self
].
(tagType == 266) ifTrue:[
"fillOrder"
(value == FILLORDER_MSB2LSB ) ifTrue:[
fillOrder := #msb
] ifFalse:[
(value == FILLORDER_LSB2MSB) ifTrue:[
fillOrder := #lsb
] ifFalse:[
fillOrder := nil
]
].
Verbose == true ifTrue:[
Logger info:' fillorder: %1' with:value
].
^ self
].
(tagType == 269) ifTrue:[
"documentName - info only"
metaData at:#DocumentName put:value.
Verbose == true ifTrue:[
Logger info:' documentName: %1' with:value
].
^ self
].
(tagType == 270) ifTrue:[
"imageDescription - info only"
metaData at:#ImageDescription put:value.
Verbose == true ifTrue:[
Logger info:' imageDescription: %1' with:value
].
^ self
].
(tagType == 271) ifTrue:[
"make - info only"
metaData at:#Make put:value.
Verbose == true ifTrue:[
Logger info:' make: %1' with:value
].
^ self
].
(tagType == 272) ifTrue:[
"model - info only"
metaData at:#Model put:value.
Verbose == true ifTrue:[
Logger info:' model: %1' with:value
].
^ self
].
(tagType == 273) ifTrue:[
"stripOffsets"
stripOffsets := valueArray.
Verbose == true ifTrue:[
Logger info:' stripOffsets: %1' with:valueArray
].
^ self
].
(tagType == 274) ifTrue:[
"Orientation"
orientation :=
#( nil "/ 1 normal (topLeft)
hFlip "/ 2 horizontal flip
hvFlip "/ 3 horizontal & vertical flip
vFlip "/ 4 vertical 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 (=%2)' with:value with:(orientation ? #normal)
].
^ self
].
(tagType == 277) ifTrue:[
samplesPerPixel := value.
Verbose == true ifTrue:[
Logger info:' samplesperpixel: %1' with:value
].
^ self
].
(tagType == 278) ifTrue:[
rowsPerStrip := value.
Verbose == true ifTrue:[
Logger info:' rowsPerStrip: %1' with:value
].
^ self
].
(tagType == 279) ifTrue:[
"stripbytecount"
stripByteCounts := valueArray.
"/ 'stripByteCounts Array(' print.
"/ stripByteCounts size print.
"/ ')' printNewline.
Verbose == true ifTrue:[
Logger info:' stripByteCounts: %1' with:valueArray
].
^ self
].
(tagType == 280) ifTrue:[
"/ minSampleValue
metaData at:#MinSampleValue put:value.
Verbose == true ifTrue:[
Logger info:' minSampleValue: %1' with:value
].
^ self
].
(tagType == 281) ifTrue:[
"/ 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 (%2)' with:value with:value asFloat
].
^ self
].
(tagType == 283) ifTrue:[
"/ yResolution
metaData at:#ResolutionY put:value.
Verbose == true ifTrue:[
Logger info:' yResolution: %1 (%2)' with:value with:value asFloat
].
^ self
].
(tagType == 284) ifTrue:[
(value == 1) ifTrue:[
planarConfiguration := PLANARCONFIG_CONTIG
] ifFalse:[
(value == 2) ifTrue:[
planarConfiguration := PLANARCONFIG_SEPARATE
] ifFalse:[
planarConfiguration := nil
]
].
Verbose == true ifTrue:[
Logger info:' planarConfiguration: %1' with:value
].
^ self
].
(tagType == 285) ifTrue:[
"/ 'pageName ' print. value printNewline.
metaData at:#PageName put:value.
^ self
].
(tagType == 286) ifTrue:[
"/ xPosition
metaData at:#PositionX put:value.
Verbose == true ifTrue:[
Logger info:' xPosition: %1' with:value
].
^ self
].
(tagType == 287) ifTrue:[
"/ yPosition
metaData at:#PositionY put:value.
Verbose == true ifTrue:[
Logger info:' yPosition: %1' with:value
].
^ self
].
(tagType == 288) ifTrue:[
"/ 'freeOffsets ' print. value printNewline.
^ self
].
(tagType == 289) ifTrue:[
"/ 'freeByteCounts ' print. value printNewline.
^ self
].
(tagType == 290) ifTrue:[
"/ 'grayResponceUnit' print. value printNewline.
metaData at:#GrayResponceUnit put:value.
^ self
].
(tagType == 291) ifTrue:[
"/ 'grayResponceCurve' print. value printNewline.
metaData at:#GrayResponceCurve put:value.
^ self
].
(tagType == 292) ifTrue:[
"/ group3options (now called T4Options)
"/ 2DENCODING -> 1
"/ UNCOMPRESSED -> 2
"/ FILLBITS -> 4
group3options := value.
Verbose == true ifTrue:[
Logger info:' group3options: %1' with:value
].
^ self
].
(tagType == 293) ifTrue:[
"/ group4options (now called T6Options)
"/ UNCOMPRESSED -> 2
"/ group4options := value.
Verbose == true ifTrue:[
Logger info:' group4options: %1' with:value
].
^ self
].
(tagType == 296) ifTrue:[
"resolutionunit"
"/ (value == 1) ifTrue:[
"/ 'res-unit pixel' printNewline
"/ ] ifFalse:[
"/ (value == 2) ifTrue:[
"/ 'res-unit inch' printNewline
"/ ] ifFalse:[
"/ (value == 3) ifTrue:[
"/ 'res-unit mm' printNewline
"/ ] ifFalse:[
"/ 'res-unit invalid' printNewline
"/ ]
"/ ]
"/ ].
metaData at:#ResolutionUnit put:value.
Verbose == true ifTrue:[
Logger info:' resolutionUnit: %1' with:value
].
^ self
].
(tagType == 297) ifTrue:[
"/ 'pageNumber ' print. value printNewline.
metaData at:#PageNumber put:value.
Verbose == true ifTrue:[
Logger info:' PageNumber: %1' with:value
].
^ self
].
].
(tagType between:300 and:399) ifTrue:[
(tagType == 300) ifTrue:[
"/ 'colorResponceUnit' print. value printNewline.
metaData at:#ColorResponceUnit put:value.
^ self
].
(tagType == 301) ifTrue:[
"/ 'colorResponceCurve' print. value printNewline.
metaData at:#ColorResponceCurve put:value.
^ self
].
(tagType == 305) ifTrue:[
"software - info only"
metaData at:#Software put:value.
Verbose == true ifTrue:[
Logger info:' software: %1' with:value
].
^ self
].
(tagType == 306) ifTrue:[
"dateTime - info only"
metaData at:#DateTime put:value.
Verbose == true ifTrue:[
Logger info:' dateTime: %1' with:value
].
^ self
].
(tagType == 315) ifTrue:[
"artist - info only"
metaData at:#Artist put:value.
Verbose == true ifTrue:[
Logger info:' artist: %1' with:value
].
^ self
].
(tagType == 316) ifTrue:[
"host computer - info only"
metaData at:#HostComputer put:value.
Verbose == true ifTrue:[
Logger info:' host: %1' with:value
].
^ self
].
(tagType == 317) ifTrue:[
"/ predictor
"/ 1 -> no predictor
"/ 2 -> horiz. difference (see tiff spec 6.0)
"/ 3 -> flt pnt (see adobe tech notes)
"/ 34892 -> horiz difference x2
"/ 34893 -> horiz difference x4
"/ 34894 -> flt pnt x2
"/ 34895 -> flt pnt x4
predictor := value.
Verbose == true ifTrue:[
Logger info:' predictor: %1' with:value
].
^ self
].
(tagType == 318) ifTrue:[
"/ whitePoint
metaData at:#WhitePoint put:value.
^ self
].
(tagType == 319) ifTrue:[
"/ primaryChromatics
metaData at:#PrimaryChromatics put:value.
^ self
].
(tagType == 320) ifTrue:[
"/ 'colorMap (size=' print. valueArray size print. ')' printNewline.
"
the tiff colormap contains 16bit values;
our colormap expects 8bit values
"
n := valueArray size // 3.
rV := ByteArray uninitializedNew:n.
gV := ByteArray uninitializedNew:n.
bV := ByteArray uninitializedNew:n.
scaleFactor := 255.0 / 16rFFFF.
i2 := n+1.
i3 := 2*n+1.
1 to:n do:[:vi |
val := ((valueArray at:vi) * scaleFactor) rounded.
rV at:vi put:val.
val := ((valueArray at:i2) * scaleFactor) rounded.
gV at:vi put:val.
val := ((valueArray at:i3) * scaleFactor) rounded.
bV at:vi put:val.
i2 := i2 + 1.
i3 := i3 + 1.
].
colorMap := MappedPalette redVector:rV greenVector:gV blueVector:bV.
Verbose == true ifTrue:[
Logger info:' colormap: ...'
].
^ self
].
(tagType == 321) ifTrue:[
"/ halftonehints
metaData at:#HalftoneHints put:value.
^ self
].
(tagType == 322) ifTrue:[
"/ 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 (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
tileOffsets := valueArray.
Verbose == true ifTrue:[
Logger info:' tileOffsets: %1' with:valueArray
].
^ self
].
(tagType == 325) ifTrue:[
"/ tilebytecounts
tileByteCounts := valueArray.
Verbose == true ifTrue:[
Logger info:' tileByteCounts: %1' with:valueArray
].
^ self
].
(tagType == 326) ifTrue:[
"/ badFaxLines
Verbose == true ifTrue:[
Logger info:' badFaxLines: %1' with:valueArray
].
^ self
].
(tagType == 327) ifTrue:[
"CleanFaxData"
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
Verbose == true ifTrue:[
Logger info:' consecutiveBadFaxLines: %1' with:valueArray
].
^ self
].
(tagType == 330) ifTrue:[
"/ subifd
Verbose == true ifTrue:[
Logger info:' subifd: %1' with:valueArray
].
subIfds := valueArray.
^ self
].
(tagType == 332) ifTrue:[
"/ 'ink set' print. value printNewline.
^ self
].
(tagType == 333) ifTrue:[
"/ 'ink names' print. value printNewline.
metaData at:#IncNames put:value.
^ self
].
(tagType == 334) ifTrue:[
"/ 'numinks' print. value printNewline.
^ self
].
(tagType == 336) ifTrue:[
"/ 'dot range' print. value printNewline.
^ self
].
(tagType == 337) ifTrue:[
"/ 'target printer' print. value printNewline.
^ self
].
(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:[
"/ 'transfer range' print. value printNewline.
^ self
].
(tagType == 343) ifTrue:[
"/ 'clip path' print. value printNewline.
^ self
].
(tagType == 344) ifTrue:[
"/ 'xclip path units' print. value printNewline.
^ self
].
(tagType == 345) ifTrue:[
"/ '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:[
(tagType == 400) ifTrue:[
"/ 'GlobalParametersIFD' print. value printNewline.
^ self
].
(tagType == 401) ifTrue:[
"/ 'ProfileType' print. value printNewline.
^ self
].
(tagType == 402) ifTrue:[
"/ 'FaxProfile' print. value printNewline.
^ self
].
(tagType == 403) ifTrue:[
"/ 'CodingMethods' print. value printNewline.
^ self
].
(tagType == 404) ifTrue:[
"/ 'VersionYear' print. value printNewline.
^ self
].
(tagType == 405) ifTrue:[
"/ 'ModeNumber' print. value printNewline.
^ self
].
(tagType == 433) ifTrue:[
"/ 'Decode' print. value printNewline.
^ self
].
(tagType == 434) ifTrue:[
"/ 'DefaultImageColor' print. value printNewline.
^ self
].
].
(tagType between:500 and:599) ifTrue:[
"/ obsolete JPEG tags
(tagType == 512) ifTrue:[
"/ 'jpeg proc' print. value printNewline.
^ self
].
(tagType == 513) ifTrue:[
"/ 'jpeg proc' print. value printNewline.
^ self
].
(tagType == 514) ifTrue:[
"/ 'jpeg ifByteCount' print. value printNewline.
^ self
].
(tagType == 515) ifTrue:[
"/ 'jpeg restartInterval' print. value printNewline.
^ self
].
(tagType == 517) ifTrue:[
"/ 'jpeg glossLessPredictors' print. value printNewline.
^ self
].
(tagType == 518) ifTrue:[
"/ 'jpeg pointTransform' print. value printNewline.
^ self
].
(tagType == 519) ifTrue:[
"/ 'jpeg qTables' print. value printNewline.
^ self
].
(tagType == 520) ifTrue:[
"/ 'jpeg dcTables' print. value printNewline.
^ self
].
(tagType == 521) ifTrue:[
"/ 'jpeg acTables' print. value printNewline.
^ self
].
(tagType == 529) ifTrue:[
"/ ycbr coeff
Verbose == true ifTrue:[
Logger info:' ycbr coeff: %1' with:value
].
^ self
].
(tagType == 530) ifTrue:[
"/ ycbr subsampling
Verbose == true ifTrue:[
Logger info:' ycbr subsampling: %1' with:value
].
^ self
].
(tagType == 531) ifTrue:[
"/ ycbr positioning
Verbose == true ifTrue:[
Logger info:' ycbr positioning: %1' with:value
].
^ self
].
(tagType == 532) ifTrue:[
"/ referenceBlackWhite
Verbose == true ifTrue:[
Logger info:' referenceBlackWhite: %1' with:value
].
^ self
].
(tagType == 559) ifTrue:[
"/ 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:[
"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
"/ value of 700, as shown in Table 1.1, "TIFF IFD Directory Entry for
"/ XML Packets
Verbose == true ifTrue:[
Logger info:' XMLPACKET: %1' with:value asString
].
decodeMetaTags == true ifTrue:[
metaData at:#xmpData put:value asString.
].
^ self
].
].
(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.
^ self
].
(tagType == 32932) ifTrue:[
"/'wang annotation' print. value printNewline.
^ self
].
"/ Private Island graphics tags
(tagType == 32953) ifTrue:[
"/'ref points' print. value printNewline.
^ self
].
(tagType == 32954) ifTrue:[
"/ 'regionTagPoint' print. value printNewline.
^ self
].
(tagType == 32955) ifTrue:[
"/ 'regionWarpCorners' print. value printNewline.
^ self
].
(tagType == 32956) ifTrue:[
"/ 'regionAffine' print. value printNewline.
^ self
].
"/ Private SGI tags
(tagType == 32995) ifTrue:[
"/ 'matteing' print. value printNewline.
^ self
].
(tagType == 32996) ifTrue:[
"/ datatype
Verbose == true ifTrue:[
Logger info:' datatype: %1' with:value
].
^ self
].
(tagType == 32997) ifTrue:[
"/ imagedepth
Verbose == true ifTrue:[
Logger info:' imagedepth: %1' with:value
].
^ self
].
(tagType == 32998) ifTrue:[
"/ tiledepth
Verbose == true ifTrue:[
Logger info:' tiledepth: %1' with:value
].
^ self
].
].
(tagType between:33000 and:33999) ifTrue:[
"/ Private Pixar tags
(tagType == 33300) ifTrue:[
"/ 'image full width' print. value printNewline.
^ self
].
(tagType == 33301) ifTrue:[
"/ 'image full length' print. value printNewline.
^ self
].
"/ Private Eastman Kodak tags
(tagType == 33405) ifTrue:[
"/ 'write serial number' print. value printNewline.
^ self
].
(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
].
(tagType == 33550) ifTrue:[
"/ 'geotiff modelpixelscaletag' print. value printNewline.
^ self
].
(tagType == 33723) ifTrue:[
"/ '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:[
(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
].
"/ Private Pixel magic
(tagType == 34232) ifTrue:[
"/ 'jbig options' print. value printNewline.
^ self
].
(tagType == 34264) ifTrue:[
"/ 'geotiff ModelTransformationTag' print. value printNewline.
^ self
].
"/ private Photoshop
(tagType == 34377) ifTrue:[
"/ RICHTIFFIPTC
"/ IPTC (International Press Telecommunications Council) metadata.
"/ (see http://www.iptc.org/std/photometadata/specification/IPTC-PhotoMetadata)
decodeMetaTags == true ifTrue:[
Verbose == true ifTrue:[
Logger info:' RICHTIFFIPTC: %1' with:value
].
self decodePhotoshopImageResourceBlock:value.
] ifFalse:[
Verbose == true ifTrue:[
Logger info:' skipped decoding of IPTC-PhotoMetadata'
].
].
^ self
].
(tagType == 34665) ifTrue:[
"/ EXIFIFD
Verbose == true ifTrue:[
Logger info:' EXIFIFD: %1' with:value
].
^ self
].
(tagType == 34675) ifTrue:[
"/ 'ICCPROFILE' print. value printNewline.
^ self
].
(tagType == 34732) ifTrue:[
"/ '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
"/ ].
^ self
].
"/ More Private SGI
(tagType == 34908) ifTrue:[
"/ 'fax recv params' print. value printNewline.
^ self
].
(tagType == 34909) ifTrue:[
"/ 'fax subaddress' print. value printNewline.
^ self
].
(tagType == 34910) ifTrue:[
"/ 'fax recv time' print. value printNewline.
^ self
].
].
(tagType between:36000 and:36999) ifTrue:[
(tagType == 36867) ifTrue:[
"/ '???' print. value printNewline.
^ self
].
].
(tagType between:37000 and:37999) ifTrue:[
(tagType == 37390) ifTrue:[
"/ '???' print. value printNewline.
^ self
].
(tagType == 37391) ifTrue:[
"/ '???' print. value printNewline.
^ self
].
(tagType == 37392) ifTrue:[
"/ '???' print. value printNewline.
^ self
].
(tagType == 37398) ifTrue:[
"/ '???' print. value printNewline.
^ self
].
].
(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
].
].
"/ dng tags (see http://wwwimages.adobe.com/content/dam/Adobe/en/products/photoshop/pdfs/dng_spec_1.4.0.0.pdf)
(tagType between:50000 and:50999) ifTrue:[
(tagType == 50706) ifTrue:[
"/ DNGVersion
Verbose == true ifTrue:[
Logger info:' DNGVersion: %1' with:value
].
isDNGImage := true.
^ self
].
(tagType == 50707) ifTrue:[
"/ DNGBackwardVersion
^ self
].
(tagType == 50708) ifTrue:[
"/ UniqueCameraModel
Verbose == true ifTrue:[
Logger info:' UniqueCameraModel: %1' with:value
].
^ self
].
(tagType == 50709) ifTrue:[
"/ LocalizedCameraModel
Verbose == true ifTrue:[
Logger info:' LocalizedCameraModel: %1' with:value
].
^ self
].
(tagType == 50710) ifTrue:[
"/ 'CFAPlaneColor' print. value printNewline.
^ self
].
(tagType == 50711) ifTrue:[
"/ 'CFALayout' print. value printNewline.
^ self
].
(tagType == 50712) ifTrue:[
"/ 'LinearizationTable' print. value printNewline.
^ self
].
(tagType == 50713) ifTrue:[
"/ 'BlackLevelRepeatDim' print. value printNewline.
^ self
].
(tagType == 50714) ifTrue:[
"/ 'BlackLevel' print. value printNewline.
^ self
].
(tagType == 50715) ifTrue:[
"/ 'BlackLevelDeltaH' print. value printNewline.
^ self
].
(tagType == 50716) ifTrue:[
"/ 'BlackLevelDeltaV' print. value printNewline.
^ self
].
(tagType == 50717) ifTrue:[
"/ 'WhiteLevel' print. value printNewline.
^ self
].
(tagType == 50718) ifTrue:[
"/ 'DefaultScale' print. value printNewline.
^ self
].
(tagType == 50719) ifTrue:[
"/ 'DefaultCropOrigin' print. value printNewline.
^ self
].
(tagType == 50720) ifTrue:[
"/ 'DefaultCropSize' print. value printNewline.
^ self
].
(tagType == 50721) ifTrue:[
"/ 'ColorMatrix1' print. value printNewline.
^ self
].
(tagType == 50722) ifTrue:[
"/ 'ColorMatrix2' print. value printNewline.
^ self
].
(tagType == 50723) ifTrue:[
"/ 'CameraCalibrarion1' print. value printNewline.
^ self
].
(tagType == 50724) ifTrue:[
"/ 'CameraCalibrarion2' print. value printNewline.
^ self
].
(tagType == 50725) ifTrue:[
"/ 'ReductionMatrix1' print. value printNewline.
^ self
].
(tagType == 50726) ifTrue:[
"/ 'ReductionMatrix2' print. value printNewline.
^ self
].
(tagType == 50727) ifTrue:[
"/ 'AnalogBalance' print. value printNewline.
^ self
].
(tagType == 50728) ifTrue:[
"/ 'AsShotNeutral' print. value printNewline.
^ self
].
(tagType == 50729) ifTrue:[
"/ 'AsShotWhiteXY' print. value printNewline.
^ self
].
(tagType == 50730) ifTrue:[
"/ 'BaselineExposure' print. value printNewline.
^ self
].
(tagType == 50731) ifTrue:[
"/ 'BaselineNoise' print. value printNewline.
^ self
].
(tagType == 50732) ifTrue:[
"/ 'BaselineSharpness' print. value printNewline.
^ self
].
(tagType == 50733) ifTrue:[
"/ 'ByerGreenSplit' print. value printNewline.
^ self
].
(tagType == 50734) ifTrue:[
"/ 'LinearResponseLimit' print. value printNewline.
^ self
].
(tagType == 50735) ifTrue:[
"/ 'CameraSerialNumber' print. value printNewline.
Verbose == true ifTrue:[
Logger info:' CameraSerialNumber: %1' with:value
].
^ self
].
(tagType == 50736) ifTrue:[
"/ 'LensInfo' print. value printNewline.
^ self
].
(tagType == 50737) ifTrue:[
"/ 'ChromaBlurRadius' print. value printNewline.
^ self
].
(tagType == 50738) ifTrue:[
"/ 'AntiAliasStrength' print. value printNewline.
^ self
].
(tagType == 50739) ifTrue:[
"/ 'ShadowScale' print. value printNewline.
^ self
].
(tagType == 50740) ifTrue:[
"/ 'DNGPrivateData' print. value printNewline.
^ self
].
(tagType == 50741) ifTrue:[
"/ 'MakerNoteSafety' print. value printNewline.
^ self
].
(tagType == 50778) ifTrue:[
"/ 'CalibrationIlluminant1' print. value printNewline.
^ self
].
(tagType == 50779) ifTrue:[
"/ 'CalibrationIlluminant2' print. value printNewline.
^ self
].
(tagType == 50780) ifTrue:[
"/ 'BestQualityScale' print. value printNewline.
^ self
].
(tagType == 50781) ifTrue:[
"/ 'RawDataUniqueID' print. value printNewline.
^ self
].
(tagType == 50827) ifTrue:[
"/ 'OriginalRawFileName' print. value printNewline.
^ self
].
].
"/
"/ 'TIFFReader: tag:' print. tagType print. ' typ:' print. numberType print.
"/ ' len:' print. length print. ' offs:' print. offset print.
"/ ' val:' print. value print. ' valArr:' print. valueArray printNewline.
"/
'TIFFReader [warning]: unknown tag type ' errorPrint. tagType errorPrintCR
"Modified (format): / 23-05-2017 / 16:12:58 / mawalch"
"Modified: / 28-08-2017 / 00:48:37 / cg"
!
positionToStrip:stripNr
inStream position:(stripOffsets at:stripNr).
!
positionToTile:tileNr
inStream position:((metaData at:#'TileOffsets') at:tileNr).
"Created: / 25-08-2017 / 13:43:30 / cg"
!
readBytes:n signed:isSigned
"read n 8bit signed or unsigned integers and return them in an array or byteArray"
|oldPos offset bytes nInline|
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:[
1 to:n do:[:i | bytes at:i put:(inStream nextSignedByte) ].
] ifFalse:[
inStream nextBytes:n into:bytes.
].
(n < nInline) ifTrue:[
inStream skip:(nInline - n).
]
] ifFalse:[
offset := inStream nextInt32MSB:(byteOrder ~~ #lsb).
oldPos := inStream position.
inStream position:offset.
isSigned ifTrue:[
1 to:n do:[:i | bytes at:i put:(inStream nextSignedByte) ].
] ifFalse:[
inStream nextBytes:n into:bytes.
].
inStream position:oldPos
].
^ bytes
"Modified: / 27-08-2017 / 19:56:23 / cg"
!
readChars:n
"read n characters and return them in a string"
|oldPos offset string nInline|
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 == #msb).
oldPos := inStream position.
inStream position:offset.
inStream nextBytes:(n - 1) into:string.
inStream position:oldPos
].
^ string
"Modified: / 27-08-2017 / 19:55:15 / cg"
!
readDoubles:nFloats
"read nFloats IEEE 64bit doubles and return them in an array"
|oldPos offset values val msb
n "{ Class: SmallInteger }" |
n := nFloats.
msb := byteOrder ~~ #lsb.
values := DoubleArray basicNew:n.
(n == 1) ifTrue:[
val := Float readBinaryIEEEDoubleFrom:inStream MSB:msb.
values at:1 put:val.
] ifFalse:[
offset := inStream nextInt32MSB:msb.
oldPos := inStream position.
inStream position:offset.
1 to:n do:[:index |
val := Float readBinaryIEEEDoubleFrom:inStream MSB:msb.
values at:index put:val
].
inStream position:oldPos
].
^ values
"Modified: / 24-08-2017 / 23:28:22 / cg"
!
readFloats:nFloats
"read nFloats IEEE 32bit floats and return them in an array"
|oldPos offset values val val1 val2 msb
n "{ Class: SmallInteger }" |
n := nFloats.
msb := byteOrder ~~ #lsb.
values := FloatArray basicNew:n.
(isBigTiff and:[ n == 2 ]) ifTrue:[
val1 := ShortFloat readBinaryIEEESingleFrom:inStream MSB:msb.
val2 := ShortFloat readBinaryIEEESingleFrom:inStream MSB:msb.
values at:1 put:val1.
n == 2 ifTrue:[
values at:2 put:val2.
].
] ifFalse:[
(n == 1) ifTrue:[
val := ShortFloat readBinaryIEEESingleFrom:inStream MSB:msb.
values at:1 put:val.
] ifFalse:[
offset := inStream nextInt32MSB:msb.
oldPos := inStream position.
inStream position:offset.
1 to:n do:[:index |
val := ShortFloat readBinaryIEEESingleFrom:inStream MSB:msb.
values at:index put:val
].
inStream position:oldPos
].
].
^ values
"Modified: / 24-08-2017 / 23:36:39 / cg"
!
readFracts:nFracts signed:isSigned
"read nFracts fractions (2 32bit words) and return them in an array"
|oldPos offset values numerator denominator msb
n "{ Class: SmallInteger }" |
n := nFracts.
msb := byteOrder ~~ #lsb.
values := Array basicNew:n.
offset := inStream nextInt32MSB:msb.
oldPos := inStream position.
inStream position:offset.
1 to:n do:[:index |
numerator := isSigned ifTrue:[inStream nextInt32MSB:msb] ifFalse:[inStream nextUnsignedInt32MSB:msb].
denominator := isSigned ifTrue:[inStream nextInt32MSB:msb] ifFalse:[inStream nextUnsignedInt32MSB:msb].
values at:index put:(Fraction numerator:numerator denominator:denominator)
].
inStream position:oldPos.
^ values
!
readLong8s:nLongs signed:isSigned
"read nLongs signed or unsigned long8 numbers (64bit) and return them in an array"
|oldPos offset values val msb
n "{ Class: SmallInteger }" |
n := nLongs.
msb := byteOrder ~~ #lsb.
values := Array basicNew:n.
(n == 1) ifTrue:[
val := isSigned ifTrue:[inStream nextInt64MSB:msb] ifFalse:[inStream nextUnsignedInt64MSB:msb].
values at:1 put:val.
] ifFalse:[
offset := inStream nextInt64MSB:msb.
oldPos := inStream position.
inStream position:offset.
1 to:n do:[:index |
val := isSigned ifTrue:[inStream nextInt64MSB:msb] ifFalse:[inStream nextUnsignedInt64MSB:msb].
values at:index put:val
].
inStream position:oldPos
].
^ values
"Created: / 24-08-2017 / 22:01:26 / cg"
!
readLongs:nLongs signed:isSigned
"read nLongs signed or unsigned long numbers (32bit) and return them in an array"
|oldPos offset values val val1 val2 msb
n "{ Class: SmallInteger }" |
n := nLongs.
msb := byteOrder ~~ #lsb.
values := Array basicNew:n.
(isBigTiff and:[ n <= 2 ]) ifTrue:[
val1 := isSigned ifTrue:[inStream nextInt32MSB:msb] ifFalse:[inStream nextUnsignedInt32MSB:msb].
val2 := isSigned ifTrue:[inStream nextInt32MSB:msb] ifFalse:[inStream nextUnsignedInt32MSB:msb].
values at:1 put:val1.
n == 2 ifTrue:[
values at:2 put:val2.
].
] ifFalse:[
(n == 1) ifTrue:[
val := isSigned ifTrue:[inStream nextInt32MSB:msb] ifFalse:[inStream nextUnsignedInt32MSB:msb].
values at:1 put:val.
] ifFalse:[
offset := inStream nextInt32MSB:msb.
oldPos := inStream position.
inStream position:offset.
1 to:n do:[:index |
val := isSigned ifTrue:[inStream nextInt32MSB:msb] ifFalse:[inStream nextUnsignedInt32MSB:msb].
values at:index put:val
].
inStream position:oldPos
].
].
^ values
"Modified: / 24-08-2017 / 23:35:38 / cg"
!
readShorts:nShorts signed:isSigned
"read nShorts signed or unsigned short numbers (16bit) and return them in an array"
|oldPos offset values msb val1 val2 val3 val4
n "{ Class: SmallInteger }" |
n := nShorts.
msb := (byteOrder ~~ #lsb).
values := Array basicNew:n.
(isBigTiff and:[ (n <= 4) ]) ifTrue:[
isSigned ifTrue:[
val1 := inStream nextInt16MSB:msb.
val2 := inStream nextInt16MSB:msb.
val3 := inStream nextInt16MSB:msb.
val4 := inStream nextInt16MSB:msb.
] ifFalse:[
val1 := inStream nextUnsignedInt16MSB:msb.
val2 := inStream nextUnsignedInt16MSB:msb.
val3 := inStream nextUnsignedInt16MSB:msb.
val4 := inStream nextUnsignedInt16MSB:msb.
].
values at:1 put:val1.
(n >= 2) ifTrue:[
values at:2 put:val2.
(n >= 3) ifTrue:[
values at:3 put:val3.
(n == 4) ifTrue:[
values at:4 put:val4.
]
]
]
] ifFalse:[
(n <= 2) ifTrue:[
isSigned ifTrue:[
val1 := inStream nextInt16MSB:msb.
val2 := inStream nextInt16MSB:msb.
] ifFalse:[
val1 := inStream nextUnsignedInt16MSB:msb.
val2 := inStream nextUnsignedInt16MSB:msb.
].
values at:1 put:val1.
(n == 2) ifTrue:[
values at:2 put:val2
]
] ifFalse:[
offset := inStream nextInt32MSB:msb.
oldPos := inStream position.
inStream position:offset.
1 to:n do:[:index |
isSigned ifTrue:[
val1 := inStream nextInt16MSB:msb.
] ifFalse:[
val1 := inStream nextUnsignedInt16MSB:msb.
].
values at:index put:val1
].
inStream position:oldPos
].
].
^ 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'!
writeBitsPerSample
"
'bitsPerSample: ' print. bitsPerSample printNewline.
'store bitspersample at: ' print. outStream position printNewline.
"
bitsPerSamplePos := outStream position.
bitsPerSample do:[:n |
self writeShort:n
]
!
writeColorMap
|n|
colorMapPos := outStream position.
#(red green blue) do:[:component |
n := 0.
colorMap do:[:clr |
|entry|
clr isNil ifTrue:[
entry := 0
] ifFalse:[
entry := clr perform:component.
"
tiff map is 16 bit - scale from percent to 0..16rFFFF
"
entry := (entry * 16rFFFF / 100) rounded.
].
self writeShort:entry.
n := n + 1
].
"
fill to 256 entries
"
[n < 256] whileTrue:[
self writeShort:0.
n := n + 1.
]
]
"Modified: 20.2.1997 / 18:06:10 / cg"
!
writeStripByteCounts
"
'stripByteCounts: ' print. stripByteCounts printNewline.
'store stripbytecounts at: ' print. outStream position printNewline.
"
stripByteCountsPos := outStream position.
stripByteCounts do:[:c |
self writeShort:c
]
!
writeStripOffsets
"
'stripOffsets: ' print. stripOffsets printNewline.
'store stripoffsets at: ' print. outStream position printNewline.
"
stripOffsetsPos := outStream position.
stripOffsets do:[:o |
self writeLong:o
]
!
writeTag:tagType
self writeTiffTag:tagType.
!
writeTiffTag:tagType
|value valueArray numberType count address|
count := 1.
address := nil.
(tagType == 253) ifTrue:[
"tiff class"
].
(tagType == 254) ifTrue:[
].
(tagType == 255) ifTrue:[
"SubfileType"
value := subFileType.
numberType := #long.
].
(tagType == 256) ifTrue:[
"ImageWidth"
value := width.
numberType := #short.
].
(tagType == 257) ifTrue:[
"ImageHeight"
value := height.
numberType := #short.
].
(tagType == 258) ifTrue:[
"bitspersample"
address := bitsPerSamplePos.
numberType := #short.
count := bitsPerSample size.
valueArray := bitsPerSample
].
(tagType == 259) ifTrue:[
"compression"
value := compression.
numberType := #short.
].
(tagType == 262) ifTrue:[
"photometric"
(photometric == #whiteIs0) ifTrue:[
value := 0
] ifFalse:[
(photometric == #blackIs0) ifTrue:[
value := 1
] ifFalse:[
(photometric == #rgb) ifTrue:[
value := 2
] ifFalse:[
(photometric == #palette) ifTrue:[
value := 3
] ifFalse:[
(photometric == #transparency) ifTrue:[
value := 4
] ifFalse:[
self error:'bad photometric' mayProceed:true.
]
]
]
]
].
numberType := #short.
].
(tagType == 263) ifTrue:[
].
(tagType == 264) ifTrue:[
].
(tagType == 265) ifTrue:[
].
(tagType == 266) ifTrue:[
"fillOrder"
(fillOrder == #msb) ifTrue:[
value := FILLORDER_MSB2LSB
] ifFalse:[
(fillOrder == #lsb) ifTrue:[
value := FILLORDER_LSB2MSB
] ifFalse:[
self error:'bad fillOrder' mayProceed:true
]
].
numberType := #short.
].
(tagType == 269) ifTrue:[
].
(tagType == 270) ifTrue:[
].
(tagType == 271) ifTrue:[
].
(tagType == 272) ifTrue:[
].
(tagType == 273) ifTrue:[
"stripoffsets"
address := stripOffsetsPos.
numberType := #long.
count := stripOffsets size.
valueArray := stripOffsets
].
(tagType == 274) ifTrue:[
].
(tagType == 277) ifTrue:[
"samplesPerPixel"
value := samplesPerPixel.
numberType := #short.
].
(tagType == 278) ifTrue:[
"rowsperstrip"
value := rowsPerStrip.
numberType := #short.
].
(tagType == 279) ifTrue:[
"stripbytecount"
address := stripByteCountsPos.
numberType := #short.
count := stripByteCounts size.
valueArray := stripByteCounts
].
(tagType == 280) ifTrue:[
"min sample value"
].
(tagType == 281) ifTrue:[
"max sample value"
].
(tagType == 282) ifTrue:[
"x resolution"
].
(tagType == 283) ifTrue:[
"y resolution"
].
(tagType == 284) ifTrue:[
"planarconfig"
value := planarConfiguration.
numberType := #short.
].
(tagType == 285) ifTrue:[
"pageName"
].
(tagType == 286) ifTrue:[
"xPosition"
].
(tagType == 287) ifTrue:[
"yPosition"
].
(tagType == 288) ifTrue:[
"freeOffsets"
].
(tagType == 289) ifTrue:[
"freeByteCounts"
].
(tagType == 290) ifTrue:[
"grayResponceUnit"
].
(tagType == 291) ifTrue:[
"grayResponceCurve"
].
(tagType == 292) ifTrue:[
"group3options"
value := group3options.
numberType := #long.
].
(tagType == 293) ifTrue:[
"group4options"
].
(tagType == 296) ifTrue:[
"resolutionunit"
^ self
].
(tagType == 297) ifTrue:[
"pageNumber"
].
(tagType == 300) ifTrue:[
"colorResponceUnit"
].
(tagType == 301) ifTrue:[
"colorResponceCurve"
].
(tagType == 306) ifTrue:[
"dateTime"
].
(tagType == 315) ifTrue:[
"artist"
].
(tagType == 317) ifTrue:[
"predictor"
].
(tagType == 320) ifTrue:[
"colormap"
address := colorMapPos.
numberType := #short.
count := 256 "(colorMap at:1) size" * 3.
].
(value isNil and:[address isNil]) ifTrue:[
self error:'unhandled tag' mayProceed:true.
^ self
].
"
'tag:' print. tagType print. ' typ:' print. numberType print.
' len:' print. count print.
' val:' print. value printNewline.
"
self writeShort:tagType.
numberType == #short ifTrue:[
self writeShort:3.
self writeLong:count.
] ifFalse:[
numberType == #long ifTrue:[
self writeShort:4.
self writeLong:count.
] ifFalse:[
numberType == #byte ifTrue:[
self writeShort:1.
self writeLong:count.
] ifFalse:[
self error:'bad numbertype'
]
]
].
address notNil ifTrue:[
(numberType == #long and:[count == 1]) ifTrue:[
self writeLong:(valueArray at:1).
^ self
].
(numberType == #short and:[count <= 2]) ifTrue:[
self writeShort:(valueArray at:1).
count == 2 ifTrue:[
self writeShort:(valueArray at:2).
] ifFalse:[
self writeShort:0
].
^ self
].
(numberType == #byte and:[count <= 4]) ifTrue:[
outStream nextPut:(valueArray at:1).
count > 1 ifTrue:[
outStream nextPut:(valueArray at:2).
count > 2 ifTrue:[
outStream nextPut:(valueArray at:3).
count > 3 ifTrue:[
outStream nextPut:(valueArray at:4).
] ifFalse:[
outStream nextPut:0
].
] ifFalse:[
outStream nextPut:0
].
] ifFalse:[
outStream nextPut:0
].
^ self
].
self writeLong:address.
^ self
].
numberType == #short ifTrue:[
self writeShort:value.
self writeShort:0
] ifFalse:[
numberType == #long ifTrue:[
self writeLong:value
] ifFalse:[
numberType == #byte ifTrue:[
outStream nextPut:value.
outStream nextPut:0.
outStream nextPut:0.
outStream nextPut:0.
] ifFalse:[
self error:'bad numbertype'
]
]
].
"Modified: / 28-08-2017 / 00:47:52 / cg"
!
writeUncompressedBits
"write bits as one or multiple strips"
|offs bytesPerRow nBytes
h "{ Class: SmallInteger }"|
nBytes := data size.
nBytes < 16rFFFF ifTrue:[
stripOffsets := Array with:(outStream position).
stripByteCounts := Array with:nBytes.
outStream nextPutBytes:nBytes from:data.
rowsPerStrip := height
] ifFalse:[
stripOffsets := Array basicNew:height.
bytesPerRow := nBytes // height.
stripByteCounts := (Array basicNew:height) atAllPut:bytesPerRow.
offs := 1.
h := height.
1 to:h do:[:row |
stripOffsets at:row put:(outStream position).
outStream nextPutBytes:bytesPerRow from:data startingAt:offs.
offs := offs + bytesPerRow
].
rowsPerStrip := 1
].
"
'stripOffsets: ' print. stripOffsets printNewline.
'stripByteCounts: ' print. stripByteCounts printNewline.
"
! !
!TIFFReader methodsFor:'reading'!
fromStream:aStream
"read a stream containing a TIFF image.
Leave image description in instance variables.
(i.e. to get the image, ask with image)."
|char1 char2 version offset msb
bytesPerRow img moreIfds|
inStream := aStream.
aStream binary.
char1 := aStream next.
char2 := aStream next.
"/ first two chars are either II (intel byte order)
"/ or MM (motorola byte orrder)
(char1 ~~ char2) ifTrue:[
^ self fileFormatError:'not a tiff file'.
].
(char1 == $I codePoint) ifTrue:[
byteOrder := #lsb.
msb := false.
] ifFalse:[
(char1 == $M codePoint) ifTrue:[
byteOrder := #msb.
msb := true.
] ifFalse:[
^ self fileFormatError:'not a tiff file'.
]
].
version := aStream nextUnsignedInt16MSB:msb.
(version == 42) ifTrue:[
isBigTiff := false.
] ifFalse:[
(version == 43) ifTrue:[
|byteSizeOfOffsets always0|
"/ 43 is the proposed bigtiff format
isBigTiff := true.
byteSizeOfOffsets := aStream nextUnsignedInt16MSB:msb.
byteSizeOfOffsets == 8 ifFalse:[
^ self fileFormatError:'version of bigtiff-file not supported'.
].
always0 := aStream nextUnsignedInt16MSB:msb.
always0 == 0 ifFalse:[
^ self fileFormatError:'version of bigtiff-file not supported'.
].
] ifFalse:[
^ self fileFormatError:'version of tiff-file not supported'.
].
].
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 := nil.
samplesPerPixel := 1.
width := height := nil.
stripOffsets := stripByteCounts := rowsPerStrip := nil.
"resolutionUnit := 2."
predictor := 1.
group3options := nil.
orientation := nil.
subFileType := subIfds := nil.
sampleFormat := SAMPLEFORMAT_UINT.
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' ].
bitsPerSample isNil ifTrue:[
bitsPerSample := Array new:samplesPerPixel withAll:1.
].
photometric isNil ifTrue:[
"/ try to repair
bitsPerSample sum == 1 ifTrue:[
photometric := #whiteIs0.
] ifFalse:[
^ 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.
].
orientation notNil ifTrue:[
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
].
].
].
imageSequence size > 1 ifTrue:[
Verbose == true ifTrue:[
Logger info:'read %1 images' with:imageSequence size
].
].
^ self
"Modified: / 27-08-2017 / 23:24:37 / cg"
! !
!TIFFReader methodsFor:'writing'!
save:image onStream:aStream
"save image as (uncompressed) TIFF file on aFileName"
|pos1 pos indicator|
image mask notNil ifTrue:[
Image informationLostQuerySignal
raiseWith:image
errorString:('TIFF writer does not (yet) support an imageMask').
].
outStream := aStream.
outStream binary.
"save as msb"
byteOrder := #msb.
"
byteOrder := #lsb.
"
fillOrder := #msb.
width := image width.
height := image height.
photometric := image photometric.
samplesPerPixel := image samplesPerPixel.
bitsPerSample := image bitsPerSample.
colorMap := image colorMap.
planarConfiguration := PLANARCONFIG_CONTIG.
compression := 1. "none"
data := image bits.
currentOffset := 0.
(byteOrder == #msb) ifTrue:[
indicator := $M codePoint.
] ifFalse:[
indicator := $I codePoint.
].
outStream nextPut:indicator; nextPut:indicator.
currentOffset := currentOffset + 2.
self writeShort:42.
currentOffset := currentOffset + 2.
pos1 := outStream position.
self writeLong:0. "start of tags - filled in later"
currentOffset := currentOffset + 4.
"output strips"
self writeUncompressedBits. "this outputs bits as strips, sets stripOffsets and stripByteCounts"
self writeStripOffsets. "this outputs strip offsets, sets stripOffsetsPos"
self writeStripByteCounts. "this outputs strip bytecounts, sets stripByteCountPos"
self writeBitsPerSample. "this outputs bitsPerSample, sets bitsPerSamplePos"
photometric == #palette ifTrue:[
self writeColorMap "this outputs colorMap, sets colorMapPos"
].
pos := outStream position. "backpatch tag offset"
outStream position:pos1.
self writeLong:pos. "fill in tag offset"
outStream position:pos.
"
('patch tag offset at: ', (pos1 printStringRadix:16) , ' to ',
(pos printStringRadix:16)) printNewline.
"
"output tag data"
photometric == #palette ifTrue:[
self writeShort:11. "11 tags"
] ifFalse:[
self writeShort:10. "10 tags"
].
self writeTag:256. "image width"
self writeTag:257. "image height"
self writeTag:258. "bits per sample"
self writeTag:259. "compression"
self writeTag:262. "photometric"
self writeTag:273. "strip offsets"
self writeTag:277. "samplesPerPixel"
self writeTag:278. "rowsPerStrip"
self writeTag:279. "strip byte counts"
self writeTag:284. "planarconfig"
photometric == #palette ifTrue:[
self writeTag:320 "colorMap"
].
self writeLong:0. "end of tags mark"
"Modified: / 27-08-2017 / 13:36:35 / cg"
! !
!TIFFReader class methodsFor:'documentation'!
version
^ '$Header$'
!
version_CVS
^ '$Header$'
! !
TIFFReader initialize!