Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 // Copyright 2013 The Go Authors. All rights reserved. | 1 // Copyright 2013 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 bmp | 5 package bmp |
6 | 6 |
7 import ( | 7 import ( |
8 "encoding/binary" | 8 "encoding/binary" |
9 "image" | 9 "image" |
10 "io" | 10 "io" |
(...skipping 10 matching lines...) Expand all Loading... | |
21 colorPlane uint16 | 21 colorPlane uint16 |
22 bpp uint16 | 22 bpp uint16 |
23 compression uint32 | 23 compression uint32 |
24 imageSize uint32 | 24 imageSize uint32 |
25 xPixelsPerMeter uint32 | 25 xPixelsPerMeter uint32 |
26 yPixelsPerMeter uint32 | 26 yPixelsPerMeter uint32 |
27 colorUse uint32 | 27 colorUse uint32 |
28 colorImportant uint32 | 28 colorImportant uint32 |
29 } | 29 } |
30 | 30 |
31 func encodePaletted(w io.Writer, m image.Image, pix []uint8, stride, step int) e rror { | 31 func encodePaletted(w io.Writer, pix []uint8, dx, dy, stride, step int) error { |
32 » if stride < step { | 32 » var padding []byte |
33 » » padding := make([]byte, step-stride) | 33 » if dx < step { |
34 » » for y := m.Bounds().Dy() - 1; y >= 0; y-- { | 34 » » padding = make([]byte, step-dx) |
35 » » » min := y*stride + 0 | 35 » } |
36 » » » max := y*stride + stride | 36 » for y := dy - 1; y >= 0; y-- { |
nigeltao
2013/09/09 07:18:26
This isn't right. Again, this can panic if width <
chai2010
2013/09/09 07:42:41
Done.
| |
37 » » » if _, err := w.Write(pix[min:max]); err != nil { | 37 » » min := y*stride + 0 |
38 » » » » return err | 38 » » max := y*stride + dx |
39 » » » } | 39 » » if _, err := w.Write(pix[min:max]); err != nil { |
40 » » » return err | |
41 » » } | |
42 » » if padding != nil { | |
40 if _, err := w.Write(padding); err != nil { | 43 if _, err := w.Write(padding); err != nil { |
41 return err | |
42 } | |
43 } | |
44 } else { | |
45 for y := m.Bounds().Dy() - 1; y >= 0; y-- { | |
46 min := y*stride + 0 | |
47 max := y*stride + step | |
nigeltao
2013/09/09 07:18:26
This will panic if width < step && step <= stride.
chai2010
2013/09/09 07:42:41
Done.
| |
48 if _, err := w.Write(pix[min:max]); err != nil { | |
49 return err | 44 return err |
50 } | 45 } |
51 } | 46 } |
52 } | 47 } |
53 return nil | 48 return nil |
54 } | 49 } |
55 | 50 |
56 func encodeRGBA(w io.Writer, m image.Image, pix []uint8, stride, step int) error { | 51 func encodeRGBA(w io.Writer, pix []uint8, dx, dy, stride, step int) error { |
57 buf := make([]byte, step) | 52 buf := make([]byte, step) |
58 » for y := m.Bounds().Dy() - 1; y >= 0; y-- { | 53 » for y := dy - 1; y >= 0; y-- { |
59 min := y*stride + 0 | 54 min := y*stride + 0 |
60 » » max := y*stride + m.Bounds().Dx()*4 | 55 » » max := y*stride + dx*4 |
61 off := 0 | 56 off := 0 |
62 for i := min; i < max; i += 4 { | 57 for i := min; i < max; i += 4 { |
63 buf[off+2] = pix[i+0] | 58 buf[off+2] = pix[i+0] |
64 buf[off+1] = pix[i+1] | 59 buf[off+1] = pix[i+1] |
65 buf[off+0] = pix[i+2] | 60 buf[off+0] = pix[i+2] |
66 off += 3 | 61 off += 3 |
67 } | 62 } |
68 if _, err := w.Write(buf); err != nil { | 63 if _, err := w.Write(buf); err != nil { |
69 return err | 64 return err |
70 } | 65 } |
71 } | 66 } |
72 return nil | 67 return nil |
73 } | 68 } |
74 | 69 |
75 func encode(w io.Writer, m image.Image, step int) error { | 70 func encode(w io.Writer, m image.Image, step int) error { |
71 b := m.Bounds() | |
76 buf := make([]byte, step) | 72 buf := make([]byte, step) |
77 » for y := m.Bounds().Dy() - 1; y >= 0; y-- { | 73 » for y := b.Max.Y - 1; y >= b.Min.Y; y-- { |
78 off := 0 | 74 off := 0 |
79 » » for x := 0; x < m.Bounds().Dx(); x++ { | 75 » » for x := b.Min.X; x < b.Max.X; x++ { |
80 r, g, b, _ := m.At(x, y).RGBA() | 76 r, g, b, _ := m.At(x, y).RGBA() |
81 buf[off+2] = byte(r >> 8) | 77 buf[off+2] = byte(r >> 8) |
82 buf[off+1] = byte(g >> 8) | 78 buf[off+1] = byte(g >> 8) |
83 buf[off+0] = byte(b >> 8) | 79 buf[off+0] = byte(b >> 8) |
84 off += 3 | 80 off += 3 |
85 } | 81 } |
86 if _, err := w.Write(buf); err != nil { | 82 if _, err := w.Write(buf); err != nil { |
87 return err | 83 return err |
88 } | 84 } |
89 } | 85 } |
90 return nil | 86 return nil |
91 } | 87 } |
92 | 88 |
93 // Encode writes the image m to w in BMP format. | 89 // Encode writes the image m to w in BMP format. |
94 func Encode(w io.Writer, m image.Image) error { | 90 func Encode(w io.Writer, m image.Image) error { |
91 d := m.Bounds().Size() | |
95 h := &header{ | 92 h := &header{ |
96 sigBM: [2]byte{'B', 'M'}, | 93 sigBM: [2]byte{'B', 'M'}, |
97 fileSize: 14 + 40, | 94 fileSize: 14 + 40, |
98 pixOffset: 14 + 40, | 95 pixOffset: 14 + 40, |
99 dibHeaderSize: 40, | 96 dibHeaderSize: 40, |
100 » » width: uint32(m.Bounds().Dx()), | 97 » » width: uint32(d.X), |
101 » » height: uint32(m.Bounds().Dy()), | 98 » » height: uint32(d.Y), |
102 colorPlane: 1, | 99 colorPlane: 1, |
103 } | 100 } |
104 | 101 |
105 var step int | 102 var step int |
106 var palette []byte | 103 var palette []byte |
107 switch m := m.(type) { | 104 switch m := m.(type) { |
108 case *image.Gray: | 105 case *image.Gray: |
109 » » step = (m.Bounds().Dx() + 3) &^ 3 | 106 » » step = (d.X + 3) &^ 3 |
110 palette = make([]byte, 1024) | 107 palette = make([]byte, 1024) |
111 for i := 0; i < 256; i++ { | 108 for i := 0; i < 256; i++ { |
112 palette[i*4+0] = uint8(i) | 109 palette[i*4+0] = uint8(i) |
113 palette[i*4+1] = uint8(i) | 110 palette[i*4+1] = uint8(i) |
114 palette[i*4+2] = uint8(i) | 111 palette[i*4+2] = uint8(i) |
115 palette[i*4+3] = 0xFF | 112 palette[i*4+3] = 0xFF |
116 } | 113 } |
117 » » h.imageSize = uint32(m.Bounds().Dy() * step) | 114 » » h.imageSize = uint32(d.Y * step) |
118 h.fileSize += uint32(len(palette)) + h.imageSize | 115 h.fileSize += uint32(len(palette)) + h.imageSize |
119 h.pixOffset += uint32(len(palette)) | 116 h.pixOffset += uint32(len(palette)) |
120 h.bpp = 8 | 117 h.bpp = 8 |
121 | 118 |
122 case *image.Paletted: | 119 case *image.Paletted: |
123 » » step = (m.Bounds().Dx() + 3) &^ 3 | 120 » » step = (d.X + 3) &^ 3 |
124 palette = make([]byte, 1024) | 121 palette = make([]byte, 1024) |
125 for i := 0; i < len(m.Palette) && i < 256; i++ { | 122 for i := 0; i < len(m.Palette) && i < 256; i++ { |
126 r, g, b, _ := m.Palette[i].RGBA() | 123 r, g, b, _ := m.Palette[i].RGBA() |
127 palette[i*4+0] = uint8(b >> 8) | 124 palette[i*4+0] = uint8(b >> 8) |
128 palette[i*4+1] = uint8(g >> 8) | 125 palette[i*4+1] = uint8(g >> 8) |
129 palette[i*4+2] = uint8(r >> 8) | 126 palette[i*4+2] = uint8(r >> 8) |
130 palette[i*4+3] = 0xFF | 127 palette[i*4+3] = 0xFF |
131 } | 128 } |
132 » » h.imageSize = uint32(m.Bounds().Dy() * step) | 129 » » h.imageSize = uint32(d.Y * step) |
133 h.fileSize += uint32(len(palette)) + h.imageSize | 130 h.fileSize += uint32(len(palette)) + h.imageSize |
134 h.pixOffset += uint32(len(palette)) | 131 h.pixOffset += uint32(len(palette)) |
135 h.bpp = 8 | 132 h.bpp = 8 |
136 default: | 133 default: |
137 » » step = (3*m.Bounds().Dx() + 3) &^ 3 | 134 » » step = (3*d.X + 3) &^ 3 |
138 » » h.imageSize = uint32(m.Bounds().Dy() * step) | 135 » » h.imageSize = uint32(d.Y * step) |
139 h.fileSize += h.imageSize | 136 h.fileSize += h.imageSize |
140 h.bpp = 24 | 137 h.bpp = 24 |
141 } | 138 } |
142 | 139 |
143 if err := binary.Write(w, binary.LittleEndian, h); err != nil { | 140 if err := binary.Write(w, binary.LittleEndian, h); err != nil { |
144 return err | 141 return err |
145 } | 142 } |
146 » if err := binary.Write(w, binary.LittleEndian, palette); err != nil { | 143 » if palette != nil { |
nigeltao
2013/09/09 07:18:26
Guard this by
if palette != nil
chai2010
2013/09/09 07:42:41
Done.
| |
147 » » return err | 144 » » if err := binary.Write(w, binary.LittleEndian, palette); err != nil { |
145 » » » return err | |
146 » » } | |
148 } | 147 } |
149 | 148 |
150 switch m := m.(type) { | 149 switch m := m.(type) { |
151 case *image.Gray: | 150 case *image.Gray: |
152 » » return encodePaletted(w, m, m.Pix, m.Stride, step) | 151 » » return encodePaletted(w, m.Pix, d.X, d.Y, m.Stride, step) |
153 case *image.Paletted: | 152 case *image.Paletted: |
154 » » return encodePaletted(w, m, m.Pix, m.Stride, step) | 153 » » return encodePaletted(w, m.Pix, d.X, d.Y, m.Stride, step) |
155 case *image.RGBA: | 154 case *image.RGBA: |
156 » » return encodeRGBA(w, m, m.Pix, m.Stride, step) | 155 » » return encodeRGBA(w, m.Pix, d.X, d.Y, m.Stride, step) |
157 } | 156 } |
158 return encode(w, m, step) | 157 return encode(w, m, step) |
159 } | 158 } |
LEFT | RIGHT |