[ARM] Fix typo in comment in arm_expand_prologue
[official-gcc.git] / libgo / go / image / jpeg / writer.go
blob91bbde3bf803e9be37056b481b4cda91bb1e8311
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.
5 package jpeg
7 import (
8 "bufio"
9 "errors"
10 "image"
11 "image/color"
12 "io"
15 // min returns the minimum of two integers.
16 func min(x, y int) int {
17 if x < y {
18 return x
20 return y
23 // div returns a/b rounded to the nearest integer, instead of rounded to zero.
24 func div(a, b int32) int32 {
25 if a >= 0 {
26 return (a + (b >> 1)) / b
28 return -((-a + (b >> 1)) / b)
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,
51 type quantIndex int
53 const (
54 quantIndexLuminance quantIndex = iota
55 quantIndexChrominance
56 nQuantIndex
59 // unscaledQuant are the unscaled quantization tables in zig-zag order. Each
60 // encoder copies and scales the tables according to its quality parameter.
61 // The values are derived from section K.1 after converting from natural to
62 // zig-zag order.
63 var unscaledQuant = [nQuantIndex][blockSize]byte{
64 // Luminance.
66 16, 11, 12, 14, 12, 10, 16, 14,
67 13, 14, 18, 17, 16, 19, 24, 40,
68 26, 24, 22, 22, 24, 49, 35, 37,
69 29, 40, 58, 51, 61, 60, 57, 51,
70 56, 55, 64, 72, 92, 78, 64, 68,
71 87, 69, 55, 56, 80, 109, 81, 87,
72 95, 98, 103, 104, 103, 62, 77, 113,
73 121, 112, 100, 120, 92, 101, 103, 99,
75 // Chrominance.
77 17, 18, 18, 24, 21, 24, 47, 26,
78 26, 47, 99, 66, 56, 66, 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 99, 99, 99, 99, 99, 99, 99, 99,
84 99, 99, 99, 99, 99, 99, 99, 99,
88 type huffIndex int
90 const (
91 huffIndexLuminanceDC huffIndex = iota
92 huffIndexLuminanceAC
93 huffIndexChrominanceDC
94 huffIndexChrominanceAC
95 nHuffIndex
98 // huffmanSpec specifies a Huffman encoding.
99 type huffmanSpec struct {
100 // count[i] is the number of codes of length i bits.
101 count [16]byte
102 // value[i] is the decoded value of the i'th codeword.
103 value []byte
106 // theHuffmanSpec is the Huffman encoding specifications.
107 // This encoder uses the same Huffman encoding for all images.
108 var theHuffmanSpec = [nHuffIndex]huffmanSpec{
109 // Luminance DC.
111 [16]byte{0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0},
112 []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
114 // Luminance AC.
116 [16]byte{0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 125},
117 []byte{
118 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
119 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
120 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
121 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
122 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
123 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
124 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
125 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
126 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
127 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
128 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
129 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
130 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
131 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
132 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
133 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
134 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
135 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
136 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
137 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
138 0xf9, 0xfa,
141 // Chrominance DC.
143 [16]byte{0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
144 []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
146 // Chrominance AC.
148 [16]byte{0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 119},
149 []byte{
150 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
151 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
152 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
153 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
154 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
155 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
156 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
157 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
158 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
159 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
160 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
161 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
162 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
163 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
164 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
165 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
166 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
167 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
168 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
169 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
170 0xf9, 0xfa,
175 // huffmanLUT is a compiled look-up table representation of a huffmanSpec.
176 // Each value maps to a uint32 of which the 8 most significant bits hold the
177 // codeword size in bits and the 24 least significant bits hold the codeword.
178 // The maximum codeword size is 16 bits.
179 type huffmanLUT []uint32
181 func (h *huffmanLUT) init(s huffmanSpec) {
182 maxValue := 0
183 for _, v := range s.value {
184 if int(v) > maxValue {
185 maxValue = int(v)
188 *h = make([]uint32, maxValue+1)
189 code, k := uint32(0), 0
190 for i := 0; i < len(s.count); i++ {
191 nBits := uint32(i+1) << 24
192 for j := uint8(0); j < s.count[i]; j++ {
193 (*h)[s.value[k]] = nBits | code
194 code++
197 code <<= 1
201 // theHuffmanLUT are compiled representations of theHuffmanSpec.
202 var theHuffmanLUT [4]huffmanLUT
204 func init() {
205 for i, s := range theHuffmanSpec {
206 theHuffmanLUT[i].init(s)
210 // writer is a buffered writer.
211 type writer interface {
212 Flush() error
213 io.Writer
214 io.ByteWriter
217 // encoder encodes an image to the JPEG format.
218 type encoder struct {
219 // w is the writer to write to. err is the first error encountered during
220 // writing. All attempted writes after the first error become no-ops.
221 w writer
222 err error
223 // buf is a scratch buffer.
224 buf [16]byte
225 // bits and nBits are accumulated bits to write to w.
226 bits, nBits uint32
227 // quant is the scaled quantization tables, in zig-zag order.
228 quant [nQuantIndex][blockSize]byte
231 func (e *encoder) flush() {
232 if e.err != nil {
233 return
235 e.err = e.w.Flush()
238 func (e *encoder) write(p []byte) {
239 if e.err != nil {
240 return
242 _, e.err = e.w.Write(p)
245 func (e *encoder) writeByte(b byte) {
246 if e.err != nil {
247 return
249 e.err = e.w.WriteByte(b)
252 // emit emits the least significant nBits bits of bits to the bit-stream.
253 // The precondition is bits < 1<<nBits && nBits <= 16.
254 func (e *encoder) emit(bits, nBits uint32) {
255 nBits += e.nBits
256 bits <<= 32 - nBits
257 bits |= e.bits
258 for nBits >= 8 {
259 b := uint8(bits >> 24)
260 e.writeByte(b)
261 if b == 0xff {
262 e.writeByte(0x00)
264 bits <<= 8
265 nBits -= 8
267 e.bits, e.nBits = bits, nBits
270 // emitHuff emits the given value with the given Huffman encoder.
271 func (e *encoder) emitHuff(h huffIndex, value int32) {
272 x := theHuffmanLUT[h][value]
273 e.emit(x&(1<<24-1), x>>24)
276 // emitHuffRLE emits a run of runLength copies of value encoded with the given
277 // Huffman encoder.
278 func (e *encoder) emitHuffRLE(h huffIndex, runLength, value int32) {
279 a, b := value, value
280 if a < 0 {
281 a, b = -value, value-1
283 var nBits uint32
284 if a < 0x100 {
285 nBits = uint32(bitCount[a])
286 } else {
287 nBits = 8 + uint32(bitCount[a>>8])
289 e.emitHuff(h, runLength<<4|int32(nBits))
290 if nBits > 0 {
291 e.emit(uint32(b)&(1<<nBits-1), nBits)
295 // writeMarkerHeader writes the header for a marker with the given length.
296 func (e *encoder) writeMarkerHeader(marker uint8, markerlen int) {
297 e.buf[0] = 0xff
298 e.buf[1] = marker
299 e.buf[2] = uint8(markerlen >> 8)
300 e.buf[3] = uint8(markerlen & 0xff)
301 e.write(e.buf[:4])
304 // writeDQT writes the Define Quantization Table marker.
305 func (e *encoder) writeDQT() {
306 const markerlen = 2 + int(nQuantIndex)*(1+blockSize)
307 e.writeMarkerHeader(dqtMarker, markerlen)
308 for i := range e.quant {
309 e.writeByte(uint8(i))
310 e.write(e.quant[i][:])
314 // writeSOF0 writes the Start Of Frame (Baseline) marker.
315 func (e *encoder) writeSOF0(size image.Point, nComponent int) {
316 markerlen := 8 + 3*nComponent
317 e.writeMarkerHeader(sof0Marker, markerlen)
318 e.buf[0] = 8 // 8-bit color.
319 e.buf[1] = uint8(size.Y >> 8)
320 e.buf[2] = uint8(size.Y & 0xff)
321 e.buf[3] = uint8(size.X >> 8)
322 e.buf[4] = uint8(size.X & 0xff)
323 e.buf[5] = uint8(nComponent)
324 if nComponent == 1 {
325 e.buf[6] = 1
326 // No subsampling for grayscale image.
327 e.buf[7] = 0x11
328 e.buf[8] = 0x00
329 } else {
330 for i := 0; i < nComponent; i++ {
331 e.buf[3*i+6] = uint8(i + 1)
332 // We use 4:2:0 chroma subsampling.
333 e.buf[3*i+7] = "\x22\x11\x11"[i]
334 e.buf[3*i+8] = "\x00\x01\x01"[i]
337 e.write(e.buf[:3*(nComponent-1)+9])
340 // writeDHT writes the Define Huffman Table marker.
341 func (e *encoder) writeDHT(nComponent int) {
342 markerlen := 2
343 specs := theHuffmanSpec[:]
344 if nComponent == 1 {
345 // Drop the Chrominance tables.
346 specs = specs[:2]
348 for _, s := range specs {
349 markerlen += 1 + 16 + len(s.value)
351 e.writeMarkerHeader(dhtMarker, markerlen)
352 for i, s := range specs {
353 e.writeByte("\x00\x10\x01\x11"[i])
354 e.write(s.count[:])
355 e.write(s.value)
359 // writeBlock writes a block of pixel data using the given quantization table,
360 // returning the post-quantized DC value of the DCT-transformed block. b is in
361 // natural (not zig-zag) order.
362 func (e *encoder) writeBlock(b *block, q quantIndex, prevDC int32) int32 {
363 fdct(b)
364 // Emit the DC delta.
365 dc := div(b[0], 8*int32(e.quant[q][0]))
366 e.emitHuffRLE(huffIndex(2*q+0), 0, dc-prevDC)
367 // Emit the AC components.
368 h, runLength := huffIndex(2*q+1), int32(0)
369 for zig := 1; zig < blockSize; zig++ {
370 ac := div(b[unzig[zig]], 8*int32(e.quant[q][zig]))
371 if ac == 0 {
372 runLength++
373 } else {
374 for runLength > 15 {
375 e.emitHuff(h, 0xf0)
376 runLength -= 16
378 e.emitHuffRLE(h, runLength, ac)
379 runLength = 0
382 if runLength > 0 {
383 e.emitHuff(h, 0x00)
385 return dc
388 // toYCbCr converts the 8x8 region of m whose top-left corner is p to its
389 // YCbCr values.
390 func toYCbCr(m image.Image, p image.Point, yBlock, cbBlock, crBlock *block) {
391 b := m.Bounds()
392 xmax := b.Max.X - 1
393 ymax := b.Max.Y - 1
394 for j := 0; j < 8; j++ {
395 for i := 0; i < 8; i++ {
396 r, g, b, _ := m.At(min(p.X+i, xmax), min(p.Y+j, ymax)).RGBA()
397 yy, cb, cr := color.RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))
398 yBlock[8*j+i] = int32(yy)
399 cbBlock[8*j+i] = int32(cb)
400 crBlock[8*j+i] = int32(cr)
405 // grayToY stores the 8x8 region of m whose top-left corner is p in yBlock.
406 func grayToY(m *image.Gray, p image.Point, yBlock *block) {
407 b := m.Bounds()
408 xmax := b.Max.X - 1
409 ymax := b.Max.Y - 1
410 pix := m.Pix
411 for j := 0; j < 8; j++ {
412 for i := 0; i < 8; i++ {
413 idx := m.PixOffset(min(p.X+i, xmax), min(p.Y+j, ymax))
414 yBlock[8*j+i] = int32(pix[idx])
419 // rgbaToYCbCr is a specialized version of toYCbCr for image.RGBA images.
420 func rgbaToYCbCr(m *image.RGBA, p image.Point, yBlock, cbBlock, crBlock *block) {
421 b := m.Bounds()
422 xmax := b.Max.X - 1
423 ymax := b.Max.Y - 1
424 for j := 0; j < 8; j++ {
425 sj := p.Y + j
426 if sj > ymax {
427 sj = ymax
429 offset := (sj-b.Min.Y)*m.Stride - b.Min.X*4
430 for i := 0; i < 8; i++ {
431 sx := p.X + i
432 if sx > xmax {
433 sx = xmax
435 pix := m.Pix[offset+sx*4:]
436 yy, cb, cr := color.RGBToYCbCr(pix[0], pix[1], pix[2])
437 yBlock[8*j+i] = int32(yy)
438 cbBlock[8*j+i] = int32(cb)
439 crBlock[8*j+i] = int32(cr)
444 // scale scales the 16x16 region represented by the 4 src blocks to the 8x8
445 // dst block.
446 func scale(dst *block, src *[4]block) {
447 for i := 0; i < 4; i++ {
448 dstOff := (i&2)<<4 | (i&1)<<2
449 for y := 0; y < 4; y++ {
450 for x := 0; x < 4; x++ {
451 j := 16*y + 2*x
452 sum := src[i][j] + src[i][j+1] + src[i][j+8] + src[i][j+9]
453 dst[8*y+x+dstOff] = (sum + 2) >> 2
459 // sosHeaderY is the SOS marker "\xff\xda" followed by 8 bytes:
460 // - the marker length "\x00\x08",
461 // - the number of components "\x01",
462 // - component 1 uses DC table 0 and AC table 0 "\x01\x00",
463 // - the bytes "\x00\x3f\x00". Section B.2.3 of the spec says that for
464 // sequential DCTs, those bytes (8-bit Ss, 8-bit Se, 4-bit Ah, 4-bit Al)
465 // should be 0x00, 0x3f, 0x00<<4 | 0x00.
466 var sosHeaderY = []byte{
467 0xff, 0xda, 0x00, 0x08, 0x01, 0x01, 0x00, 0x00, 0x3f, 0x00,
470 // sosHeaderYCbCr is the SOS marker "\xff\xda" followed by 12 bytes:
471 // - the marker length "\x00\x0c",
472 // - the number of components "\x03",
473 // - component 1 uses DC table 0 and AC table 0 "\x01\x00",
474 // - component 2 uses DC table 1 and AC table 1 "\x02\x11",
475 // - component 3 uses DC table 1 and AC table 1 "\x03\x11",
476 // - the bytes "\x00\x3f\x00". Section B.2.3 of the spec says that for
477 // sequential DCTs, those bytes (8-bit Ss, 8-bit Se, 4-bit Ah, 4-bit Al)
478 // should be 0x00, 0x3f, 0x00<<4 | 0x00.
479 var sosHeaderYCbCr = []byte{
480 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02,
481 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00,
484 // writeSOS writes the StartOfScan marker.
485 func (e *encoder) writeSOS(m image.Image) {
486 switch m.(type) {
487 case *image.Gray:
488 e.write(sosHeaderY)
489 default:
490 e.write(sosHeaderYCbCr)
492 var (
493 // Scratch buffers to hold the YCbCr values.
494 // The blocks are in natural (not zig-zag) order.
495 b block
496 cb, cr [4]block
497 // DC components are delta-encoded.
498 prevDCY, prevDCCb, prevDCCr int32
500 bounds := m.Bounds()
501 switch m := m.(type) {
502 // TODO(wathiede): switch on m.ColorModel() instead of type.
503 case *image.Gray:
504 for y := bounds.Min.Y; y < bounds.Max.Y; y += 8 {
505 for x := bounds.Min.X; x < bounds.Max.X; x += 8 {
506 p := image.Pt(x, y)
507 grayToY(m, p, &b)
508 prevDCY = e.writeBlock(&b, 0, prevDCY)
511 default:
512 rgba, _ := m.(*image.RGBA)
513 for y := bounds.Min.Y; y < bounds.Max.Y; y += 16 {
514 for x := bounds.Min.X; x < bounds.Max.X; x += 16 {
515 for i := 0; i < 4; i++ {
516 xOff := (i & 1) * 8
517 yOff := (i & 2) * 4
518 p := image.Pt(x+xOff, y+yOff)
519 if rgba != nil {
520 rgbaToYCbCr(rgba, p, &b, &cb[i], &cr[i])
521 } else {
522 toYCbCr(m, p, &b, &cb[i], &cr[i])
524 prevDCY = e.writeBlock(&b, 0, prevDCY)
526 scale(&b, &cb)
527 prevDCCb = e.writeBlock(&b, 1, prevDCCb)
528 scale(&b, &cr)
529 prevDCCr = e.writeBlock(&b, 1, prevDCCr)
533 // Pad the last byte with 1's.
534 e.emit(0x7f, 7)
537 // DefaultQuality is the default quality encoding parameter.
538 const DefaultQuality = 75
540 // Options are the encoding parameters.
541 // Quality ranges from 1 to 100 inclusive, higher is better.
542 type Options struct {
543 Quality int
546 // Encode writes the Image m to w in JPEG 4:2:0 baseline format with the given
547 // options. Default parameters are used if a nil *Options is passed.
548 func Encode(w io.Writer, m image.Image, o *Options) error {
549 b := m.Bounds()
550 if b.Dx() >= 1<<16 || b.Dy() >= 1<<16 {
551 return errors.New("jpeg: image is too large to encode")
553 var e encoder
554 if ww, ok := w.(writer); ok {
555 e.w = ww
556 } else {
557 e.w = bufio.NewWriter(w)
559 // Clip quality to [1, 100].
560 quality := DefaultQuality
561 if o != nil {
562 quality = o.Quality
563 if quality < 1 {
564 quality = 1
565 } else if quality > 100 {
566 quality = 100
569 // Convert from a quality rating to a scaling factor.
570 var scale int
571 if quality < 50 {
572 scale = 5000 / quality
573 } else {
574 scale = 200 - quality*2
576 // Initialize the quantization tables.
577 for i := range e.quant {
578 for j := range e.quant[i] {
579 x := int(unscaledQuant[i][j])
580 x = (x*scale + 50) / 100
581 if x < 1 {
582 x = 1
583 } else if x > 255 {
584 x = 255
586 e.quant[i][j] = uint8(x)
589 // Compute number of components based on input image type.
590 nComponent := 3
591 switch m.(type) {
592 // TODO(wathiede): switch on m.ColorModel() instead of type.
593 case *image.Gray:
594 nComponent = 1
596 // Write the Start Of Image marker.
597 e.buf[0] = 0xff
598 e.buf[1] = 0xd8
599 e.write(e.buf[:2])
600 // Write the quantization tables.
601 e.writeDQT()
602 // Write the image dimensions.
603 e.writeSOF0(b.Size(), nComponent)
604 // Write the Huffman tables.
605 e.writeDHT(nComponent)
606 // Write the image data.
607 e.writeSOS(m)
608 // Write the End Of Image marker.
609 e.buf[0] = 0xff
610 e.buf[1] = 0xd9
611 e.write(e.buf[:2])
612 e.flush()
613 return e.err