94 version := inStream nextShortMSB:(char1 == $M). |
94 version := inStream nextShortMSB:(char1 == $M). |
95 inStream close. |
95 inStream close. |
96 |
96 |
97 (version ~~ 42) ifTrue:[^ false]. |
97 (version ~~ 42) ifTrue:[^ false]. |
98 ^ true |
98 ^ true |
99 ! |
|
100 |
|
101 canRepresent:anImage |
|
102 "return true, if anImage can be represented in my file format. |
|
103 Any image is supported." |
|
104 |
|
105 ^ true |
|
106 ! ! |
99 ! ! |
107 |
100 |
108 !TIFFReader methodsFor:'reading from file'! |
|
109 |
|
110 fromStream:aStream |
|
111 "read an image from aStream" |
|
112 |
|
113 |char1 char2 version |
|
114 numberOfTags "{ Class: SmallInteger }" |
|
115 tagType "{ Class: SmallInteger }" |
|
116 numberType "{ Class: SmallInteger }" |
|
117 length "{ Class: SmallInteger }" |
|
118 result offset ok msb| |
|
119 |
|
120 inStream := aStream. |
|
121 |
|
122 char1 := aStream next. |
|
123 char2 := aStream next. |
|
124 (char1 ~~ char2) ifTrue:[ |
|
125 'TIFFReader: not a tiff file' errorPrintNL. |
|
126 ^ nil |
|
127 ]. |
|
128 (char1 == $I) ifTrue:[ |
|
129 byteOrder := #lsb. |
|
130 msb := false. |
|
131 ] ifFalse:[ |
|
132 (char1 == $M) ifTrue:[ |
|
133 byteOrder := #msb. |
|
134 msb := true. |
|
135 ] ifFalse:[ |
|
136 'TIFFReader: not a tiff file' errorPrintNL. |
|
137 ^ nil |
|
138 ] |
|
139 ]. |
|
140 |
|
141 aStream binary. |
|
142 |
|
143 version := self readShort. |
|
144 (version ~~ 42) ifTrue:[ |
|
145 'TIFFReader: version of tiff-file not supported' errorPrintNL. |
|
146 ^ nil |
|
147 ]. |
|
148 |
|
149 "setup default values" |
|
150 |
|
151 compression := 1. "none" |
|
152 fillOrder := #msb. |
|
153 planarConfiguration := 1. |
|
154 photometric := nil. |
|
155 bitsPerSample := 1. |
|
156 samplesPerPixel := 1. |
|
157 width := nil. |
|
158 height := nil. |
|
159 stripOffsets := nil. |
|
160 rowsPerStrip := nil. |
|
161 "resolutionUnit := 2." |
|
162 predictor := 1. |
|
163 |
|
164 offset := aStream nextLongMSB:msb. |
|
165 aStream position:offset + 1. |
|
166 |
|
167 numberOfTags := self readShort. |
|
168 1 to:numberOfTags do:[:index | |
|
169 tagType := self readShort. |
|
170 numberType := self readShort. |
|
171 length := aStream nextLongMSB:msb. |
|
172 self decodeTiffTag:tagType numberType:numberType length:length |
|
173 ]. |
|
174 |
|
175 offset := aStream nextLongMSB:msb. |
|
176 (offset ~~ 0) ifTrue:[ |
|
177 'TIFFReader: more tags ignored' errorPrintNL |
|
178 ]. |
|
179 |
|
180 "check for required tags" |
|
181 ok := true. |
|
182 width isNil ifTrue:[ |
|
183 'TIFFReader: missing width tag' errorPrintNL. |
|
184 ok := false |
|
185 ]. |
|
186 |
|
187 height isNil ifTrue:[ |
|
188 'TIFFReader: missing length tag' errorPrintNL. |
|
189 ok := false |
|
190 ]. |
|
191 |
|
192 photometric isNil ifTrue:[ |
|
193 'TIFFReader: missing photometric tag' errorPrintNL. |
|
194 ok := false |
|
195 ]. |
|
196 |
|
197 stripOffsets isNil ifTrue:[ |
|
198 'TIFFReader: missing stripOffsets tag' errorPrintNL. |
|
199 ok := false |
|
200 ]. |
|
201 |
|
202 stripByteCounts isNil ifTrue:[ |
|
203 stripOffsets size == 1 ifTrue:[ |
|
204 stripByteCounts := Array with:(self bitsPerPixel // 8) * width * height |
|
205 ] |
|
206 ]. |
|
207 |
|
208 stripByteCounts isNil ifTrue:[ |
|
209 'TIFFReader: missing stripByteCounts tag' errorPrintNL. |
|
210 ok := false |
|
211 ]. |
|
212 |
|
213 ok ifFalse:[ |
|
214 ^ nil |
|
215 ]. |
|
216 |
|
217 "given all the information, read the bits" |
|
218 |
|
219 rowsPerStrip isNil ifTrue:[ |
|
220 rowsPerStrip := height |
|
221 ]. |
|
222 |
|
223 ok := false. |
|
224 (compression == 1) ifTrue:[ |
|
225 result := self readUncompressedTiffImageData. |
|
226 ok := true |
|
227 ]. |
|
228 (compression == 2) ifTrue:[ |
|
229 result := self readCCITT3RLETiffImageData. |
|
230 ok := true |
|
231 ]. |
|
232 (compression == 3) ifTrue:[ |
|
233 result := self readCCITTGroup3TiffImageData. |
|
234 ok := true |
|
235 ]. |
|
236 (compression == 4) ifTrue:[ |
|
237 result := self readCCITTGroup4TiffImageData. |
|
238 ok := true |
|
239 ]. |
|
240 (compression == 5) ifTrue:[ |
|
241 result := self readLZWTiffImageData. |
|
242 ok := true |
|
243 ]. |
|
244 (compression == 6) ifTrue:[ |
|
245 result := self readJPEGTiffImageData. |
|
246 ok := true |
|
247 ]. |
|
248 (compression == 32766) ifTrue:[ |
|
249 result := self readNeXTRLE2TiffImageData. |
|
250 ok := true |
|
251 ]. |
|
252 (compression == 32771) ifTrue:[ |
|
253 result := self readCCITTRLEWTiffImageData. |
|
254 ok := true |
|
255 ]. |
|
256 (compression == 32773) ifTrue:[ |
|
257 result := self readPackbitsTiffImageData. |
|
258 ok := true |
|
259 ]. |
|
260 (compression == 32865) ifTrue:[ |
|
261 result := self readNeXTJPEGTiffImageData. |
|
262 ok := true |
|
263 ]. |
|
264 ok ifFalse:[ |
|
265 'TIFFReader: compression type ' errorPrint. compression errorPrint. |
|
266 ' not known' errorPrintNL |
|
267 ]. |
|
268 ^ result |
|
269 ! ! |
|
270 |
|
271 !TIFFReader methodsFor:'writing to file'! |
|
272 |
|
273 save:image onFile:aFileName |
|
274 "save image as (uncompressed) TIFF file on aFileName" |
|
275 |
|
276 |pos1 pos| |
|
277 |
|
278 outStream := FileStream newFileNamed:aFileName. |
|
279 outStream isNil ifTrue:[ |
|
280 'TIFFReader: create error' errorPrintNL. |
|
281 ^ nil |
|
282 ]. |
|
283 |
|
284 "save as msb" |
|
285 |
|
286 byteOrder := #msb. |
|
287 " |
|
288 byteOrder := #lsb. |
|
289 " |
|
290 fillOrder := #msb. |
|
291 width := image width. |
|
292 height := image height. |
|
293 photometric := image photometric. |
|
294 samplesPerPixel := image samplesPerPixel. |
|
295 bitsPerSample := image bitsPerSample. |
|
296 colorMap := image colorMap. |
|
297 planarConfiguration := 1. |
|
298 compression := 1. "none" |
|
299 data := image bits. |
|
300 |
|
301 currentOffset := 0. |
|
302 |
|
303 (byteOrder == #msb) ifTrue:[ |
|
304 outStream nextPut:$M. |
|
305 outStream nextPut:$M. |
|
306 ] ifFalse:[ |
|
307 outStream nextPut:$I. |
|
308 outStream nextPut:$I. |
|
309 ]. |
|
310 currentOffset := currentOffset + 2. |
|
311 |
|
312 outStream binary. |
|
313 |
|
314 self writeShort:42. |
|
315 currentOffset := currentOffset + 2. |
|
316 |
|
317 pos1 := outStream position. |
|
318 self writeLong:0. "start of tags - filled in later" |
|
319 currentOffset := currentOffset + 4. |
|
320 |
|
321 "output strips" |
|
322 |
|
323 self writeUncompressedBits. "this outputs bits as strips, sets stripOffsets and stripByteCounts" |
|
324 self writeStripOffsets. "this outputs strip offsets, sets stripOffsetsPos" |
|
325 self writeStripByteCounts. "this outputs strip bytecounts, sets stripByteCountPos" |
|
326 self writeBitsPerSample. "this outputs bitsPerSample, sets bitsPerSamplePos" |
|
327 photometric == #palette ifTrue:[ |
|
328 self writeColorMap "this outputs colorMap, sets colorMapPos" |
|
329 ]. |
|
330 |
|
331 pos := outStream position. "backpatch tag offset" |
|
332 outStream position:pos1. |
|
333 self writeLong:(pos - 1). "fill in tag offset" |
|
334 outStream position:pos. |
|
335 " |
|
336 ('patch tag offset at: ', (pos1 printStringRadix:16) , ' to ', |
|
337 (pos printStringRadix:16)) printNewline. |
|
338 " |
|
339 "output tag data" |
|
340 |
|
341 photometric == #palette ifTrue:[ |
|
342 self writeShort:10. "10 tags" |
|
343 ] ifFalse:[ |
|
344 self writeShort:9. "9 tags" |
|
345 ]. |
|
346 self writeTag:256. "image width" |
|
347 self writeTag:257. "image height" |
|
348 self writeTag:258. "bits per sample" |
|
349 self writeTag:259. "compression" |
|
350 self writeTag:262. "photometric" |
|
351 self writeTag:273. "strip offsets" |
|
352 self writeTag:278. "rowsPerStrip" |
|
353 self writeTag:279. "strip byte counts" |
|
354 self writeTag:284. "planarconfig" |
|
355 photometric == #palette ifTrue:[ |
|
356 self writeTag:320 "colorMap" |
|
357 ]. |
|
358 self writeLong:0. "end of tags mark" |
|
359 outStream close |
|
360 ! ! |
|
361 |
|
362 !TIFFReader methodsFor:'private'! |
101 !TIFFReader methodsFor:'private'! |
363 |
|
364 readLongs:nLongs |
|
365 "read nLongs long numbers (32bit) and return them in an array" |
|
366 |
|
367 |oldPos offset values msb |
|
368 n "{ Class: SmallInteger }" | |
|
369 |
|
370 n := nLongs. |
|
371 |
|
372 msb := byteOrder ~~ #lsb. |
|
373 values := Array basicNew:n. |
|
374 (n == 1) ifTrue:[ |
|
375 values at:1 put:(inStream nextLongMSB:msb). |
|
376 ] ifFalse:[ |
|
377 offset := inStream nextLongMSB:msb. |
|
378 oldPos := inStream position. |
|
379 inStream position:(offset + 1). |
|
380 1 to:n do:[:index | |
|
381 values at:index put:(inStream nextLongMSB:msb) |
|
382 ]. |
|
383 inStream position:oldPos |
|
384 ]. |
|
385 ^ values |
|
386 ! |
|
387 |
|
388 readShorts:nShorts |
|
389 "read nShorts short numbers (16bit) and return them in an array" |
|
390 |
|
391 |oldPos offset values msb val2 |
|
392 n "{ Class: SmallInteger }" | |
|
393 |
|
394 n := nShorts. |
|
395 |
|
396 msb := (byteOrder ~~ #lsb). |
|
397 values := Array basicNew:n. |
|
398 (n <= 2) ifTrue:[ |
|
399 values at:1 put:(inStream nextUnsignedShortMSB:msb). |
|
400 val2 := inStream nextUnsignedShortMSB:msb. |
|
401 |
|
402 (n == 2) ifTrue:[ |
|
403 values at:2 put:val2 |
|
404 ] |
|
405 ] ifFalse:[ |
|
406 offset := inStream nextLongMSB:msb. |
|
407 oldPos := inStream position. |
|
408 inStream position:(offset + 1). |
|
409 1 to:n do:[:index | |
|
410 values at:index put:(inStream nextUnsignedShortMSB:msb) |
|
411 ]. |
|
412 inStream position:oldPos |
|
413 ]. |
|
414 ^ values |
|
415 ! |
|
416 |
|
417 readChars:n |
|
418 "read n characters and return them in a string" |
|
419 |
|
420 |oldPos offset string| |
|
421 |
|
422 string := String new:(n - 1). |
|
423 (n <= 4) ifTrue:[ |
|
424 inStream nextBytes:(n - 1) into:string |
|
425 ] ifFalse:[ |
|
426 offset := inStream nextLongMSB:(byteOrder ~~ #lsb). |
|
427 oldPos := inStream position. |
|
428 inStream position:(offset + 1). |
|
429 inStream nextBytes:(n - 1) into:string. |
|
430 inStream position:oldPos |
|
431 ]. |
|
432 ^ string |
|
433 ! |
|
434 |
|
435 readFracts:nFracts |
|
436 "read nFracts fractions (2 32bit words) and return them in an array" |
|
437 |
|
438 |oldPos offset values numerator denominator msb |
|
439 n "{ Class: SmallInteger }" | |
|
440 |
|
441 n := nFracts. |
|
442 |
|
443 msb := byteOrder ~~ #lsb. |
|
444 values := Array basicNew:n. |
|
445 offset := inStream nextLongMSB:msb. |
|
446 oldPos := inStream position. |
|
447 inStream position:(offset + 1). |
|
448 1 to:n do:[:index | |
|
449 numerator := inStream nextLongMSB:msb. |
|
450 denominator := inStream nextLongMSB:msb. |
|
451 values at:index put:(Fraction numerator:numerator denominator:denominator) |
|
452 ]. |
|
453 inStream position:oldPos. |
|
454 ^ values |
|
455 ! |
|
456 |
102 |
457 decodeTiffTag:tagType numberType:numberType length:length |
103 decodeTiffTag:tagType numberType:numberType length:length |
458 |offset value valueArray |
104 |offset value valueArray |
459 val scaleFactor rV gV bV |
105 val scaleFactor rV gV bV |
460 n "{ Class: SmallInteger }" |
106 n "{ Class: SmallInteger }" |
1016 ' val:' print. value print. ' valArr:' print. valueArray printNewline. |
662 ' val:' print. value print. ' valArr:' print. valueArray printNewline. |
1017 " |
663 " |
1018 'TIFFReader: unknown tag type ' errorPrint. tagType errorPrintNL |
664 'TIFFReader: unknown tag type ' errorPrint. tagType errorPrintNL |
1019 ! |
665 ! |
1020 |
666 |
1021 writeUncompressedBits |
667 readCCITT3RLETiffImageData |
1022 "write bits as one or multiple strips" |
668 'TIFFReader: ccitt mod Huffman (rle) compression not implemented' errorPrintNL. |
1023 |
669 ! |
1024 |offs bytesPerRow nBytes |
670 |
1025 h "{ Class: SmallInteger }"| |
671 readCCITT3RLEWTiffImageData |
1026 |
672 'TIFFReader: ccitt mod Huffman (rlew) compression not implemented' errorPrintNL. |
1027 nBytes := data size. |
673 ! |
1028 nBytes < 16rFFFF ifTrue:[ |
674 |
1029 stripOffsets := Array with:(outStream position - 1). |
675 readCCITTGroup3TiffImageData |
1030 stripByteCounts := Array with:nBytes. |
676 "not really tested - all I got is a single |
1031 outStream nextPutBytes:nBytes from:data. |
677 fax from NeXT step" |
1032 rowsPerStrip := height |
678 |
|
679 |bytesPerRow bitsPerRow compressedStrip nPlanes |
|
680 stripNr "{ Class: SmallInteger }" |
|
681 offset "{ Class: SmallInteger }" |
|
682 row "{ Class: SmallInteger }" |
|
683 bytesPerStrip "{ Class: SmallInteger }" | |
|
684 |
|
685 nPlanes := samplesPerPixel. |
|
686 (nPlanes == 2) ifTrue:[ |
|
687 'TIFFReader: ignoring alpha plane' errorPrintNL. |
|
688 nPlanes := 1 |
|
689 ]. |
|
690 |
|
691 (nPlanes ~~ 1) ifTrue:[ |
|
692 self error:'only monochrome/greyscale supported'. |
|
693 ^ nil |
|
694 ]. |
|
695 |
|
696 stripByteCounts isNil ifTrue:[ |
|
697 self error:'currently require stripByteCounts'. |
|
698 ^ nil |
|
699 ]. |
|
700 (rowsPerStrip ~~ 1) isNil ifTrue:[ |
|
701 self error:'currently require rowsPerStrip to be 1'. |
|
702 ^ nil |
|
703 ]. |
|
704 |
|
705 'TIFFReader: decompressing CCITT-3 ...' infoPrintNL. |
|
706 |
|
707 bitsPerRow := width * (bitsPerSample at:1). |
|
708 bytesPerRow := bitsPerRow // 8. |
|
709 ((bitsPerRow \\ 8) ~~ 0) ifTrue:[ |
|
710 bytesPerRow := bytesPerRow + 1 |
|
711 ]. |
|
712 |
|
713 data := ByteArray new:(bytesPerRow * height). |
|
714 compressedStrip := ByteArray uninitializedNew:bytesPerRow. |
|
715 |
|
716 offset := 1. |
|
717 stripNr := 0. |
|
718 |
|
719 row := 1. |
|
720 bytesPerStrip := bytesPerRow * rowsPerStrip. |
|
721 [row <= height] whileTrue:[ |
|
722 stripNr := stripNr + 1. |
|
723 inStream position:((stripOffsets at:stripNr) + 1). |
|
724 inStream nextBytes:(stripByteCounts at:stripNr) into:compressedStrip. |
|
725 self class decompressCCITT3From:compressedStrip |
|
726 into:data |
|
727 startingAt:offset |
|
728 count:width. |
|
729 offset := offset + bytesPerStrip. |
|
730 row := row + rowsPerStrip |
|
731 ] |
|
732 ! |
|
733 |
|
734 readCCITTGroup4TiffImageData |
|
735 'TIFFReader: ccitt group4 fax compression not implemented' errorPrintNL. |
|
736 ! |
|
737 |
|
738 readChars:n |
|
739 "read n characters and return them in a string" |
|
740 |
|
741 |oldPos offset string| |
|
742 |
|
743 string := String new:(n - 1). |
|
744 (n <= 4) ifTrue:[ |
|
745 inStream nextBytes:(n - 1) into:string |
1033 ] ifFalse:[ |
746 ] ifFalse:[ |
1034 stripOffsets := Array basicNew:height. |
747 offset := inStream nextLongMSB:(byteOrder ~~ #lsb). |
1035 bytesPerRow := nBytes // height. |
748 oldPos := inStream position. |
1036 stripByteCounts := (Array basicNew:height) atAllPut:bytesPerRow. |
749 inStream position:(offset + 1). |
1037 |
750 inStream nextBytes:(n - 1) into:string. |
1038 offs := 1. |
751 inStream position:oldPos |
1039 h := height. |
752 ]. |
1040 1 to:h do:[:row | |
753 ^ string |
1041 stripOffsets at:row put:(outStream position - 1). |
754 ! |
1042 outStream nextPutBytes:bytesPerRow from:data startingAt:offs. |
755 |
1043 offs := offs + bytesPerRow |
756 readFracts:nFracts |
1044 ]. |
757 "read nFracts fractions (2 32bit words) and return them in an array" |
1045 rowsPerStrip := 1 |
758 |
1046 ]. |
759 |oldPos offset values numerator denominator msb |
1047 " |
760 n "{ Class: SmallInteger }" | |
1048 'stripOffsets: ' print. stripOffsets printNewline. |
761 |
1049 'stripByteCounts: ' print. stripByteCounts printNewline. |
762 n := nFracts. |
1050 " |
763 |
1051 ! |
764 msb := byteOrder ~~ #lsb. |
1052 |
765 values := Array basicNew:n. |
1053 writeColorMap |
766 offset := inStream nextLongMSB:msb. |
1054 |n| |
767 oldPos := inStream position. |
1055 |
768 inStream position:(offset + 1). |
1056 colorMapPos := outStream position. |
769 1 to:n do:[:index | |
1057 #(red green blue) do:[:component | |
770 numerator := inStream nextLongMSB:msb. |
1058 n := 0. |
771 denominator := inStream nextLongMSB:msb. |
1059 colorMap do:[:clr | |
772 values at:index put:(Fraction numerator:numerator denominator:denominator) |
1060 |entry| |
773 ]. |
1061 |
774 inStream position:oldPos. |
1062 clr isNil ifTrue:[ |
775 ^ values |
1063 entry := 0 |
776 ! |
1064 ] ifFalse:[ |
777 |
1065 entry := clr perform:component. |
778 readJPEGTiffImageData |
1066 " |
779 'TIFFReader: jpeg compression not implemented' errorPrintNL |
1067 tiff map is 16 bit - scale from percent to 0..16rFFFF |
780 ! |
1068 " |
781 |
1069 entry := (entry * 16rFFFF / 100) rounded. |
782 readLZWTiffImageData |
|
783 "read LZW compressed tiff data; this method only |
|
784 handles 3x8 rgb and 1x2 or 2x2 greyscale images. |
|
785 For 2x2 greyscale images, the alpha plane is ignored. |
|
786 (maybe other formats work also - its simply not |
|
787 tested)" |
|
788 |
|
789 |bytesPerRow compressedStrip nPlanes |
|
790 bytesPerStrip "{ Class: SmallInteger }" |
|
791 nBytes "{ Class: SmallInteger }" |
|
792 prevSize "{ Class: SmallInteger }" |
|
793 stripNr "{ Class: SmallInteger }" |
|
794 offset "{ Class: SmallInteger }" |
|
795 row "{ Class: SmallInteger }" | |
|
796 |
|
797 nPlanes := samplesPerPixel. |
|
798 |
|
799 (nPlanes == 3) ifTrue:[ |
|
800 ((bitsPerSample at:1) ~~ 8) ifTrue:[ |
|
801 self error:'only 8 bit/sample supported'. |
|
802 ^ nil |
|
803 ]. |
|
804 ((bitsPerSample at:2) ~~ 8) ifTrue:[ |
|
805 self error:'only 8 bit/sample supported'. |
|
806 ^ nil |
|
807 ]. |
|
808 ((bitsPerSample at:3) ~~ 8) ifTrue:[ |
|
809 self error:'only 8 bit/sample supported'. |
|
810 ^ nil |
|
811 ]. |
|
812 bytesPerRow := width * samplesPerPixel. |
|
813 ] ifFalse:[ |
|
814 (nPlanes == 2) ifTrue:[ |
|
815 (planarConfiguration ~~ 2) ifTrue:[ |
|
816 self error:'only separate planes supported'. |
|
817 ^ nil |
1070 ]. |
818 ]. |
1071 self writeShort:entry. |
819 'TIFFReader: ignoring alpha plane' errorPrintNL. |
1072 n := n + 1 |
820 nPlanes := 1 |
1073 ]. |
821 ]. |
1074 " |
822 (nPlanes == 1) ifFalse:[ |
1075 fill to 256 entries |
823 self error:'only 3-sample rgb / monochrome supported'. |
1076 " |
824 ^ nil |
1077 [n < 256] whileTrue:[ |
825 ]. |
1078 self writeShort:0. |
826 bytesPerRow := (width * (bitsPerSample at:1) + 7) // 8. |
1079 n := n + 1. |
827 ]. |
|
828 |
|
829 stripByteCounts isNil ifTrue:[ |
|
830 self error:'currently require stripByteCounts'. |
|
831 ^ nil |
|
832 ]. |
|
833 |
|
834 'TIFFReader: decompressing LZW ...' infoPrintNL. |
|
835 |
|
836 data := ByteArray uninitializedNew:(bytesPerRow * height). |
|
837 |
|
838 offset := 1. |
|
839 stripNr := 0. |
|
840 |
|
841 row := 1. |
|
842 bytesPerStrip := bytesPerRow * rowsPerStrip. |
|
843 prevSize := 0. |
|
844 [row <= height] whileTrue:[ |
|
845 stripNr := stripNr + 1. |
|
846 inStream position:((stripOffsets at:stripNr) + 1). |
|
847 nBytes := stripByteCounts at:stripNr. |
|
848 (nBytes > prevSize) ifTrue:[ |
|
849 compressedStrip := ByteArray uninitializedNew:nBytes. |
|
850 prevSize := nBytes |
|
851 ]. |
|
852 inStream nextBytes:nBytes |
|
853 into:compressedStrip. |
|
854 self class decompressLZWFrom:compressedStrip |
|
855 count:nBytes |
|
856 into:data |
|
857 startingAt:offset. |
|
858 offset := offset + bytesPerStrip. |
|
859 row := row + rowsPerStrip |
|
860 ]. |
|
861 |
|
862 (predictor == 2) ifTrue:[ |
|
863 self class decodeDelta:3 in:data width:width height:height |
|
864 ] |
|
865 ! |
|
866 |
|
867 readLongs:nLongs |
|
868 "read nLongs long numbers (32bit) and return them in an array" |
|
869 |
|
870 |oldPos offset values msb |
|
871 n "{ Class: SmallInteger }" | |
|
872 |
|
873 n := nLongs. |
|
874 |
|
875 msb := byteOrder ~~ #lsb. |
|
876 values := Array basicNew:n. |
|
877 (n == 1) ifTrue:[ |
|
878 values at:1 put:(inStream nextLongMSB:msb). |
|
879 ] ifFalse:[ |
|
880 offset := inStream nextLongMSB:msb. |
|
881 oldPos := inStream position. |
|
882 inStream position:(offset + 1). |
|
883 1 to:n do:[:index | |
|
884 values at:index put:(inStream nextLongMSB:msb) |
|
885 ]. |
|
886 inStream position:oldPos |
|
887 ]. |
|
888 ^ values |
|
889 ! |
|
890 |
|
891 readNeXTJPEGTiffImageData |
|
892 'TIFFReader: jpeg compression not implemented' errorPrintNL |
|
893 ! |
|
894 |
|
895 readNeXTRLE2TiffImageData |
|
896 'TIFFReader: next 2bit rle compression not implemented' errorPrintNL. |
|
897 ! |
|
898 |
|
899 readPackbitsTiffImageData |
|
900 "had no samples yet - however, packbits decompression |
|
901 is rather trivial to add ..." |
|
902 |
|
903 'TIFFReader: packbits compression not implemented' errorPrintNL |
|
904 ! |
|
905 |
|
906 readShorts:nShorts |
|
907 "read nShorts short numbers (16bit) and return them in an array" |
|
908 |
|
909 |oldPos offset values msb val2 |
|
910 n "{ Class: SmallInteger }" | |
|
911 |
|
912 n := nShorts. |
|
913 |
|
914 msb := (byteOrder ~~ #lsb). |
|
915 values := Array basicNew:n. |
|
916 (n <= 2) ifTrue:[ |
|
917 values at:1 put:(inStream nextUnsignedShortMSB:msb). |
|
918 val2 := inStream nextUnsignedShortMSB:msb. |
|
919 |
|
920 (n == 2) ifTrue:[ |
|
921 values at:2 put:val2 |
1080 ] |
922 ] |
1081 ] |
|
1082 ! |
|
1083 |
|
1084 writeStripOffsets |
|
1085 " |
|
1086 'stripOffsets: ' print. stripOffsets printNewline. |
|
1087 'store stripoffsets at: ' print. outStream position printNewline. |
|
1088 " |
|
1089 stripOffsetsPos := outStream position. |
|
1090 stripOffsets do:[:o | |
|
1091 self writeLong:o |
|
1092 ] |
|
1093 ! |
|
1094 |
|
1095 writeStripByteCounts |
|
1096 " |
|
1097 'stripByteCounts: ' print. stripByteCounts printNewline. |
|
1098 'store stripbytecounts at: ' print. outStream position printNewline. |
|
1099 " |
|
1100 stripByteCountsPos := outStream position. |
|
1101 stripByteCounts do:[:c | |
|
1102 self writeShort:c |
|
1103 ] |
|
1104 ! |
|
1105 |
|
1106 writeBitsPerSample |
|
1107 " |
|
1108 'bitsPerSample: ' print. bitsPerSample printNewline. |
|
1109 'store bitspersample at: ' print. outStream position printNewline. |
|
1110 " |
|
1111 bitsPerSamplePos := outStream position. |
|
1112 bitsPerSample do:[:n | |
|
1113 self writeShort:n |
|
1114 ] |
|
1115 ! |
|
1116 |
|
1117 writeTag:tagType |
|
1118 self writeTiffTag:tagType. |
|
1119 ! |
|
1120 |
|
1121 writeTiffTag:tagType |
|
1122 |value valueArray numberType count address| |
|
1123 |
|
1124 count := 1. |
|
1125 address := nil. |
|
1126 (tagType == 253) ifTrue:[ |
|
1127 "tiff class" |
|
1128 ]. |
|
1129 (tagType == 254) ifTrue:[ |
|
1130 ]. |
|
1131 (tagType == 255) ifTrue:[ |
|
1132 "SubfileType" |
|
1133 value := subFileType. |
|
1134 numberType := #long. |
|
1135 ]. |
|
1136 (tagType == 256) ifTrue:[ |
|
1137 "ImageWidth" |
|
1138 value := width. |
|
1139 numberType := #short. |
|
1140 ]. |
|
1141 (tagType == 257) ifTrue:[ |
|
1142 "ImageHeight" |
|
1143 value := height. |
|
1144 numberType := #short. |
|
1145 ]. |
|
1146 (tagType == 258) ifTrue:[ |
|
1147 "bitspersample" |
|
1148 address := bitsPerSamplePos - 1. |
|
1149 numberType := #short. |
|
1150 count := bitsPerSample size. |
|
1151 valueArray := bitsPerSample |
|
1152 ]. |
|
1153 (tagType == 259) ifTrue:[ |
|
1154 "compression" |
|
1155 value := compression. |
|
1156 numberType := #short. |
|
1157 ]. |
|
1158 (tagType == 262) ifTrue:[ |
|
1159 "photometric" |
|
1160 (photometric == #whiteIs0) ifTrue:[ |
|
1161 value := 0 |
|
1162 ] ifFalse:[ |
|
1163 (photometric == #blackIs0) ifTrue:[ |
|
1164 value := 1 |
|
1165 ] ifFalse:[ |
|
1166 (photometric == #rgb) ifTrue:[ |
|
1167 value := 2 |
|
1168 ] ifFalse:[ |
|
1169 (photometric == #palette) ifTrue:[ |
|
1170 value := 3 |
|
1171 ] ifFalse:[ |
|
1172 (photometric == #transparency) ifTrue:[ |
|
1173 value := 4 |
|
1174 ] ifFalse:[ |
|
1175 self error:'bad photometric' |
|
1176 ] |
|
1177 ] |
|
1178 ] |
|
1179 ] |
|
1180 ]. |
|
1181 numberType := #short. |
|
1182 ]. |
|
1183 (tagType == 263) ifTrue:[ |
|
1184 ]. |
|
1185 (tagType == 264) ifTrue:[ |
|
1186 ]. |
|
1187 (tagType == 265) ifTrue:[ |
|
1188 ]. |
|
1189 (tagType == 266) ifTrue:[ |
|
1190 "fillOrder" |
|
1191 (fillOrder == #msb) ifTrue:[ |
|
1192 value := 1 |
|
1193 ] ifFalse:[ |
|
1194 (fillOrder == #lsb) ifTrue:[ |
|
1195 value := 2 |
|
1196 ] ifFalse:[ |
|
1197 self error:'bad fillOrder' |
|
1198 ] |
|
1199 ]. |
|
1200 numberType := #short. |
|
1201 ]. |
|
1202 (tagType == 269) ifTrue:[ |
|
1203 ]. |
|
1204 (tagType == 270) ifTrue:[ |
|
1205 ]. |
|
1206 (tagType == 271) ifTrue:[ |
|
1207 ]. |
|
1208 (tagType == 272) ifTrue:[ |
|
1209 ]. |
|
1210 (tagType == 273) ifTrue:[ |
|
1211 "stripoffsets" |
|
1212 address := stripOffsetsPos - 1. |
|
1213 numberType := #long. |
|
1214 count := stripOffsets size. |
|
1215 valueArray := stripOffsets |
|
1216 ]. |
|
1217 (tagType == 274) ifTrue:[ |
|
1218 ]. |
|
1219 (tagType == 277) ifTrue:[ |
|
1220 "samplesPerPixel" |
|
1221 value := samplesPerPixel. |
|
1222 numberType := #short. |
|
1223 ]. |
|
1224 (tagType == 278) ifTrue:[ |
|
1225 "rowsperstrip" |
|
1226 value := rowsPerStrip. |
|
1227 numberType := #short. |
|
1228 ]. |
|
1229 (tagType == 279) ifTrue:[ |
|
1230 "stripbytecount" |
|
1231 address := stripByteCountsPos - 1. |
|
1232 numberType := #short. |
|
1233 count := stripByteCounts size. |
|
1234 valueArray := stripByteCounts |
|
1235 ]. |
|
1236 (tagType == 280) ifTrue:[ |
|
1237 "min sample value" |
|
1238 ]. |
|
1239 (tagType == 281) ifTrue:[ |
|
1240 "max sample value" |
|
1241 ]. |
|
1242 (tagType == 282) ifTrue:[ |
|
1243 "x resolution" |
|
1244 ]. |
|
1245 (tagType == 283) ifTrue:[ |
|
1246 "y resolution" |
|
1247 ]. |
|
1248 (tagType == 284) ifTrue:[ |
|
1249 "planarconfig" |
|
1250 value := planarConfiguration. |
|
1251 numberType := #short. |
|
1252 ]. |
|
1253 (tagType == 285) ifTrue:[ |
|
1254 "pageName" |
|
1255 ]. |
|
1256 (tagType == 286) ifTrue:[ |
|
1257 "xPosition" |
|
1258 ]. |
|
1259 (tagType == 287) ifTrue:[ |
|
1260 "yPosition" |
|
1261 ]. |
|
1262 (tagType == 288) ifTrue:[ |
|
1263 "freeOffsets" |
|
1264 ]. |
|
1265 (tagType == 289) ifTrue:[ |
|
1266 "freeByteCounts" |
|
1267 ]. |
|
1268 (tagType == 290) ifTrue:[ |
|
1269 "grayResponceUnit" |
|
1270 ]. |
|
1271 (tagType == 291) ifTrue:[ |
|
1272 "grayResponceCurve" |
|
1273 ]. |
|
1274 (tagType == 292) ifTrue:[ |
|
1275 "group3options" |
|
1276 value := group3options. |
|
1277 numberType := #long. |
|
1278 ]. |
|
1279 (tagType == 293) ifTrue:[ |
|
1280 "group4options" |
|
1281 ]. |
|
1282 (tagType == 296) ifTrue:[ |
|
1283 "resolutionunit" |
|
1284 ^ self |
|
1285 ]. |
|
1286 (tagType == 297) ifTrue:[ |
|
1287 "pageNumber" |
|
1288 ]. |
|
1289 (tagType == 300) ifTrue:[ |
|
1290 "colorResponceUnit" |
|
1291 ]. |
|
1292 (tagType == 301) ifTrue:[ |
|
1293 "colorResponceCurve" |
|
1294 ]. |
|
1295 (tagType == 306) ifTrue:[ |
|
1296 "dateTime" |
|
1297 ]. |
|
1298 (tagType == 315) ifTrue:[ |
|
1299 "artist" |
|
1300 ]. |
|
1301 (tagType == 317) ifTrue:[ |
|
1302 "predictor" |
|
1303 ]. |
|
1304 (tagType == 320) ifTrue:[ |
|
1305 "colormap" |
|
1306 address := colorMapPos - 1. |
|
1307 numberType := #short. |
|
1308 count := 256 "(colorMap at:1) size" * 3. |
|
1309 ]. |
|
1310 |
|
1311 (value isNil and:[address isNil]) ifTrue:[ |
|
1312 self error:'unhandled tag'. |
|
1313 ^ self |
|
1314 ]. |
|
1315 |
|
1316 " |
|
1317 'tag:' print. tagType print. ' typ:' print. numberType print. |
|
1318 ' len:' print. count print. |
|
1319 ' val:' print. value printNewline. |
|
1320 " |
|
1321 |
|
1322 self writeShort:tagType. |
|
1323 numberType == #short ifTrue:[ |
|
1324 self writeShort:3. |
|
1325 self writeLong:count. |
|
1326 ] ifFalse:[ |
923 ] ifFalse:[ |
1327 numberType == #long ifTrue:[ |
924 offset := inStream nextLongMSB:msb. |
1328 self writeShort:4. |
925 oldPos := inStream position. |
1329 self writeLong:count. |
926 inStream position:(offset + 1). |
1330 ] ifFalse:[ |
927 1 to:n do:[:index | |
1331 numberType == #byte ifTrue:[ |
928 values at:index put:(inStream nextUnsignedShortMSB:msb) |
1332 self writeShort:1. |
929 ]. |
1333 self writeLong:count. |
930 inStream position:oldPos |
1334 ] ifFalse:[ |
931 ]. |
1335 self error:'bad numbertype' |
932 ^ values |
1336 ] |
|
1337 ] |
|
1338 ]. |
|
1339 address notNil ifTrue:[ |
|
1340 (numberType == #long and:[count == 1]) ifTrue:[ |
|
1341 self writeLong:(valueArray at:1). |
|
1342 ^ self |
|
1343 ]. |
|
1344 (numberType == #short and:[count <= 2]) ifTrue:[ |
|
1345 self writeShort:(valueArray at:1). |
|
1346 count == 2 ifTrue:[ |
|
1347 self writeShort:(valueArray at:2). |
|
1348 ] ifFalse:[ |
|
1349 self writeShort:0 |
|
1350 ]. |
|
1351 ^ self |
|
1352 ]. |
|
1353 (numberType == #byte and:[count <= 4]) ifTrue:[ |
|
1354 outStream nextPut:(valueArray at:1). |
|
1355 count > 1 ifTrue:[ |
|
1356 outStream nextPut:(valueArray at:2). |
|
1357 count > 2 ifTrue:[ |
|
1358 outStream nextPut:(valueArray at:3). |
|
1359 count > 3 ifTrue:[ |
|
1360 outStream nextPut:(valueArray at:4). |
|
1361 ] ifFalse:[ |
|
1362 outStream nextPut:0 |
|
1363 ]. |
|
1364 ] ifFalse:[ |
|
1365 outStream nextPut:0 |
|
1366 ]. |
|
1367 ] ifFalse:[ |
|
1368 outStream nextPut:0 |
|
1369 ]. |
|
1370 ^ self |
|
1371 ]. |
|
1372 self writeLong:address. |
|
1373 ^ self |
|
1374 ]. |
|
1375 numberType == #short ifTrue:[ |
|
1376 self writeShort:value. |
|
1377 self writeShort:0 |
|
1378 ] ifFalse:[ |
|
1379 numberType == #long ifTrue:[ |
|
1380 self writeLong:value |
|
1381 ] ifFalse:[ |
|
1382 numberType == #byte ifTrue:[ |
|
1383 outStream nextPut:value. |
|
1384 outStream nextPut:0. |
|
1385 outStream nextPut:0. |
|
1386 outStream nextPut:0. |
|
1387 ] ifFalse:[ |
|
1388 self error:'bad numbertype' |
|
1389 ] |
|
1390 ] |
|
1391 ]. |
|
1392 ! |
933 ! |
1393 |
934 |
1394 readUncompressedTiffImageData |
935 readUncompressedTiffImageData |
1395 |bytesPerRow bitsPerRow nPlanes |
936 |bytesPerRow bitsPerRow nPlanes |
1396 stripNr "{ Class: SmallInteger }" |
937 stripNr "{ Class: SmallInteger }" |
1457 offset := offset + nBytes. |
998 offset := offset + nBytes. |
1458 row := row + rowsPerStrip |
999 row := row + rowsPerStrip |
1459 ] |
1000 ] |
1460 ! |
1001 ! |
1461 |
1002 |
1462 readLZWTiffImageData |
1003 writeBitsPerSample |
1463 "read LZW compressed tiff data; this method only |
1004 " |
1464 handles 3x8 rgb and 1x2 or 2x2 greyscale images. |
1005 'bitsPerSample: ' print. bitsPerSample printNewline. |
1465 For 2x2 greyscale images, the alpha plane is ignored. |
1006 'store bitspersample at: ' print. outStream position printNewline. |
1466 (maybe other formats work also - its simply not |
1007 " |
1467 tested)" |
1008 bitsPerSamplePos := outStream position. |
1468 |
1009 bitsPerSample do:[:n | |
1469 |bytesPerRow compressedStrip nPlanes |
1010 self writeShort:n |
1470 bytesPerStrip "{ Class: SmallInteger }" |
1011 ] |
1471 nBytes "{ Class: SmallInteger }" |
1012 ! |
1472 prevSize "{ Class: SmallInteger }" |
1013 |
1473 stripNr "{ Class: SmallInteger }" |
1014 writeColorMap |
1474 offset "{ Class: SmallInteger }" |
1015 |n| |
1475 row "{ Class: SmallInteger }" | |
1016 |
1476 |
1017 colorMapPos := outStream position. |
1477 nPlanes := samplesPerPixel. |
1018 #(red green blue) do:[:component | |
1478 |
1019 n := 0. |
1479 (nPlanes == 3) ifTrue:[ |
1020 colorMap do:[:clr | |
1480 ((bitsPerSample at:1) ~~ 8) ifTrue:[ |
1021 |entry| |
1481 self error:'only 8 bit/sample supported'. |
1022 |
|
1023 clr isNil ifTrue:[ |
|
1024 entry := 0 |
|
1025 ] ifFalse:[ |
|
1026 entry := clr perform:component. |
|
1027 " |
|
1028 tiff map is 16 bit - scale from percent to 0..16rFFFF |
|
1029 " |
|
1030 entry := (entry * 16rFFFF / 100) rounded. |
|
1031 ]. |
|
1032 self writeShort:entry. |
|
1033 n := n + 1 |
|
1034 ]. |
|
1035 " |
|
1036 fill to 256 entries |
|
1037 " |
|
1038 [n < 256] whileTrue:[ |
|
1039 self writeShort:0. |
|
1040 n := n + 1. |
|
1041 ] |
|
1042 ] |
|
1043 ! |
|
1044 |
|
1045 writeStripByteCounts |
|
1046 " |
|
1047 'stripByteCounts: ' print. stripByteCounts printNewline. |
|
1048 'store stripbytecounts at: ' print. outStream position printNewline. |
|
1049 " |
|
1050 stripByteCountsPos := outStream position. |
|
1051 stripByteCounts do:[:c | |
|
1052 self writeShort:c |
|
1053 ] |
|
1054 ! |
|
1055 |
|
1056 writeStripOffsets |
|
1057 " |
|
1058 'stripOffsets: ' print. stripOffsets printNewline. |
|
1059 'store stripoffsets at: ' print. outStream position printNewline. |
|
1060 " |
|
1061 stripOffsetsPos := outStream position. |
|
1062 stripOffsets do:[:o | |
|
1063 self writeLong:o |
|
1064 ] |
|
1065 ! |
|
1066 |
|
1067 writeTag:tagType |
|
1068 self writeTiffTag:tagType. |
|
1069 ! |
|
1070 |
|
1071 writeTiffTag:tagType |
|
1072 |value valueArray numberType count address| |
|
1073 |
|
1074 count := 1. |
|
1075 address := nil. |
|
1076 (tagType == 253) ifTrue:[ |
|
1077 "tiff class" |
|
1078 ]. |
|
1079 (tagType == 254) ifTrue:[ |
|
1080 ]. |
|
1081 (tagType == 255) ifTrue:[ |
|
1082 "SubfileType" |
|
1083 value := subFileType. |
|
1084 numberType := #long. |
|
1085 ]. |
|
1086 (tagType == 256) ifTrue:[ |
|
1087 "ImageWidth" |
|
1088 value := width. |
|
1089 numberType := #short. |
|
1090 ]. |
|
1091 (tagType == 257) ifTrue:[ |
|
1092 "ImageHeight" |
|
1093 value := height. |
|
1094 numberType := #short. |
|
1095 ]. |
|
1096 (tagType == 258) ifTrue:[ |
|
1097 "bitspersample" |
|
1098 address := bitsPerSamplePos - 1. |
|
1099 numberType := #short. |
|
1100 count := bitsPerSample size. |
|
1101 valueArray := bitsPerSample |
|
1102 ]. |
|
1103 (tagType == 259) ifTrue:[ |
|
1104 "compression" |
|
1105 value := compression. |
|
1106 numberType := #short. |
|
1107 ]. |
|
1108 (tagType == 262) ifTrue:[ |
|
1109 "photometric" |
|
1110 (photometric == #whiteIs0) ifTrue:[ |
|
1111 value := 0 |
|
1112 ] ifFalse:[ |
|
1113 (photometric == #blackIs0) ifTrue:[ |
|
1114 value := 1 |
|
1115 ] ifFalse:[ |
|
1116 (photometric == #rgb) ifTrue:[ |
|
1117 value := 2 |
|
1118 ] ifFalse:[ |
|
1119 (photometric == #palette) ifTrue:[ |
|
1120 value := 3 |
|
1121 ] ifFalse:[ |
|
1122 (photometric == #transparency) ifTrue:[ |
|
1123 value := 4 |
|
1124 ] ifFalse:[ |
|
1125 self error:'bad photometric' |
|
1126 ] |
|
1127 ] |
|
1128 ] |
|
1129 ] |
|
1130 ]. |
|
1131 numberType := #short. |
|
1132 ]. |
|
1133 (tagType == 263) ifTrue:[ |
|
1134 ]. |
|
1135 (tagType == 264) ifTrue:[ |
|
1136 ]. |
|
1137 (tagType == 265) ifTrue:[ |
|
1138 ]. |
|
1139 (tagType == 266) ifTrue:[ |
|
1140 "fillOrder" |
|
1141 (fillOrder == #msb) ifTrue:[ |
|
1142 value := 1 |
|
1143 ] ifFalse:[ |
|
1144 (fillOrder == #lsb) ifTrue:[ |
|
1145 value := 2 |
|
1146 ] ifFalse:[ |
|
1147 self error:'bad fillOrder' |
|
1148 ] |
|
1149 ]. |
|
1150 numberType := #short. |
|
1151 ]. |
|
1152 (tagType == 269) ifTrue:[ |
|
1153 ]. |
|
1154 (tagType == 270) ifTrue:[ |
|
1155 ]. |
|
1156 (tagType == 271) ifTrue:[ |
|
1157 ]. |
|
1158 (tagType == 272) ifTrue:[ |
|
1159 ]. |
|
1160 (tagType == 273) ifTrue:[ |
|
1161 "stripoffsets" |
|
1162 address := stripOffsetsPos - 1. |
|
1163 numberType := #long. |
|
1164 count := stripOffsets size. |
|
1165 valueArray := stripOffsets |
|
1166 ]. |
|
1167 (tagType == 274) ifTrue:[ |
|
1168 ]. |
|
1169 (tagType == 277) ifTrue:[ |
|
1170 "samplesPerPixel" |
|
1171 value := samplesPerPixel. |
|
1172 numberType := #short. |
|
1173 ]. |
|
1174 (tagType == 278) ifTrue:[ |
|
1175 "rowsperstrip" |
|
1176 value := rowsPerStrip. |
|
1177 numberType := #short. |
|
1178 ]. |
|
1179 (tagType == 279) ifTrue:[ |
|
1180 "stripbytecount" |
|
1181 address := stripByteCountsPos - 1. |
|
1182 numberType := #short. |
|
1183 count := stripByteCounts size. |
|
1184 valueArray := stripByteCounts |
|
1185 ]. |
|
1186 (tagType == 280) ifTrue:[ |
|
1187 "min sample value" |
|
1188 ]. |
|
1189 (tagType == 281) ifTrue:[ |
|
1190 "max sample value" |
|
1191 ]. |
|
1192 (tagType == 282) ifTrue:[ |
|
1193 "x resolution" |
|
1194 ]. |
|
1195 (tagType == 283) ifTrue:[ |
|
1196 "y resolution" |
|
1197 ]. |
|
1198 (tagType == 284) ifTrue:[ |
|
1199 "planarconfig" |
|
1200 value := planarConfiguration. |
|
1201 numberType := #short. |
|
1202 ]. |
|
1203 (tagType == 285) ifTrue:[ |
|
1204 "pageName" |
|
1205 ]. |
|
1206 (tagType == 286) ifTrue:[ |
|
1207 "xPosition" |
|
1208 ]. |
|
1209 (tagType == 287) ifTrue:[ |
|
1210 "yPosition" |
|
1211 ]. |
|
1212 (tagType == 288) ifTrue:[ |
|
1213 "freeOffsets" |
|
1214 ]. |
|
1215 (tagType == 289) ifTrue:[ |
|
1216 "freeByteCounts" |
|
1217 ]. |
|
1218 (tagType == 290) ifTrue:[ |
|
1219 "grayResponceUnit" |
|
1220 ]. |
|
1221 (tagType == 291) ifTrue:[ |
|
1222 "grayResponceCurve" |
|
1223 ]. |
|
1224 (tagType == 292) ifTrue:[ |
|
1225 "group3options" |
|
1226 value := group3options. |
|
1227 numberType := #long. |
|
1228 ]. |
|
1229 (tagType == 293) ifTrue:[ |
|
1230 "group4options" |
|
1231 ]. |
|
1232 (tagType == 296) ifTrue:[ |
|
1233 "resolutionunit" |
|
1234 ^ self |
|
1235 ]. |
|
1236 (tagType == 297) ifTrue:[ |
|
1237 "pageNumber" |
|
1238 ]. |
|
1239 (tagType == 300) ifTrue:[ |
|
1240 "colorResponceUnit" |
|
1241 ]. |
|
1242 (tagType == 301) ifTrue:[ |
|
1243 "colorResponceCurve" |
|
1244 ]. |
|
1245 (tagType == 306) ifTrue:[ |
|
1246 "dateTime" |
|
1247 ]. |
|
1248 (tagType == 315) ifTrue:[ |
|
1249 "artist" |
|
1250 ]. |
|
1251 (tagType == 317) ifTrue:[ |
|
1252 "predictor" |
|
1253 ]. |
|
1254 (tagType == 320) ifTrue:[ |
|
1255 "colormap" |
|
1256 address := colorMapPos - 1. |
|
1257 numberType := #short. |
|
1258 count := 256 "(colorMap at:1) size" * 3. |
|
1259 ]. |
|
1260 |
|
1261 (value isNil and:[address isNil]) ifTrue:[ |
|
1262 self error:'unhandled tag'. |
|
1263 ^ self |
|
1264 ]. |
|
1265 |
|
1266 " |
|
1267 'tag:' print. tagType print. ' typ:' print. numberType print. |
|
1268 ' len:' print. count print. |
|
1269 ' val:' print. value printNewline. |
|
1270 " |
|
1271 |
|
1272 self writeShort:tagType. |
|
1273 numberType == #short ifTrue:[ |
|
1274 self writeShort:3. |
|
1275 self writeLong:count. |
|
1276 ] ifFalse:[ |
|
1277 numberType == #long ifTrue:[ |
|
1278 self writeShort:4. |
|
1279 self writeLong:count. |
|
1280 ] ifFalse:[ |
|
1281 numberType == #byte ifTrue:[ |
|
1282 self writeShort:1. |
|
1283 self writeLong:count. |
|
1284 ] ifFalse:[ |
|
1285 self error:'bad numbertype' |
|
1286 ] |
|
1287 ] |
|
1288 ]. |
|
1289 address notNil ifTrue:[ |
|
1290 (numberType == #long and:[count == 1]) ifTrue:[ |
|
1291 self writeLong:(valueArray at:1). |
|
1292 ^ self |
|
1293 ]. |
|
1294 (numberType == #short and:[count <= 2]) ifTrue:[ |
|
1295 self writeShort:(valueArray at:1). |
|
1296 count == 2 ifTrue:[ |
|
1297 self writeShort:(valueArray at:2). |
|
1298 ] ifFalse:[ |
|
1299 self writeShort:0 |
|
1300 ]. |
|
1301 ^ self |
|
1302 ]. |
|
1303 (numberType == #byte and:[count <= 4]) ifTrue:[ |
|
1304 outStream nextPut:(valueArray at:1). |
|
1305 count > 1 ifTrue:[ |
|
1306 outStream nextPut:(valueArray at:2). |
|
1307 count > 2 ifTrue:[ |
|
1308 outStream nextPut:(valueArray at:3). |
|
1309 count > 3 ifTrue:[ |
|
1310 outStream nextPut:(valueArray at:4). |
|
1311 ] ifFalse:[ |
|
1312 outStream nextPut:0 |
|
1313 ]. |
|
1314 ] ifFalse:[ |
|
1315 outStream nextPut:0 |
|
1316 ]. |
|
1317 ] ifFalse:[ |
|
1318 outStream nextPut:0 |
|
1319 ]. |
|
1320 ^ self |
|
1321 ]. |
|
1322 self writeLong:address. |
|
1323 ^ self |
|
1324 ]. |
|
1325 numberType == #short ifTrue:[ |
|
1326 self writeShort:value. |
|
1327 self writeShort:0 |
|
1328 ] ifFalse:[ |
|
1329 numberType == #long ifTrue:[ |
|
1330 self writeLong:value |
|
1331 ] ifFalse:[ |
|
1332 numberType == #byte ifTrue:[ |
|
1333 outStream nextPut:value. |
|
1334 outStream nextPut:0. |
|
1335 outStream nextPut:0. |
|
1336 outStream nextPut:0. |
|
1337 ] ifFalse:[ |
|
1338 self error:'bad numbertype' |
|
1339 ] |
|
1340 ] |
|
1341 ]. |
|
1342 ! |
|
1343 |
|
1344 writeUncompressedBits |
|
1345 "write bits as one or multiple strips" |
|
1346 |
|
1347 |offs bytesPerRow nBytes |
|
1348 h "{ Class: SmallInteger }"| |
|
1349 |
|
1350 nBytes := data size. |
|
1351 nBytes < 16rFFFF ifTrue:[ |
|
1352 stripOffsets := Array with:(outStream position - 1). |
|
1353 stripByteCounts := Array with:nBytes. |
|
1354 outStream nextPutBytes:nBytes from:data. |
|
1355 rowsPerStrip := height |
|
1356 ] ifFalse:[ |
|
1357 stripOffsets := Array basicNew:height. |
|
1358 bytesPerRow := nBytes // height. |
|
1359 stripByteCounts := (Array basicNew:height) atAllPut:bytesPerRow. |
|
1360 |
|
1361 offs := 1. |
|
1362 h := height. |
|
1363 1 to:h do:[:row | |
|
1364 stripOffsets at:row put:(outStream position - 1). |
|
1365 outStream nextPutBytes:bytesPerRow from:data startingAt:offs. |
|
1366 offs := offs + bytesPerRow |
|
1367 ]. |
|
1368 rowsPerStrip := 1 |
|
1369 ]. |
|
1370 " |
|
1371 'stripOffsets: ' print. stripOffsets printNewline. |
|
1372 'stripByteCounts: ' print. stripByteCounts printNewline. |
|
1373 " |
|
1374 ! ! |
|
1375 |
|
1376 !TIFFReader methodsFor:'reading from file'! |
|
1377 |
|
1378 fromStream:aStream |
|
1379 "read an image from aStream" |
|
1380 |
|
1381 |char1 char2 version |
|
1382 numberOfTags "{ Class: SmallInteger }" |
|
1383 tagType "{ Class: SmallInteger }" |
|
1384 numberType "{ Class: SmallInteger }" |
|
1385 length "{ Class: SmallInteger }" |
|
1386 result offset ok msb| |
|
1387 |
|
1388 inStream := aStream. |
|
1389 |
|
1390 char1 := aStream next. |
|
1391 char2 := aStream next. |
|
1392 (char1 ~~ char2) ifTrue:[ |
|
1393 'TIFFReader: not a tiff file' errorPrintNL. |
|
1394 ^ nil |
|
1395 ]. |
|
1396 (char1 == $I) ifTrue:[ |
|
1397 byteOrder := #lsb. |
|
1398 msb := false. |
|
1399 ] ifFalse:[ |
|
1400 (char1 == $M) ifTrue:[ |
|
1401 byteOrder := #msb. |
|
1402 msb := true. |
|
1403 ] ifFalse:[ |
|
1404 'TIFFReader: not a tiff file' errorPrintNL. |
1482 ^ nil |
1405 ^ nil |
1483 ]. |
1406 ] |
1484 ((bitsPerSample at:2) ~~ 8) ifTrue:[ |
1407 ]. |
1485 self error:'only 8 bit/sample supported'. |
1408 |
1486 ^ nil |
1409 aStream binary. |
1487 ]. |
1410 |
1488 ((bitsPerSample at:3) ~~ 8) ifTrue:[ |
1411 version := self readShort. |
1489 self error:'only 8 bit/sample supported'. |
1412 (version ~~ 42) ifTrue:[ |
1490 ^ nil |
1413 'TIFFReader: version of tiff-file not supported' errorPrintNL. |
1491 ]. |
1414 ^ nil |
1492 bytesPerRow := width * samplesPerPixel. |
1415 ]. |
|
1416 |
|
1417 "setup default values" |
|
1418 |
|
1419 compression := 1. "none" |
|
1420 fillOrder := #msb. |
|
1421 planarConfiguration := 1. |
|
1422 photometric := nil. |
|
1423 bitsPerSample := 1. |
|
1424 samplesPerPixel := 1. |
|
1425 width := nil. |
|
1426 height := nil. |
|
1427 stripOffsets := nil. |
|
1428 rowsPerStrip := nil. |
|
1429 "resolutionUnit := 2." |
|
1430 predictor := 1. |
|
1431 |
|
1432 offset := aStream nextLongMSB:msb. |
|
1433 aStream position:offset + 1. |
|
1434 |
|
1435 numberOfTags := self readShort. |
|
1436 1 to:numberOfTags do:[:index | |
|
1437 tagType := self readShort. |
|
1438 numberType := self readShort. |
|
1439 length := aStream nextLongMSB:msb. |
|
1440 self decodeTiffTag:tagType numberType:numberType length:length |
|
1441 ]. |
|
1442 |
|
1443 offset := aStream nextLongMSB:msb. |
|
1444 (offset ~~ 0) ifTrue:[ |
|
1445 'TIFFReader: more tags ignored' errorPrintNL |
|
1446 ]. |
|
1447 |
|
1448 "check for required tags" |
|
1449 ok := true. |
|
1450 width isNil ifTrue:[ |
|
1451 'TIFFReader: missing width tag' errorPrintNL. |
|
1452 ok := false |
|
1453 ]. |
|
1454 |
|
1455 height isNil ifTrue:[ |
|
1456 'TIFFReader: missing length tag' errorPrintNL. |
|
1457 ok := false |
|
1458 ]. |
|
1459 |
|
1460 photometric isNil ifTrue:[ |
|
1461 'TIFFReader: missing photometric tag' errorPrintNL. |
|
1462 ok := false |
|
1463 ]. |
|
1464 |
|
1465 stripOffsets isNil ifTrue:[ |
|
1466 'TIFFReader: missing stripOffsets tag' errorPrintNL. |
|
1467 ok := false |
|
1468 ]. |
|
1469 |
|
1470 stripByteCounts isNil ifTrue:[ |
|
1471 stripOffsets size == 1 ifTrue:[ |
|
1472 stripByteCounts := Array with:(self bitsPerPixel // 8) * width * height |
|
1473 ] |
|
1474 ]. |
|
1475 |
|
1476 stripByteCounts isNil ifTrue:[ |
|
1477 'TIFFReader: missing stripByteCounts tag' errorPrintNL. |
|
1478 ok := false |
|
1479 ]. |
|
1480 |
|
1481 ok ifFalse:[ |
|
1482 ^ nil |
|
1483 ]. |
|
1484 |
|
1485 "given all the information, read the bits" |
|
1486 |
|
1487 rowsPerStrip isNil ifTrue:[ |
|
1488 rowsPerStrip := height |
|
1489 ]. |
|
1490 |
|
1491 ok := false. |
|
1492 (compression == 1) ifTrue:[ |
|
1493 result := self readUncompressedTiffImageData. |
|
1494 ok := true |
|
1495 ]. |
|
1496 (compression == 2) ifTrue:[ |
|
1497 result := self readCCITT3RLETiffImageData. |
|
1498 ok := true |
|
1499 ]. |
|
1500 (compression == 3) ifTrue:[ |
|
1501 result := self readCCITTGroup3TiffImageData. |
|
1502 ok := true |
|
1503 ]. |
|
1504 (compression == 4) ifTrue:[ |
|
1505 result := self readCCITTGroup4TiffImageData. |
|
1506 ok := true |
|
1507 ]. |
|
1508 (compression == 5) ifTrue:[ |
|
1509 result := self readLZWTiffImageData. |
|
1510 ok := true |
|
1511 ]. |
|
1512 (compression == 6) ifTrue:[ |
|
1513 result := self readJPEGTiffImageData. |
|
1514 ok := true |
|
1515 ]. |
|
1516 (compression == 32766) ifTrue:[ |
|
1517 result := self readNeXTRLE2TiffImageData. |
|
1518 ok := true |
|
1519 ]. |
|
1520 (compression == 32771) ifTrue:[ |
|
1521 result := self readCCITTRLEWTiffImageData. |
|
1522 ok := true |
|
1523 ]. |
|
1524 (compression == 32773) ifTrue:[ |
|
1525 result := self readPackbitsTiffImageData. |
|
1526 ok := true |
|
1527 ]. |
|
1528 (compression == 32865) ifTrue:[ |
|
1529 result := self readNeXTJPEGTiffImageData. |
|
1530 ok := true |
|
1531 ]. |
|
1532 ok ifFalse:[ |
|
1533 'TIFFReader: compression type ' errorPrint. compression errorPrint. |
|
1534 ' not known' errorPrintNL |
|
1535 ]. |
|
1536 ^ result |
|
1537 ! ! |
|
1538 |
|
1539 !TIFFReader methodsFor:'writing to file'! |
|
1540 |
|
1541 save:image onFile:aFileName |
|
1542 "save image as (uncompressed) TIFF file on aFileName" |
|
1543 |
|
1544 |pos1 pos| |
|
1545 |
|
1546 outStream := FileStream newFileNamed:aFileName. |
|
1547 outStream isNil ifTrue:[ |
|
1548 'TIFFReader: create error' errorPrintNL. |
|
1549 ^ nil |
|
1550 ]. |
|
1551 |
|
1552 "save as msb" |
|
1553 |
|
1554 byteOrder := #msb. |
|
1555 " |
|
1556 byteOrder := #lsb. |
|
1557 " |
|
1558 fillOrder := #msb. |
|
1559 width := image width. |
|
1560 height := image height. |
|
1561 photometric := image photometric. |
|
1562 samplesPerPixel := image samplesPerPixel. |
|
1563 bitsPerSample := image bitsPerSample. |
|
1564 colorMap := image colorMap. |
|
1565 planarConfiguration := 1. |
|
1566 compression := 1. "none" |
|
1567 data := image bits. |
|
1568 |
|
1569 currentOffset := 0. |
|
1570 |
|
1571 (byteOrder == #msb) ifTrue:[ |
|
1572 outStream nextPut:$M. |
|
1573 outStream nextPut:$M. |
1493 ] ifFalse:[ |
1574 ] ifFalse:[ |
1494 (nPlanes == 2) ifTrue:[ |
1575 outStream nextPut:$I. |
1495 (planarConfiguration ~~ 2) ifTrue:[ |
1576 outStream nextPut:$I. |
1496 self error:'only separate planes supported'. |
1577 ]. |
1497 ^ nil |
1578 currentOffset := currentOffset + 2. |
1498 ]. |
1579 |
1499 'TIFFReader: ignoring alpha plane' errorPrintNL. |
1580 outStream binary. |
1500 nPlanes := 1 |
1581 |
1501 ]. |
1582 self writeShort:42. |
1502 (nPlanes == 1) ifFalse:[ |
1583 currentOffset := currentOffset + 2. |
1503 self error:'only 3-sample rgb / monochrome supported'. |
1584 |
1504 ^ nil |
1585 pos1 := outStream position. |
1505 ]. |
1586 self writeLong:0. "start of tags - filled in later" |
1506 bytesPerRow := (width * (bitsPerSample at:1) + 7) // 8. |
1587 currentOffset := currentOffset + 4. |
1507 ]. |
1588 |
1508 |
1589 "output strips" |
1509 stripByteCounts isNil ifTrue:[ |
1590 |
1510 self error:'currently require stripByteCounts'. |
1591 self writeUncompressedBits. "this outputs bits as strips, sets stripOffsets and stripByteCounts" |
1511 ^ nil |
1592 self writeStripOffsets. "this outputs strip offsets, sets stripOffsetsPos" |
1512 ]. |
1593 self writeStripByteCounts. "this outputs strip bytecounts, sets stripByteCountPos" |
1513 |
1594 self writeBitsPerSample. "this outputs bitsPerSample, sets bitsPerSamplePos" |
1514 'TIFFReader: decompressing LZW ...' infoPrintNL. |
1595 photometric == #palette ifTrue:[ |
1515 |
1596 self writeColorMap "this outputs colorMap, sets colorMapPos" |
1516 data := ByteArray uninitializedNew:(bytesPerRow * height). |
1597 ]. |
1517 |
1598 |
1518 offset := 1. |
1599 pos := outStream position. "backpatch tag offset" |
1519 stripNr := 0. |
1600 outStream position:pos1. |
1520 |
1601 self writeLong:(pos - 1). "fill in tag offset" |
1521 row := 1. |
1602 outStream position:pos. |
1522 bytesPerStrip := bytesPerRow * rowsPerStrip. |
1603 " |
1523 prevSize := 0. |
1604 ('patch tag offset at: ', (pos1 printStringRadix:16) , ' to ', |
1524 [row <= height] whileTrue:[ |
1605 (pos printStringRadix:16)) printNewline. |
1525 stripNr := stripNr + 1. |
1606 " |
1526 inStream position:((stripOffsets at:stripNr) + 1). |
1607 "output tag data" |
1527 nBytes := stripByteCounts at:stripNr. |
1608 |
1528 (nBytes > prevSize) ifTrue:[ |
1609 photometric == #palette ifTrue:[ |
1529 compressedStrip := ByteArray uninitializedNew:nBytes. |
1610 self writeShort:10. "10 tags" |
1530 prevSize := nBytes |
1611 ] ifFalse:[ |
1531 ]. |
1612 self writeShort:9. "9 tags" |
1532 inStream nextBytes:nBytes |
1613 ]. |
1533 into:compressedStrip. |
1614 self writeTag:256. "image width" |
1534 self class decompressLZWFrom:compressedStrip |
1615 self writeTag:257. "image height" |
1535 count:nBytes |
1616 self writeTag:258. "bits per sample" |
1536 into:data |
1617 self writeTag:259. "compression" |
1537 startingAt:offset. |
1618 self writeTag:262. "photometric" |
1538 offset := offset + bytesPerStrip. |
1619 self writeTag:273. "strip offsets" |
1539 row := row + rowsPerStrip |
1620 self writeTag:278. "rowsPerStrip" |
1540 ]. |
1621 self writeTag:279. "strip byte counts" |
1541 |
1622 self writeTag:284. "planarconfig" |
1542 (predictor == 2) ifTrue:[ |
1623 photometric == #palette ifTrue:[ |
1543 self class decodeDelta:3 in:data width:width height:height |
1624 self writeTag:320 "colorMap" |
1544 ] |
1625 ]. |
1545 ! |
1626 self writeLong:0. "end of tags mark" |
1546 |
1627 outStream close |
1547 readCCITTGroup3TiffImageData |
|
1548 "not really tested - all I got is a single |
|
1549 fax from NeXT step" |
|
1550 |
|
1551 |bytesPerRow bitsPerRow compressedStrip nPlanes |
|
1552 stripNr "{ Class: SmallInteger }" |
|
1553 offset "{ Class: SmallInteger }" |
|
1554 row "{ Class: SmallInteger }" |
|
1555 bytesPerStrip "{ Class: SmallInteger }" | |
|
1556 |
|
1557 nPlanes := samplesPerPixel. |
|
1558 (nPlanes == 2) ifTrue:[ |
|
1559 'TIFFReader: ignoring alpha plane' errorPrintNL. |
|
1560 nPlanes := 1 |
|
1561 ]. |
|
1562 |
|
1563 (nPlanes ~~ 1) ifTrue:[ |
|
1564 self error:'only monochrome/greyscale supported'. |
|
1565 ^ nil |
|
1566 ]. |
|
1567 |
|
1568 stripByteCounts isNil ifTrue:[ |
|
1569 self error:'currently require stripByteCounts'. |
|
1570 ^ nil |
|
1571 ]. |
|
1572 (rowsPerStrip ~~ 1) isNil ifTrue:[ |
|
1573 self error:'currently require rowsPerStrip to be 1'. |
|
1574 ^ nil |
|
1575 ]. |
|
1576 |
|
1577 'TIFFReader: decompressing CCITT-3 ...' infoPrintNL. |
|
1578 |
|
1579 bitsPerRow := width * (bitsPerSample at:1). |
|
1580 bytesPerRow := bitsPerRow // 8. |
|
1581 ((bitsPerRow \\ 8) ~~ 0) ifTrue:[ |
|
1582 bytesPerRow := bytesPerRow + 1 |
|
1583 ]. |
|
1584 |
|
1585 data := ByteArray new:(bytesPerRow * height). |
|
1586 compressedStrip := ByteArray uninitializedNew:bytesPerRow. |
|
1587 |
|
1588 offset := 1. |
|
1589 stripNr := 0. |
|
1590 |
|
1591 row := 1. |
|
1592 bytesPerStrip := bytesPerRow * rowsPerStrip. |
|
1593 [row <= height] whileTrue:[ |
|
1594 stripNr := stripNr + 1. |
|
1595 inStream position:((stripOffsets at:stripNr) + 1). |
|
1596 inStream nextBytes:(stripByteCounts at:stripNr) into:compressedStrip. |
|
1597 self class decompressCCITT3From:compressedStrip |
|
1598 into:data |
|
1599 startingAt:offset |
|
1600 count:width. |
|
1601 offset := offset + bytesPerStrip. |
|
1602 row := row + rowsPerStrip |
|
1603 ] |
|
1604 ! |
|
1605 |
|
1606 readJPEGTiffImageData |
|
1607 'TIFFReader: jpeg compression not implemented' errorPrintNL |
|
1608 ! |
|
1609 |
|
1610 readNeXTJPEGTiffImageData |
|
1611 'TIFFReader: jpeg compression not implemented' errorPrintNL |
|
1612 ! |
|
1613 |
|
1614 readCCITT3RLETiffImageData |
|
1615 'TIFFReader: ccitt mod Huffman (rle) compression not implemented' errorPrintNL. |
|
1616 ! |
|
1617 |
|
1618 readCCITT3RLEWTiffImageData |
|
1619 'TIFFReader: ccitt mod Huffman (rlew) compression not implemented' errorPrintNL. |
|
1620 ! |
|
1621 |
|
1622 readCCITTGroup4TiffImageData |
|
1623 'TIFFReader: ccitt group4 fax compression not implemented' errorPrintNL. |
|
1624 ! |
|
1625 |
|
1626 readNeXTRLE2TiffImageData |
|
1627 'TIFFReader: next 2bit rle compression not implemented' errorPrintNL. |
|
1628 ! |
|
1629 |
|
1630 readPackbitsTiffImageData |
|
1631 "had no samples yet - however, packbits decompression |
|
1632 is rather trivial to add ..." |
|
1633 |
|
1634 'TIFFReader: packbits compression not implemented' errorPrintNL |
|
1635 ! ! |
1628 ! ! |
|
1629 |
|
1630 !TIFFReader class methodsFor:'documentation'! |
|
1631 |
|
1632 version |
|
1633 ^ '$Header: /cvs/stx/stx/libview2/Attic/TIFFRdr.st,v 1.27 1995-12-07 11:38:46 cg Exp $' |
|
1634 ! ! |
|
1635 TIFFReader initialize! |