Left: | ||
Right: |
OLD | NEW |
---|---|
1 // Copyright 2012 The Go Authors. All rights reserved. | 1 // Copyright 2012 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 package tiff | 5 package tiff |
6 | 6 |
7 import ( | 7 import ( |
8 "encoding/binary" | 8 "encoding/binary" |
9 "image" | 9 "image" |
10 "io" | 10 "io" |
(...skipping 29 matching lines...) Expand all Loading... | |
40 case dtShort: | 40 case dtShort: |
41 enc.PutUint16(p, uint16(d)) | 41 enc.PutUint16(p, uint16(d)) |
42 p = p[2:] | 42 p = p[2:] |
43 case dtLong, dtRational: | 43 case dtLong, dtRational: |
44 enc.PutUint32(p, uint32(d)) | 44 enc.PutUint32(p, uint32(d)) |
45 p = p[4:] | 45 p = p[4:] |
46 } | 46 } |
47 } | 47 } |
48 } | 48 } |
49 | 49 |
50 type ifd []ifdEntry | 50 type byTag []ifdEntry |
51 | 51 |
52 func (d ifd) Len() int { | 52 func (d byTag) Len() int { return len(d) } |
53 » return len(d) | 53 func (d byTag) Less(i, j int) bool { return d[i].tag < d[j].tag } |
54 } | 54 func (d byTag) Swap(i, j int) { d[i], d[j] = d[j], d[i] } |
55 | 55 |
56 func (d ifd) Less(i, j int) bool { | 56 func writeImgData(w io.Writer, m image.Image) error { |
57 » return d[i].tag < d[j].tag | 57 » b := m.Bounds() |
bsiegert
2012/03/05 13:21:14
Now that I think about it, this variable should ma
nigeltao
2012/03/05 23:35:04
Done.
| |
58 } | |
59 | |
60 func (d ifd) Swap(i, j int) { | |
61 » d[i], d[j] = d[j], d[i] | |
62 } | |
63 | |
64 type encoder struct { | |
65 » ifd ifd | |
66 » img image.Image | |
67 » imageLen int // Length of the image in bytes. | |
68 } | |
69 | |
70 func newEncoder(m image.Image) *encoder { | |
71 » width := m.Bounds().Dx() | |
72 » height := m.Bounds().Dy() | |
73 » imageLen := width * height * 4 | |
74 » return &encoder{ | |
75 » » img: m, | |
76 » » // For uncompressed images, imageLen is known in advance. | |
77 » » // For compressed images, we would need to write the image | |
78 » » // data in a buffer here to get its length. | |
79 » » imageLen: imageLen, | |
80 » » ifd: ifd{ | |
81 » » » {tImageWidth, dtShort, []uint32{uint32(width)}}, | |
82 » » » {tImageLength, dtShort, []uint32{uint32(height)}}, | |
83 » » » {tBitsPerSample, dtShort, []uint32{8, 8, 8, 8}}, | |
84 » » » {tCompression, dtShort, []uint32{cNone}}, | |
85 » » » {tPhotometricInterpretation, dtShort, []uint32{pRGB}}, | |
86 » » » {tStripOffsets, dtLong, []uint32{8}}, | |
87 » » » {tSamplesPerPixel, dtShort, []uint32{4}}, | |
88 » » » {tRowsPerStrip, dtShort, []uint32{uint32(height)}}, | |
89 » » » {tStripByteCounts, dtLong, []uint32{uint32(imageLen)}}, | |
90 » » » // There is currently no support for storing the image | |
91 » » » // resolution, so give a bogus value of 72x72 dpi. | |
92 » » » {tXResolution, dtRational, []uint32{72, 1}}, | |
93 » » » {tYResolution, dtRational, []uint32{72, 1}}, | |
94 » » » {tResolutionUnit, dtShort, []uint32{resPerInch}}, | |
95 » » » {tExtraSamples, dtShort, []uint32{1}}, // RGBA. | |
96 » » }, | |
97 » } | |
98 } | |
99 | |
100 func (e *encoder) writeImgData(w io.Writer) error { | |
101 » b := e.img.Bounds() | |
102 buf := make([]byte, 4*b.Dx()) | 58 buf := make([]byte, 4*b.Dx()) |
103 for y := b.Min.Y; y < b.Max.Y; y++ { | 59 for y := b.Min.Y; y < b.Max.Y; y++ { |
104 i := 0 | 60 i := 0 |
105 for x := b.Min.X; x < b.Max.X; x++ { | 61 for x := b.Min.X; x < b.Max.X; x++ { |
106 » » » r, g, b, a := e.img.At(x, y).RGBA() | 62 » » » r, g, b, a := m.At(x, y).RGBA() |
107 buf[i+0] = uint8(r >> 8) | 63 buf[i+0] = uint8(r >> 8) |
108 buf[i+1] = uint8(g >> 8) | 64 buf[i+1] = uint8(g >> 8) |
109 buf[i+2] = uint8(b >> 8) | 65 buf[i+2] = uint8(b >> 8) |
110 buf[i+3] = uint8(a >> 8) | 66 buf[i+3] = uint8(a >> 8) |
111 i += 4 | 67 i += 4 |
112 } | 68 } |
113 if _, err := w.Write(buf); err != nil { | 69 if _, err := w.Write(buf); err != nil { |
114 return err | 70 return err |
115 } | 71 } |
116 } | 72 } |
117 return nil | 73 return nil |
118 } | 74 } |
119 | 75 |
120 func (e *encoder) writeIFD(w io.Writer) error { | 76 func writeIFD(w io.Writer, ifdOffset int, d []ifdEntry) error { |
121 var buf [ifdLen]byte | 77 var buf [ifdLen]byte |
122 // Make space for "pointer area" containing IFD entry data | 78 // Make space for "pointer area" containing IFD entry data |
123 // longer than 4 bytes. | 79 // longer than 4 bytes. |
124 parea := make([]byte, 1024) | 80 parea := make([]byte, 1024) |
125 » pstart := int(e.imageLen) + 8 + (ifdLen * len(e.ifd)) + 6 | 81 » pstart := ifdOffset + ifdLen*len(d) + 6 |
126 var o int // Current offset in parea. | 82 var o int // Current offset in parea. |
127 | 83 |
128 // The IFD has to be written with the tags in ascending order. | 84 // The IFD has to be written with the tags in ascending order. |
129 » sort.Sort(e.ifd) | 85 » sort.Sort(byTag(d)) |
130 | 86 |
131 // Write the number of entries in this IFD. | 87 // Write the number of entries in this IFD. |
132 » if err := binary.Write(w, enc, uint16(len(e.ifd))); err != nil { | 88 » if err := binary.Write(w, enc, uint16(len(d))); err != nil { |
133 return err | 89 return err |
134 } | 90 } |
135 » for _, ent := range e.ifd { | 91 » for _, ent := range d { |
136 enc.PutUint16(buf[0:2], uint16(ent.tag)) | 92 enc.PutUint16(buf[0:2], uint16(ent.tag)) |
137 enc.PutUint16(buf[2:4], uint16(ent.datatype)) | 93 enc.PutUint16(buf[2:4], uint16(ent.datatype)) |
138 count := uint32(len(ent.data)) | 94 count := uint32(len(ent.data)) |
139 if ent.datatype == dtRational { | 95 if ent.datatype == dtRational { |
140 count /= 2 | 96 count /= 2 |
141 } | 97 } |
142 enc.PutUint32(buf[4:8], count) | 98 enc.PutUint32(buf[4:8], count) |
143 datalen := int(count * lengths[ent.datatype]) | 99 datalen := int(count * lengths[ent.datatype]) |
144 if datalen <= 4 { | 100 if datalen <= 4 { |
145 ent.putData(buf[8:12]) | 101 ent.putData(buf[8:12]) |
(...skipping 17 matching lines...) Expand all Loading... | |
163 } | 119 } |
164 // The IFD ends with the offset of the next IFD in the file, | 120 // The IFD ends with the offset of the next IFD in the file, |
165 // or zero if it is the last one (page 14). | 121 // or zero if it is the last one (page 14). |
166 if err := binary.Write(w, enc, uint32(0)); err != nil { | 122 if err := binary.Write(w, enc, uint32(0)); err != nil { |
167 return err | 123 return err |
168 } | 124 } |
169 _, err := w.Write(parea[:o]) | 125 _, err := w.Write(parea[:o]) |
170 return err | 126 return err |
171 } | 127 } |
172 | 128 |
173 func (e *encoder) encode(w io.Writer) error { | 129 // Encode writes the image m to w in uncompressed RGBA format. |
130 func Encode(w io.Writer, m image.Image) error { | |
131 » b := m.Bounds() | |
132 » width := b.Dx() | |
133 » height := b.Dy() | |
134 » // imageLen is the length of the image data in bytes. | |
135 » imageLen := width * height * 4 | |
136 | |
174 _, err := io.WriteString(w, leHeader) | 137 _, err := io.WriteString(w, leHeader) |
175 if err != nil { | 138 if err != nil { |
176 return err | 139 return err |
177 } | 140 } |
178 | 141 |
179 » ifdOffset := e.imageLen + 8 // 8 bytes for TIFF header. | 142 » ifdOffset := imageLen + 8 // 8 bytes for TIFF header. |
bsiegert
2012/03/05 13:21:14
Move the definition of imageLen before this line.
nigeltao
2012/03/05 23:35:04
Done.
| |
180 err = binary.Write(w, enc, uint32(ifdOffset)) | 143 err = binary.Write(w, enc, uint32(ifdOffset)) |
181 if err != nil { | 144 if err != nil { |
182 return err | 145 return err |
183 } | 146 } |
184 » err = e.writeImgData(w) | 147 » err = writeImgData(w, m) |
185 if err != nil { | 148 if err != nil { |
186 return err | 149 return err |
187 } | 150 } |
188 » return e.writeIFD(w) | 151 » return writeIFD(w, ifdOffset, []ifdEntry{ |
152 » » {tImageWidth, dtShort, []uint32{uint32(width)}}, | |
153 » » {tImageLength, dtShort, []uint32{uint32(height)}}, | |
154 » » {tBitsPerSample, dtShort, []uint32{8, 8, 8, 8}}, | |
155 » » {tCompression, dtShort, []uint32{cNone}}, | |
156 » » {tPhotometricInterpretation, dtShort, []uint32{pRGB}}, | |
157 » » {tStripOffsets, dtLong, []uint32{8}}, | |
158 » » {tSamplesPerPixel, dtShort, []uint32{4}}, | |
159 » » {tRowsPerStrip, dtShort, []uint32{uint32(height)}}, | |
160 » » {tStripByteCounts, dtLong, []uint32{uint32(imageLen)}}, | |
161 » » // There is currently no support for storing the image | |
162 » » // resolution, so give a bogus value of 72x72 dpi. | |
163 » » {tXResolution, dtRational, []uint32{72, 1}}, | |
164 » » {tYResolution, dtRational, []uint32{72, 1}}, | |
165 » » {tResolutionUnit, dtShort, []uint32{resPerInch}}, | |
166 » » {tExtraSamples, dtShort, []uint32{1}}, // RGBA. | |
167 » }) | |
189 } | 168 } |
190 | |
191 // Encode writes the image m to w in uncompressed RGBA format. | |
192 func Encode(w io.Writer, m image.Image) error { | |
193 return newEncoder(m).encode(w) | |
194 } | |
OLD | NEW |