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 "bytes" |
| 9 "compress/zlib" |
8 "encoding/binary" | 10 "encoding/binary" |
9 "image" | 11 "image" |
10 "io" | 12 "io" |
11 "sort" | 13 "sort" |
12 ) | 14 ) |
13 | 15 |
14 // The TIFF format allows to choose the order of the different elements freely. | 16 // The TIFF format allows to choose the order of the different elements freely. |
15 // The basic structure of a TIFF file written by this package is: | 17 // The basic structure of a TIFF file written by this package is: |
16 // | 18 // |
17 // 1. Header (8 bytes). | 19 // 1. Header (8 bytes). |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
172 // types of images and compressors. For example, it works well for | 174 // types of images and compressors. For example, it works well for |
173 // photos with Deflate compression. | 175 // photos with Deflate compression. |
174 Predictor bool | 176 Predictor bool |
175 } | 177 } |
176 | 178 |
177 // Encode writes the image m to w. opt determines the options used for | 179 // Encode writes the image m to w. opt determines the options used for |
178 // encoding, such as the compression type. If opt is nil, an uncompressed | 180 // encoding, such as the compression type. If opt is nil, an uncompressed |
179 // image is written. | 181 // image is written. |
180 func Encode(w io.Writer, m image.Image, opt *Options) error { | 182 func Encode(w io.Writer, m image.Image, opt *Options) error { |
181 predictor := false | 183 predictor := false |
182 » compression := Uncompressed | 184 » compression := uint32(cNone) |
183 if opt != nil { | 185 if opt != nil { |
184 predictor = opt.Predictor | 186 predictor = opt.Predictor |
185 » » compression = opt.Compression | 187 » » compression = opt.Compression.specValue() |
186 » } | |
187 » if compression != Uncompressed { | |
188 » » return UnsupportedError("compression type") | |
189 } | 188 } |
190 | 189 |
191 var extrasamples uint32 | |
192 _, err := io.WriteString(w, leHeader) | 190 _, err := io.WriteString(w, leHeader) |
193 if err != nil { | 191 if err != nil { |
194 return err | 192 return err |
195 } | 193 } |
196 | 194 |
| 195 // Compressed data is written into a buffer first, so that we |
| 196 // know the compressed size. |
| 197 var buf bytes.Buffer |
| 198 // dst holds the destination for the pixel data of the image -- |
| 199 // either w or a writer to buf. |
| 200 var dst io.Writer |
| 201 // imageLen is the length of the pixel data in bytes. |
| 202 // The offset of the IFD is imageLen + 8 header bytes. |
| 203 var imageLen int |
197 bounds := m.Bounds() | 204 bounds := m.Bounds() |
198 width, height := bounds.Dx(), bounds.Dy() | 205 width, height := bounds.Dx(), bounds.Dy() |
199 » // imageLen is the length of the image data in bytes. | 206 |
200 » imageLen := width * height * 4 | 207 » switch compression { |
201 » ifdOffset := imageLen + 8 // 8 bytes for TIFF header. | 208 » case cNone: |
202 » err = binary.Write(w, enc, uint32(ifdOffset)) | 209 » » dst = w |
203 » if err != nil { | 210 » » // Write IFD offset before outputting pixel data. |
204 » » return err | 211 » » imageLen = width * height * 4 |
| 212 » » err = binary.Write(w, enc, uint32(imageLen+8)) |
| 213 » » if err != nil { |
| 214 » » » return err |
| 215 » » } |
| 216 » case cDeflate: |
| 217 » » dst = zlib.NewWriter(&buf) |
205 } | 218 } |
| 219 |
206 var pr uint32 = prNone | 220 var pr uint32 = prNone |
207 » extrasamples = 1 // Associated alpha (default). | 221 » var extrasamples uint32 = 1 // Associated alpha (default). |
208 if predictor { | 222 if predictor { |
209 pr = prHorizontal | 223 pr = prHorizontal |
210 » » err = writeImgData(w, m, predictor) | 224 » » err = writeImgData(dst, m, predictor) |
211 } else { | 225 } else { |
212 switch img := m.(type) { | 226 switch img := m.(type) { |
213 case *image.NRGBA: | 227 case *image.NRGBA: |
214 extrasamples = 2 // Unassociated alpha. | 228 extrasamples = 2 // Unassociated alpha. |
215 off := img.PixOffset(img.Rect.Min.X, img.Rect.Min.Y) | 229 off := img.PixOffset(img.Rect.Min.X, img.Rect.Min.Y) |
216 » » » err = writePix(w, img.Pix[off:], img.Rect.Dy(), 4*img.Re
ct.Dx(), img.Stride) | 230 » » » err = writePix(dst, img.Pix[off:], img.Rect.Dy(), 4*img.
Rect.Dx(), img.Stride) |
217 case *image.RGBA: | 231 case *image.RGBA: |
218 off := img.PixOffset(img.Rect.Min.X, img.Rect.Min.Y) | 232 off := img.PixOffset(img.Rect.Min.X, img.Rect.Min.Y) |
219 » » » err = writePix(w, img.Pix[off:], img.Rect.Dy(), 4*img.Re
ct.Dx(), img.Stride) | 233 » » » err = writePix(dst, img.Pix[off:], img.Rect.Dy(), 4*img.
Rect.Dx(), img.Stride) |
220 default: | 234 default: |
221 » » » err = writeImgData(w, m, predictor) | 235 » » » err = writeImgData(dst, m, predictor) |
222 } | 236 } |
223 } | 237 } |
224 if err != nil { | 238 if err != nil { |
225 return err | 239 return err |
226 } | 240 } |
227 | 241 |
228 » return writeIFD(w, ifdOffset, []ifdEntry{ | 242 » if compression != cNone { |
| 243 » » if err = dst.(io.Closer).Close(); err != nil { |
| 244 » » » return err |
| 245 » » } |
| 246 » » imageLen = buf.Len() |
| 247 » » if err = binary.Write(w, enc, uint32(imageLen+8)); err != nil { |
| 248 » » » return err |
| 249 » » } |
| 250 » » if _, err = buf.WriteTo(w); err != nil { |
| 251 » » » return err |
| 252 » » } |
| 253 » } |
| 254 |
| 255 » return writeIFD(w, imageLen+8, []ifdEntry{ |
229 {tImageWidth, dtShort, []uint32{uint32(width)}}, | 256 {tImageWidth, dtShort, []uint32{uint32(width)}}, |
230 {tImageLength, dtShort, []uint32{uint32(height)}}, | 257 {tImageLength, dtShort, []uint32{uint32(height)}}, |
231 {tBitsPerSample, dtShort, []uint32{8, 8, 8, 8}}, | 258 {tBitsPerSample, dtShort, []uint32{8, 8, 8, 8}}, |
232 » » {tCompression, dtShort, []uint32{cNone}}, | 259 » » {tCompression, dtShort, []uint32{compression}}, |
233 {tPhotometricInterpretation, dtShort, []uint32{pRGB}}, | 260 {tPhotometricInterpretation, dtShort, []uint32{pRGB}}, |
234 {tStripOffsets, dtLong, []uint32{8}}, | 261 {tStripOffsets, dtLong, []uint32{8}}, |
235 {tSamplesPerPixel, dtShort, []uint32{4}}, | 262 {tSamplesPerPixel, dtShort, []uint32{4}}, |
236 {tRowsPerStrip, dtShort, []uint32{uint32(height)}}, | 263 {tRowsPerStrip, dtShort, []uint32{uint32(height)}}, |
237 {tStripByteCounts, dtLong, []uint32{uint32(imageLen)}}, | 264 {tStripByteCounts, dtLong, []uint32{uint32(imageLen)}}, |
238 // There is currently no support for storing the image | 265 // There is currently no support for storing the image |
239 // resolution, so give a bogus value of 72x72 dpi. | 266 // resolution, so give a bogus value of 72x72 dpi. |
240 {tXResolution, dtRational, []uint32{72, 1}}, | 267 {tXResolution, dtRational, []uint32{72, 1}}, |
241 {tYResolution, dtRational, []uint32{72, 1}}, | 268 {tYResolution, dtRational, []uint32{72, 1}}, |
242 {tResolutionUnit, dtShort, []uint32{resPerInch}}, | 269 {tResolutionUnit, dtShort, []uint32{resPerInch}}, |
243 {tPredictor, dtShort, []uint32{pr}}, | 270 {tPredictor, dtShort, []uint32{pr}}, |
244 {tExtraSamples, dtShort, []uint32{extrasamples}}, | 271 {tExtraSamples, dtShort, []uint32{extrasamples}}, |
245 }) | 272 }) |
246 } | 273 } |
OLD | NEW |