1010package tiff
1111
1212import (
13+ "bytes"
1314 "compress/zlib"
1415 "encoding/binary"
1516 "fmt"
1617 "image"
1718 "image/color"
19+ "image/draw"
1820 "io"
19- "io/ioutil"
2021 "math"
2122
2223 "github.com/hhrutter/lzw"
@@ -40,6 +41,17 @@ func (e UnsupportedError) Error() string {
4041
4142var errNoPixels = FormatError ("not enough pixel data" )
4243
44+ var app14Marker = []byte {
45+ 0xFF , 0xEE ,
46+ 0x00 , 0x0E ,
47+ 'A' , 'd' , 'o' , 'b' , 'e' ,
48+ 0x00 ,
49+ 0x64 , 0x00 ,
50+ 0x00 , 0x00 ,
51+ 0x00 , 0x00 ,
52+ 0x00 , // RGB
53+ }
54+
4355type decoder struct {
4456 r io.ReaderAt
4557 byteOrder binary.ByteOrder
@@ -48,6 +60,7 @@ type decoder struct {
4860 bpp uint
4961 features map [int ][]uint
5062 palette []color.Color
63+ tables []byte
5164
5265 buf []byte
5366 off int // Current offset in buf.
@@ -173,7 +186,19 @@ func (d *decoder) parseIFD(p []byte) (int, error) {
173186 return 0 , UnsupportedError ("sample format" )
174187 }
175188 }
189+ case tJPEGTables :
190+ // See Adobe Photoshop® TIFF Technical Notes.
191+ datatype := d .byteOrder .Uint16 (p [2 :4 ])
192+ if dt := int (datatype ); dt != 7 {
193+ return 0 , UnsupportedError ("IFD entry datatype" )
194+ }
195+ size := d .byteOrder .Uint32 (p [4 :8 ])
196+ d .tables = make ([]byte , size - 4 )
197+ if _ , err := d .r .ReadAt (d .tables , int64 (d .byteOrder .Uint32 (p [8 :12 ]))+ 2 ); err != nil {
198+ return 0 , err
199+ }
176200 }
201+
177202 return int (tag ), nil
178203}
179204
@@ -411,7 +436,7 @@ func (d *decoder) decode(dst image.Image, xmin, ymin, xmax, ymax int) error {
411436 return nil
412437}
413438
414- func newDecoder (r io.Reader ) (* decoder , error ) {
439+ func newDecoderAt (r io.Reader , ifdOffset int64 ) (* decoder , error ) {
415440 d := & decoder {
416441 r : newReaderAt (r ),
417442 features : make (map [int ][]uint ),
@@ -430,7 +455,9 @@ func newDecoder(r io.Reader) (*decoder, error) {
430455 return nil , FormatError ("malformed header" )
431456 }
432457
433- ifdOffset := int64 (d .byteOrder .Uint32 (p [4 :8 ]))
458+ if ifdOffset == 0 {
459+ ifdOffset = int64 (d .byteOrder .Uint32 (p [4 :8 ]))
460+ }
434461
435462 // The first two bytes contain the number of entries (12 bytes each).
436463 if _ , err := d .r .ReadAt (p [0 :2 ], ifdOffset ); err != nil {
@@ -559,7 +586,17 @@ func newDecoder(r io.Reader) (*decoder, error) {
559586// DecodeConfig returns the color model and dimensions of a TIFF image without
560587// decoding the entire image.
561588func DecodeConfig (r io.Reader ) (image.Config , error ) {
562- d , err := newDecoder (r )
589+ d , err := newDecoderAt (r , 0 )
590+ if err != nil {
591+ return image.Config {}, err
592+ }
593+ return d .config , nil
594+ }
595+
596+ // DecodeConfig returns the color model and dimensions of a TIFF image at ifdOffset without
597+ // decoding the entire image.
598+ func DecodeConfigAt (r io.Reader , ifdOffset int64 ) (image.Config , error ) {
599+ d , err := newDecoderAt (r , ifdOffset )
563600 if err != nil {
564601 return image.Config {}, err
565602 }
@@ -573,14 +610,83 @@ func ccittFillOrder(tiffFillOrder uint) ccitt.Order {
573610 return ccitt .MSB
574611}
575612
576- // Decode reads a TIFF image from r and returns it as an image.Image.
577- // The type of Image returned depends on the contents of the TIFF.
578- func Decode (r io.Reader ) (img image.Image , err error ) {
579- d , err := newDecoder (r )
613+ func (d * decoder ) copyStrip (dst image.Image , strip image.Image , x , y int ) {
614+ switch d .mode {
615+ case mGray , mGrayInvert :
616+ if d .bpp == 16 {
617+ draw .Draw (dst .(* image.Gray16 ), image .Rect (x , y , x + strip .Bounds ().Dx (), y + strip .Bounds ().Dy ()), strip , image.Point {}, draw .Over )
618+ } else {
619+ draw .Draw (dst .(* image.Gray ), image .Rect (x , y , x + strip .Bounds ().Dx (), y + strip .Bounds ().Dy ()), strip , image.Point {}, draw .Over )
620+ }
621+ case mPaletted :
622+ draw .Draw (dst .(* image.Paletted ), image .Rect (x , y , x + strip .Bounds ().Dx (), y + strip .Bounds ().Dy ()), strip , image.Point {}, draw .Over )
623+ case mNRGBA :
624+ if d .bpp == 16 {
625+ draw .Draw (dst .(* image.NRGBA64 ), image .Rect (x , y , x + strip .Bounds ().Dx (), y + strip .Bounds ().Dy ()), strip , image.Point {}, draw .Over )
626+ } else {
627+ draw .Draw (dst .(* image.NRGBA ), image .Rect (x , y , x + strip .Bounds ().Dx (), y + strip .Bounds ().Dy ()), strip , image.Point {}, draw .Over )
628+ }
629+ case mRGB , mRGBA :
630+ if d .bpp == 16 {
631+ draw .Draw (dst .(* image.RGBA64 ), image .Rect (x , y , x + strip .Bounds ().Dx (), y + strip .Bounds ().Dy ()), strip , image.Point {}, draw .Over )
632+ } else {
633+ draw .Draw (dst .(* image.RGBA ), image .Rect (x , y , x + strip .Bounds ().Dx (), y + strip .Bounds ().Dy ()), strip , image.Point {}, draw .Over )
634+ }
635+ case mCMYK :
636+ draw .Draw (dst .(* image.CMYK ), image .Rect (x , y , x + strip .Bounds ().Dx (), y + strip .Bounds ().Dy ()), strip , image.Point {}, draw .Over )
637+ }
638+ }
639+
640+ func (d * decoder ) prepJPEG (offset , n int64 , needAPP14 , needTables bool ) (io.Reader , error ) {
641+ bb , err := io .ReadAll (io .NewSectionReader (d .r , offset , n ))
580642 if err != nil {
581- return
643+ return nil , err
644+ }
645+ if len (bb ) < 2 || bb [0 ] != 0xFF || bb [1 ] != 0xD8 {
646+ return nil , FormatError ("corrupt JPG stream" )
582647 }
583648
649+ if needAPP14 {
650+ var buf bytes.Buffer
651+ buf .Write (bb [:2 ])
652+ buf .Write (app14Marker )
653+ buf .Write (bb [2 :])
654+ bb = buf .Bytes ()
655+ }
656+
657+ if needTables {
658+ sosIndex := bytes .Index (bb , []byte {0xFF , 0xDA })
659+ if sosIndex == - 1 {
660+ return nil , FormatError ("corrupt JPG stream" )
661+ }
662+ var buf bytes.Buffer
663+ buf .Write (bb [:sosIndex ])
664+ buf .Write (d .tables )
665+ buf .Write (bb [sosIndex :])
666+ bb = buf .Bytes ()
667+ }
668+
669+ return bytes .NewReader (bb ), nil
670+ }
671+
672+ func (d * decoder ) decodeJPGOld (img image.Image , offset , n int64 , i , j , blockWidth , blockHeight int ) error {
673+ var rd io.Reader = io .NewSectionReader (d .r , offset , n )
674+ if len (d .features [tBitsPerSample ]) == 4 && d .firstVal (tExtraSamples ) > 0 {
675+ var err error
676+ rd , err = d .prepJPEG (offset , n , true , false )
677+ if err != nil {
678+ return err
679+ }
680+ }
681+ img0 , _ , err := image .Decode (rd )
682+ if err != nil {
683+ return err
684+ }
685+ d .copyStrip (img , img0 , i * blockWidth , j * blockHeight )
686+ return nil
687+ }
688+
689+ func decode (d * decoder ) (img image.Image , err error ) {
584690 blockPadding := false
585691 blockWidth := d .config .Width
586692 blockHeight := d .config .Height
@@ -689,24 +795,47 @@ func Decode(r io.Reader) (img image.Image, err error) {
689795 inv := d .firstVal (tPhotometricInterpretation ) == pWhiteIsZero
690796 order := ccittFillOrder (d .firstVal (tFillOrder ))
691797 r := ccitt .NewReader (io .NewSectionReader (d .r , offset , n ), order , ccitt .Group3 , blkW , blkH , & ccitt.Options {Invert : inv , Align : false })
692- d .buf , err = ioutil .ReadAll (r )
798+ d .buf , err = io .ReadAll (r )
693799 case cG4 :
694800 inv := d .firstVal (tPhotometricInterpretation ) == pWhiteIsZero
695801 order := ccittFillOrder (d .firstVal (tFillOrder ))
696802 r := ccitt .NewReader (io .NewSectionReader (d .r , offset , n ), order , ccitt .Group4 , blkW , blkH , & ccitt.Options {Invert : inv , Align : false })
697- d .buf , err = ioutil .ReadAll (r )
803+ d .buf , err = io .ReadAll (r )
698804 case cLZW :
699805 r := lzw .NewReader (io .NewSectionReader (d .r , offset , n ), true )
700- d .buf , err = ioutil .ReadAll (r )
806+ d .buf , err = io .ReadAll (r )
701807 r .Close ()
702808 case cDeflate , cDeflateOld :
703809 var r io.ReadCloser
704810 r , err = zlib .NewReader (io .NewSectionReader (d .r , offset , n ))
705811 if err != nil {
706812 return nil , err
707813 }
708- d .buf , err = ioutil .ReadAll (r )
814+ d .buf , err = io .ReadAll (r )
709815 r .Close ()
816+ case cJPEGOld :
817+ if err := d .decodeJPGOld (img , offset , n , i , j , blockWidth , blockHeight ); err != nil {
818+ return nil , err
819+ }
820+ continue
821+ case cJPEG :
822+ if len (d .tables ) == 0 {
823+ if err := d .decodeJPGOld (img , offset , n , i , j , blockWidth , blockHeight ); err != nil {
824+ return nil , err
825+ }
826+ continue
827+ }
828+ needAPP14 := len (d .features [tBitsPerSample ]) == 4 && d .firstVal (tExtraSamples ) > 0
829+ rd , err := d .prepJPEG (offset , n , needAPP14 , true )
830+ if err != nil {
831+ return nil , err
832+ }
833+ img0 , _ , err := image .Decode (rd )
834+ if err != nil {
835+ return nil , err
836+ }
837+ d .copyStrip (img , img0 , i * blockWidth , j * blockHeight )
838+ continue
710839 case cPackBits :
711840 d .buf , err = unpackBits (io .NewSectionReader (d .r , offset , n ))
712841 default :
@@ -729,6 +858,26 @@ func Decode(r io.Reader) (img image.Image, err error) {
729858 return
730859}
731860
861+ // Decode reads a TIFF image from r and returns it as an image.Image.
862+ // The type of Image returned depends on the contents of the TIFF.
863+ func Decode (r io.Reader ) (img image.Image , err error ) {
864+ d , err := newDecoderAt (r , 0 )
865+ if err != nil {
866+ return
867+ }
868+ return decode (d )
869+ }
870+
871+ // DecodeAt reads a TIFF image from r at ifdOffset and returns it as an image.Image.
872+ // The type of Image returned depends on the contents of the TIFF.
873+ func DecodeAt (r io.Reader , ifdOffset int64 ) (img image.Image , err error ) {
874+ d , err := newDecoderAt (r , ifdOffset )
875+ if err != nil {
876+ return
877+ }
878+ return decode (d )
879+ }
880+
732881func init () {
733882 image .RegisterFormat ("tiff" , leHeader , Decode , DecodeConfig )
734883 image .RegisterFormat ("tiff" , beHeader , Decode , DecodeConfig )
0 commit comments