Left: | ||
Right: |
OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2011 The Go Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style | |
3 // license that can be found in the LICENSE file. | |
4 | |
5 package jpeg | |
6 | |
7 import ( | |
8 "bufio" | |
9 "image" | |
10 "image/ycbcr" | |
11 "io" | |
12 "os" | |
13 ) | |
14 | |
15 // min returns the minimum of two integers. | |
16 func min(x, y int) int { | |
17 if x < y { | |
18 return x | |
19 } | |
20 return y | |
21 } | |
22 | |
23 // div returns a/b rounded to the nearest integer, instead of rounded to zero. | |
24 func div(a int, b int) int { | |
25 if a >= 0 { | |
26 return (a + (b >> 1)) / b | |
27 } | |
28 return -((-a + (b >> 1)) / b) | |
29 } | |
30 | |
31 // bitCount counts the number of bits needed to hold an integer. | |
32 var bitCount = [256]byte{ | |
33 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, | |
34 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, | |
35 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, | |
36 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, | |
37 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | |
38 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | |
39 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | |
40 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | |
41 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, | |
42 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, | |
43 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, | |
44 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, | |
45 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, | |
46 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, | |
47 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, | |
48 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, | |
49 } | |
50 | |
51 type quantIndex int | |
52 | |
53 const ( | |
54 quantIndexLuminance quantIndex = iota | |
55 quantIndexChrominance | |
56 nQuantIndex | |
57 ) | |
58 | |
59 // unscaledQuant are the unscaled quantization tables. Each encoder copies and | |
60 // scales the tables according to its quality parameter. | |
61 var unscaledQuant = [nQuantIndex][blockSize]byte{ | |
62 // Luminance. | |
63 { | |
64 16, 11, 10, 16, 24, 40, 51, 61, | |
65 12, 12, 14, 19, 26, 58, 60, 55, | |
66 14, 13, 16, 24, 40, 57, 69, 56, | |
67 14, 17, 22, 29, 51, 87, 80, 62, | |
68 18, 22, 37, 56, 68, 109, 103, 77, | |
69 24, 35, 55, 64, 81, 104, 113, 92, | |
70 49, 64, 78, 87, 103, 121, 120, 101, | |
71 72, 92, 95, 98, 112, 100, 103, 99, | |
72 }, | |
73 // Chrominance. | |
74 { | |
75 17, 18, 24, 47, 99, 99, 99, 99, | |
76 18, 21, 26, 66, 99, 99, 99, 99, | |
77 24, 26, 56, 99, 99, 99, 99, 99, | |
78 47, 66, 99, 99, 99, 99, 99, 99, | |
79 99, 99, 99, 99, 99, 99, 99, 99, | |
80 99, 99, 99, 99, 99, 99, 99, 99, | |
81 99, 99, 99, 99, 99, 99, 99, 99, | |
82 99, 99, 99, 99, 99, 99, 99, 99, | |
83 }, | |
84 } | |
85 | |
86 type huffIndex int | |
87 | |
88 const ( | |
89 huffIndexLuminanceDC huffIndex = iota | |
90 huffIndexLuminanceAC | |
91 huffIndexChrominanceDC | |
92 huffIndexChrominanceAC | |
93 nHuffIndex | |
94 ) | |
95 | |
96 // huffmanSpec specifies a Huffman encoding. | |
97 type huffmanSpec struct { | |
98 // count[i] is the number of codes of length i bits. | |
99 count [16]byte | |
100 // value[i] is the decoded value of the i'th codeword. | |
101 value []byte | |
102 } | |
103 | |
104 // theHuffmanSpec is the Huffman encoding specifications. | |
105 // This encoder uses the same Huffman encoding for all images. | |
106 var theHuffmanSpec = [nHuffIndex]huffmanSpec{ | |
107 // Luminance DC. | |
108 { | |
109 [16]byte{0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, | |
110 []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, | |
111 }, | |
112 // Luminance AC. | |
113 { | |
114 [16]byte{0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 125}, | |
115 []byte{ | |
116 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, | |
117 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, | |
118 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, | |
119 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, | |
120 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, | |
121 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, | |
122 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, | |
123 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, | |
124 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, | |
125 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, | |
126 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, | |
127 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, | |
128 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, | |
129 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, | |
130 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, | |
131 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, | |
132 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, | |
133 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, | |
134 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, | |
135 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, | |
136 0xf9, 0xfa, | |
137 }, | |
138 }, | |
139 // Chrominance DC. | |
140 { | |
141 [16]byte{0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}, | |
142 []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, | |
143 }, | |
144 // Chrominance AC. | |
145 { | |
146 [16]byte{0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 119}, | |
147 []byte{ | |
148 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, | |
149 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, | |
150 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, | |
151 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, | |
152 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, | |
153 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, | |
154 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, | |
155 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, | |
156 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, | |
157 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, | |
158 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, | |
159 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, | |
160 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, | |
161 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, | |
162 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, | |
163 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, | |
164 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, | |
165 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, | |
166 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, | |
167 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, | |
168 0xf9, 0xfa, | |
169 }, | |
170 }, | |
171 } | |
172 | |
173 // huffmanLUT is a compiled look-up table representation of a huffmanSpec. | |
174 // Each value maps to an uint32 of which the 8 most significant bits hold the | |
r
2011/04/18 19:30:42
s/an/a/
nigeltao
2011/04/19 00:47:06
Done.
| |
175 // codeword size in bits and the 24 least significant bits hold the codeword. | |
176 // The maximum codeword size is 16 bits. | |
177 type huffmanLUT []uint32 | |
178 | |
179 func (h *huffmanLUT) init(s huffmanSpec) { | |
180 maxValue := 0 | |
181 for _, v := range s.value { | |
182 if int(v) > maxValue { | |
183 maxValue = int(v) | |
184 } | |
185 } | |
186 *h = make([]uint32, maxValue+1) | |
187 code, k := uint32(0), 0 | |
188 for i := 0; i < len(s.count); i++ { | |
189 nBits := uint32(i+1) << 24 | |
190 for j := uint8(0); j < s.count[i]; j++ { | |
191 (*h)[s.value[k]] = nBits | code | |
192 code++ | |
193 k++ | |
194 } | |
195 code <<= 1 | |
196 } | |
197 } | |
198 | |
199 // theHuffmanLUT are compiled representations of theHuffmanSpec. | |
200 var theHuffmanLUT [4]huffmanLUT | |
201 | |
202 func init() { | |
203 for i, s := range theHuffmanSpec { | |
204 theHuffmanLUT[i].init(s) | |
205 } | |
206 } | |
207 | |
208 // writer is a buffered writer. | |
209 type writer interface { | |
210 Flush() os.Error | |
211 Write([]byte) (int, os.Error) | |
212 WriteByte(byte) os.Error | |
213 WriteString(string) (int, os.Error) | |
214 } | |
215 | |
216 // An encoder wraps a writer's methods to save the first returned error as | |
217 // e.err and return void. | |
r
2011/04/18 19:30:42
void?
nigeltao
2011/04/19 00:47:06
Rewritten.
| |
218 | |
219 func (e *encoder) flush() { | |
220 if e.err != nil { | |
221 return | |
222 } | |
223 e.err = e.w.Flush() | |
224 } | |
225 | |
226 func (e *encoder) write(p []byte) { | |
227 if e.err != nil { | |
228 return | |
229 } | |
230 _, e.err = e.w.Write(p) | |
231 } | |
232 | |
233 func (e *encoder) writeByte(b byte) { | |
234 if e.err != nil { | |
235 return | |
236 } | |
237 e.err = e.w.WriteByte(b) | |
238 } | |
239 | |
240 func (e *encoder) writeString(s string) { | |
241 if e.err != nil { | |
242 return | |
243 } | |
244 _, e.err = e.w.WriteString(s) | |
245 } | |
246 | |
247 // encoder encodes an image to the JPEG format. | |
r
2011/04/18 19:30:42
move this above its methods and combine the commen
nigeltao
2011/04/19 00:47:06
Done.
| |
248 type encoder struct { | |
249 // w is the writer to write to. err is the first error encountered | |
250 // during writing. | |
251 w writer | |
252 err os.Error | |
253 // bits and nBits are accumulated bits to write to w. | |
254 bits uint32 | |
255 nBits uint8 | |
256 // quant is the scaled quantization tables. | |
257 quant [nQuantIndex][blockSize]byte | |
258 } | |
259 | |
260 // emit emits the least significant nBits bits of bits to the bitstream. | |
r
2011/04/18 19:30:42
nBits bits of bits to the bits. wow.
| |
261 // The precondition is bits < 1<<nBits && nBits <= 16. | |
262 func (e *encoder) emit(bits uint32, nBits uint8) { | |
263 nBits += e.nBits | |
264 bits <<= 32 - nBits | |
265 bits |= e.bits | |
266 for nBits >= 8 { | |
267 b := uint8(bits >> 24) | |
268 e.writeByte(b) | |
269 if b == 255 { | |
270 e.writeByte(0x00) | |
271 } | |
272 bits <<= 8 | |
273 nBits -= 8 | |
274 } | |
275 e.bits, e.nBits = bits, nBits | |
276 } | |
277 | |
278 // emitHuff emits the given value with the given Huffman encoder. | |
279 func (e *encoder) emitHuff(h huffIndex, value int) { | |
280 x := theHuffmanLUT[h][value] | |
281 e.emit(x&(1<<24-1), uint8(x>>24)) | |
282 } | |
283 | |
284 // emitHuffRLE emits a run of runLength copies of value encoded with the given | |
285 // Huffman encoder. | |
286 func (e *encoder) emitHuffRLE(h huffIndex, runLength, value int) { | |
287 a, b := value, value | |
288 if a < 0 { | |
289 a, b = -value, value-1 | |
290 } | |
291 var nBits uint8 | |
292 if a < 0x100 { | |
293 nBits = bitCount[a] | |
294 } else { | |
295 nBits = 8 + bitCount[a>>8] | |
296 } | |
297 e.emitHuff(h, runLength<<4|int(nBits)) | |
298 if nBits > 0 { | |
299 e.emit(uint32(b)&(1<<nBits-1), nBits) | |
300 } | |
301 } | |
302 | |
303 // writeMarkerHeader writes the header for a maker with the given length. | |
r
2011/04/18 19:30:42
s/maker/marker/
nigeltao
2011/04/19 00:47:06
Done.
| |
304 func (e *encoder) writeMarkerHeader(marker uint8, markerlen int) { | |
305 e.writeByte(0xff) | |
306 e.writeByte(marker) | |
307 e.writeByte(uint8(markerlen >> 8)) | |
308 e.writeByte(uint8(markerlen & 0xff)) | |
r
2011/04/18 19:30:42
this is a fair bit of overhead. we could put a [4]
nigeltao
2011/04/19 00:47:06
Done.
| |
309 } | |
310 | |
311 // writeDQT writes the Define Quantization Table marker. | |
312 func (e *encoder) writeDQT() { | |
313 markerlen := 2 | |
314 for _, q := range e.quant { | |
315 markerlen += 1 + len(q) | |
316 } | |
317 e.writeMarkerHeader(dqtMarker, markerlen) | |
318 for i, q := range e.quant { | |
319 e.writeByte(uint8(i)) | |
320 e.write(q[:]) | |
321 } | |
322 } | |
323 | |
324 // writeSOF0 writes the Start Of Frame (Baseline) marker. | |
325 func (e *encoder) writeSOF0(size image.Point) { | |
326 markerlen := 8 + 3*nComponent | |
327 e.writeMarkerHeader(sof0Marker, markerlen) | |
328 e.writeByte(8) // 8-bit color. | |
329 e.writeByte(uint8(size.Y >> 8)) | |
330 e.writeByte(uint8(size.Y & 0xff)) | |
331 e.writeByte(uint8(size.X >> 8)) | |
332 e.writeByte(uint8(size.X & 0xff)) | |
r
2011/04/18 19:30:42
ditto.
nigeltao
2011/04/19 00:47:06
Done.
| |
333 e.writeByte(nComponent) | |
334 for i := 0; i < nComponent; i++ { | |
335 e.writeByte(uint8(i + 1)) | |
336 // We use 4:2:0 chroma subsampling. | |
337 e.writeByte("\x22\x11\x11"[i]) | |
338 e.writeByte("\x00\x01\x01"[i]) | |
r
2011/04/18 19:30:42
ditto
nigeltao
2011/04/19 00:47:06
Done.
| |
339 } | |
340 } | |
341 | |
342 // writeDHT writes the Define Huffman Table marker. | |
343 func (e *encoder) writeDHT() { | |
344 markerlen := 2 | |
345 for _, s := range theHuffmanSpec { | |
346 markerlen += 1 + 16 + len(s.value) | |
347 } | |
348 e.writeMarkerHeader(dhtMarker, markerlen) | |
349 for i, s := range theHuffmanSpec { | |
350 e.writeByte("\x00\x10\x01\x11"[i]) | |
351 e.write(s.count[:]) | |
352 e.write(s.value) | |
r
2011/04/18 19:30:42
ditto
nigeltao
2011/04/19 00:47:06
I don't think this applies here; s.value is a slic
| |
353 } | |
354 } | |
355 | |
356 // writeBlock writes a block of pixel data using the given quantization table, | |
357 // returning the post-quantized DC value of the DCT-transformed block. | |
358 func (e *encoder) writeBlock(b *block, q quantIndex, prevDC int) int { | |
359 fdct(b) | |
360 // Emit the DC delta. | |
361 dc := div(b[0], (8 * int(e.quant[q][0]))) | |
362 e.emitHuffRLE(huffIndex(2*q+0), 0, dc-prevDC) | |
363 // Emit the AC components. | |
364 h, runLength := huffIndex(2*q+1), 0 | |
365 for k := 1; k < blockSize; k++ { | |
366 ac := div(b[unzig[k]], (8 * int(e.quant[q][k]))) | |
367 if ac == 0 { | |
368 runLength++ | |
369 } else { | |
370 for runLength > 15 { | |
371 e.emitHuff(h, 0xf0) | |
372 runLength -= 16 | |
373 } | |
374 e.emitHuffRLE(h, runLength, ac) | |
375 runLength = 0 | |
376 } | |
377 } | |
378 if runLength > 0 { | |
379 e.emitHuff(h, 0x00) | |
380 } | |
381 return dc | |
382 } | |
383 | |
384 // toYCbCr converts the 8x8 region of m whose top-left corner is p to its | |
385 // YCbCr values. | |
386 func toYCbCr(m image.Image, p image.Point, yBlock, cbBlock, crBlock *block) { | |
387 b := m.Bounds() | |
388 xmax := b.Max.X - 1 | |
389 ymax := b.Max.Y - 1 | |
390 for j := 0; j < 8; j++ { | |
391 for i := 0; i < 8; i++ { | |
392 r, g, b, _ := m.At(min(p.X+i, xmax), min(p.Y+j, ymax)).R GBA() | |
393 yy, cb, cr := ycbcr.RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8)) | |
394 yBlock[8*j+i] = int(yy) | |
395 cbBlock[8*j+i] = int(cb) | |
396 crBlock[8*j+i] = int(cr) | |
397 } | |
398 } | |
399 } | |
400 | |
401 // scale scales the 16x16 region represented by the 4 src blocks to the 8x8 | |
402 // dst block. | |
403 func scale(dst *block, src *[4]block) { | |
404 for i := 0; i < 4; i++ { | |
405 dstOff := (i&2)<<4 | (i&1)<<2 | |
406 for y := 0; y < 4; y++ { | |
407 for x := 0; x < 4; x++ { | |
408 j := 16*y + 2*x | |
409 sum := src[i][j] + src[i][j+1] + src[i][j+8] + s rc[i][j+9] | |
410 dst[8*y+x+dstOff] = (sum + 2) >> 2 | |
411 } | |
412 } | |
413 } | |
414 } | |
415 | |
416 // writeSOS writes the StartOfScan marker. | |
417 func (e *encoder) writeSOS(m image.Image) { | |
418 // Write the SOS marker "\xff\xda" followed by 12 bytes: | |
419 // - the marker length "\x00\x0c", | |
420 // - the number of components "\x03", | |
421 // - component 1 uses DC table 0 and AC table 0 "\x01\x00", | |
422 // - component 2 uses DC table 1 and AC table 1 "\x02\x11", | |
423 // - component 3 uses DC table 1 and AC table 1 "\x03\x11", | |
424 // - padding "\x00\x00\x00". | |
425 e.writeString("\xff\xda\x00\x0c\x03\x01\x00\x02\x11\x03\x11\x00\x00\x00" ) | |
r
2011/04/18 19:30:42
depending on the implementation of the writer, wri
nigeltao
2011/04/19 00:47:06
Done.
| |
426 var ( | |
427 // Scratch buffers to hold the YCbCr values. | |
428 yBlock block | |
429 cbBlock [4]block | |
430 crBlock [4]block | |
431 cBlock block | |
r
2011/04/18 19:30:42
ok for now, but these are more unnecessary allocat
nigeltao
2011/04/19 00:47:06
There is only one SOS per image. Also, eventually,
| |
432 // DC components are delta-encoded. | |
433 lastY, lastCb, lastCr int | |
434 ) | |
435 bounds := m.Bounds() | |
436 for y := bounds.Min.Y; y < bounds.Max.Y; y += 16 { | |
437 for x := bounds.Min.X; x < bounds.Max.X; x += 16 { | |
438 for i := 0; i < 4; i++ { | |
439 xOff := (i & 1) * 8 | |
440 yOff := (i & 2) * 4 | |
441 p := image.Point{x + xOff, y + yOff} | |
442 toYCbCr(m, p, &yBlock, &cbBlock[i], &crBlock[i]) | |
443 lastY = e.writeBlock(&yBlock, 0, lastY) | |
444 } | |
445 scale(&cBlock, &cbBlock) | |
446 lastCb = e.writeBlock(&cBlock, 1, lastCb) | |
447 scale(&cBlock, &crBlock) | |
448 lastCr = e.writeBlock(&cBlock, 1, lastCr) | |
449 } | |
450 } | |
451 // Pad the last byte with 1's. | |
452 e.emit(0x7f, 7) | |
453 } | |
454 | |
455 // DefaultQuality is the default quality encoding parameter. | |
456 const DefaultQuality = 75 | |
457 | |
458 // Options are the encoding parameters. | |
459 // Quality ranges from 1 to 100 inclusive, higher is better. | |
460 type Options struct { | |
461 Quality int | |
462 } | |
463 | |
464 // Encode writes the Image m to w in JPEG 4:2:0 baseline format with the given | |
465 // options. Default parameters are used if a nil *Options is passed. | |
466 func Encode(w io.Writer, m image.Image, o *Options) os.Error { | |
467 b := m.Bounds() | |
468 if b.Dx() >= 1<<16 || b.Dy() >= 1<<16 { | |
469 return os.NewError("jpeg: image is too large to encode") | |
470 } | |
471 var e encoder | |
472 if ww, ok := w.(writer); ok { | |
473 e.w = ww | |
474 } else { | |
475 e.w = bufio.NewWriter(w) | |
476 } | |
477 // Clip quality to [1, 100]. | |
478 quality := DefaultQuality | |
479 if o != nil { | |
480 quality = o.Quality | |
481 if quality < 1 { | |
482 quality = 1 | |
483 } else if quality > 100 { | |
484 quality = 100 | |
485 } | |
486 } | |
487 // Convert from a quality rating to a scaling factor. | |
488 var scale int | |
489 if quality < 50 { | |
490 scale = 5000 / quality | |
491 } else { | |
492 scale = 200 - quality*2 | |
493 } | |
494 // Initialize the quantization tables. | |
495 for i := range e.quant { | |
496 for j := range e.quant[i] { | |
497 x := int(unscaledQuant[i][j]) | |
498 x = (x*scale + 50) / 100 | |
499 if x < 1 { | |
500 x = 1 | |
501 } else if x > 255 { | |
502 x = 255 | |
503 } | |
504 e.quant[i][j] = uint8(x) | |
505 } | |
506 } | |
507 // Write the Start Of Image marker. | |
508 e.writeString("\xff\xd8") | |
509 // Write the quantization tables. | |
510 e.writeDQT() | |
511 // Write the image dimensions. | |
512 e.writeSOF0(b.Size()) | |
513 // Write the Huffman tables. | |
514 e.writeDHT() | |
515 // Write the image data. | |
516 e.writeSOS(m) | |
517 // Write the End Of Image marker. | |
518 e.writeString("\xff\xd9") | |
519 e.flush() | |
520 return e.err | |
521 } | |
OLD | NEW |