OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [image/] [png/] [writer.go] - Blame information for rev 774

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 747 jeremybenn
// Copyright 2009 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 png
6
 
7
import (
8
        "bufio"
9
        "compress/zlib"
10
        "hash/crc32"
11
        "image"
12
        "image/color"
13
        "io"
14
        "strconv"
15
)
16
 
17
type encoder struct {
18
        w      io.Writer
19
        m      image.Image
20
        cb     int
21
        err    error
22
        header [8]byte
23
        footer [4]byte
24
        tmp    [3 * 256]byte
25
}
26
 
27
// Big-endian.
28
func writeUint32(b []uint8, u uint32) {
29
        b[0] = uint8(u >> 24)
30
        b[1] = uint8(u >> 16)
31
        b[2] = uint8(u >> 8)
32
        b[3] = uint8(u >> 0)
33
}
34
 
35
type opaquer interface {
36
        Opaque() bool
37
}
38
 
39
// Returns whether or not the image is fully opaque.
40
func opaque(m image.Image) bool {
41
        if o, ok := m.(opaquer); ok {
42
                return o.Opaque()
43
        }
44
        b := m.Bounds()
45
        for y := b.Min.Y; y < b.Max.Y; y++ {
46
                for x := b.Min.X; x < b.Max.X; x++ {
47
                        _, _, _, a := m.At(x, y).RGBA()
48
                        if a != 0xffff {
49
                                return false
50
                        }
51
                }
52
        }
53
        return true
54
}
55
 
56
// The absolute value of a byte interpreted as a signed int8.
57
func abs8(d uint8) int {
58
        if d < 128 {
59
                return int(d)
60
        }
61
        return 256 - int(d)
62
}
63
 
64
func (e *encoder) writeChunk(b []byte, name string) {
65
        if e.err != nil {
66
                return
67
        }
68
        n := uint32(len(b))
69
        if int(n) != len(b) {
70
                e.err = UnsupportedError(name + " chunk is too large: " + strconv.Itoa(len(b)))
71
                return
72
        }
73
        writeUint32(e.header[0:4], n)
74
        e.header[4] = name[0]
75
        e.header[5] = name[1]
76
        e.header[6] = name[2]
77
        e.header[7] = name[3]
78
        crc := crc32.NewIEEE()
79
        crc.Write(e.header[4:8])
80
        crc.Write(b)
81
        writeUint32(e.footer[0:4], crc.Sum32())
82
 
83
        _, e.err = e.w.Write(e.header[0:8])
84
        if e.err != nil {
85
                return
86
        }
87
        _, e.err = e.w.Write(b)
88
        if e.err != nil {
89
                return
90
        }
91
        _, e.err = e.w.Write(e.footer[0:4])
92
}
93
 
94
func (e *encoder) writeIHDR() {
95
        b := e.m.Bounds()
96
        writeUint32(e.tmp[0:4], uint32(b.Dx()))
97
        writeUint32(e.tmp[4:8], uint32(b.Dy()))
98
        // Set bit depth and color type.
99
        switch e.cb {
100
        case cbG8:
101
                e.tmp[8] = 8
102
                e.tmp[9] = ctGrayscale
103
        case cbTC8:
104
                e.tmp[8] = 8
105
                e.tmp[9] = ctTrueColor
106
        case cbP8:
107
                e.tmp[8] = 8
108
                e.tmp[9] = ctPaletted
109
        case cbTCA8:
110
                e.tmp[8] = 8
111
                e.tmp[9] = ctTrueColorAlpha
112
        case cbG16:
113
                e.tmp[8] = 16
114
                e.tmp[9] = ctGrayscale
115
        case cbTC16:
116
                e.tmp[8] = 16
117
                e.tmp[9] = ctTrueColor
118
        case cbTCA16:
119
                e.tmp[8] = 16
120
                e.tmp[9] = ctTrueColorAlpha
121
        }
122
        e.tmp[10] = 0 // default compression method
123
        e.tmp[11] = 0 // default filter method
124
        e.tmp[12] = 0 // non-interlaced
125
        e.writeChunk(e.tmp[0:13], "IHDR")
126
}
127
 
128
func (e *encoder) writePLTE(p color.Palette) {
129
        if len(p) < 1 || len(p) > 256 {
130
                e.err = FormatError("bad palette length: " + strconv.Itoa(len(p)))
131
                return
132
        }
133
        for i, c := range p {
134
                r, g, b, _ := c.RGBA()
135
                e.tmp[3*i+0] = uint8(r >> 8)
136
                e.tmp[3*i+1] = uint8(g >> 8)
137
                e.tmp[3*i+2] = uint8(b >> 8)
138
        }
139
        e.writeChunk(e.tmp[0:3*len(p)], "PLTE")
140
}
141
 
142
func (e *encoder) maybeWritetRNS(p color.Palette) {
143
        last := -1
144
        for i, c := range p {
145
                _, _, _, a := c.RGBA()
146
                if a != 0xffff {
147
                        last = i
148
                }
149
                e.tmp[i] = uint8(a >> 8)
150
        }
151
        if last == -1 {
152
                return
153
        }
154
        e.writeChunk(e.tmp[:last+1], "tRNS")
155
}
156
 
157
// An encoder is an io.Writer that satisfies writes by writing PNG IDAT chunks,
158
// including an 8-byte header and 4-byte CRC checksum per Write call. Such calls
159
// should be relatively infrequent, since writeIDATs uses a bufio.Writer.
160
//
161
// This method should only be called from writeIDATs (via writeImage).
162
// No other code should treat an encoder as an io.Writer.
163
func (e *encoder) Write(b []byte) (int, error) {
164
        e.writeChunk(b, "IDAT")
165
        if e.err != nil {
166
                return 0, e.err
167
        }
168
        return len(b), nil
169
}
170
 
171
// Chooses the filter to use for encoding the current row, and applies it.
172
// The return value is the index of the filter and also of the row in cr that has had it applied.
173
func filter(cr *[nFilter][]byte, pr []byte, bpp int) int {
174
        // We try all five filter types, and pick the one that minimizes the sum of absolute differences.
175
        // This is the same heuristic that libpng uses, although the filters are attempted in order of
176
        // estimated most likely to be minimal (ftUp, ftPaeth, ftNone, ftSub, ftAverage), rather than
177
        // in their enumeration order (ftNone, ftSub, ftUp, ftAverage, ftPaeth).
178
        cdat0 := cr[0][1:]
179
        cdat1 := cr[1][1:]
180
        cdat2 := cr[2][1:]
181
        cdat3 := cr[3][1:]
182
        cdat4 := cr[4][1:]
183
        pdat := pr[1:]
184
        n := len(cdat0)
185
 
186
        // The up filter.
187
        sum := 0
188
        for i := 0; i < n; i++ {
189
                cdat2[i] = cdat0[i] - pdat[i]
190
                sum += abs8(cdat2[i])
191
        }
192
        best := sum
193
        filter := ftUp
194
 
195
        // The Paeth filter.
196
        sum = 0
197
        for i := 0; i < bpp; i++ {
198
                cdat4[i] = cdat0[i] - paeth(0, pdat[i], 0)
199
                sum += abs8(cdat4[i])
200
        }
201
        for i := bpp; i < n; i++ {
202
                cdat4[i] = cdat0[i] - paeth(cdat0[i-bpp], pdat[i], pdat[i-bpp])
203
                sum += abs8(cdat4[i])
204
                if sum >= best {
205
                        break
206
                }
207
        }
208
        if sum < best {
209
                best = sum
210
                filter = ftPaeth
211
        }
212
 
213
        // The none filter.
214
        sum = 0
215
        for i := 0; i < n; i++ {
216
                sum += abs8(cdat0[i])
217
                if sum >= best {
218
                        break
219
                }
220
        }
221
        if sum < best {
222
                best = sum
223
                filter = ftNone
224
        }
225
 
226
        // The sub filter.
227
        sum = 0
228
        for i := 0; i < bpp; i++ {
229
                cdat1[i] = cdat0[i]
230
                sum += abs8(cdat1[i])
231
        }
232
        for i := bpp; i < n; i++ {
233
                cdat1[i] = cdat0[i] - cdat0[i-bpp]
234
                sum += abs8(cdat1[i])
235
                if sum >= best {
236
                        break
237
                }
238
        }
239
        if sum < best {
240
                best = sum
241
                filter = ftSub
242
        }
243
 
244
        // The average filter.
245
        sum = 0
246
        for i := 0; i < bpp; i++ {
247
                cdat3[i] = cdat0[i] - pdat[i]/2
248
                sum += abs8(cdat3[i])
249
        }
250
        for i := bpp; i < n; i++ {
251
                cdat3[i] = cdat0[i] - uint8((int(cdat0[i-bpp])+int(pdat[i]))/2)
252
                sum += abs8(cdat3[i])
253
                if sum >= best {
254
                        break
255
                }
256
        }
257
        if sum < best {
258
                best = sum
259
                filter = ftAverage
260
        }
261
 
262
        return filter
263
}
264
 
265
func writeImage(w io.Writer, m image.Image, cb int) error {
266
        zw, err := zlib.NewWriter(w)
267
        if err != nil {
268
                return err
269
        }
270
        defer zw.Close()
271
 
272
        bpp := 0 // Bytes per pixel.
273
 
274
        switch cb {
275
        case cbG8:
276
                bpp = 1
277
        case cbTC8:
278
                bpp = 3
279
        case cbP8:
280
                bpp = 1
281
        case cbTCA8:
282
                bpp = 4
283
        case cbTC16:
284
                bpp = 6
285
        case cbTCA16:
286
                bpp = 8
287
        case cbG16:
288
                bpp = 2
289
        }
290
        // cr[*] and pr are the bytes for the current and previous row.
291
        // cr[0] is unfiltered (or equivalently, filtered with the ftNone filter).
292
        // cr[ft], for non-zero filter types ft, are buffers for transforming cr[0] under the
293
        // other PNG filter types. These buffers are allocated once and re-used for each row.
294
        // The +1 is for the per-row filter type, which is at cr[*][0].
295
        b := m.Bounds()
296
        var cr [nFilter][]uint8
297
        for i := range cr {
298
                cr[i] = make([]uint8, 1+bpp*b.Dx())
299
                cr[i][0] = uint8(i)
300
        }
301
        pr := make([]uint8, 1+bpp*b.Dx())
302
 
303
        for y := b.Min.Y; y < b.Max.Y; y++ {
304
                // Convert from colors to bytes.
305
                i := 1
306
                switch cb {
307
                case cbG8:
308
                        for x := b.Min.X; x < b.Max.X; x++ {
309
                                c := color.GrayModel.Convert(m.At(x, y)).(color.Gray)
310
                                cr[0][i] = c.Y
311
                                i++
312
                        }
313
                case cbTC8:
314
                        // We have previously verified that the alpha value is fully opaque.
315
                        cr0 := cr[0]
316
                        if rgba, _ := m.(*image.RGBA); rgba != nil {
317
                                j0 := (y - b.Min.Y) * rgba.Stride
318
                                j1 := j0 + b.Dx()*4
319
                                for j := j0; j < j1; j += 4 {
320
                                        cr0[i+0] = rgba.Pix[j+0]
321
                                        cr0[i+1] = rgba.Pix[j+1]
322
                                        cr0[i+2] = rgba.Pix[j+2]
323
                                        i += 3
324
                                }
325
                        } else {
326
                                for x := b.Min.X; x < b.Max.X; x++ {
327
                                        r, g, b, _ := m.At(x, y).RGBA()
328
                                        cr0[i+0] = uint8(r >> 8)
329
                                        cr0[i+1] = uint8(g >> 8)
330
                                        cr0[i+2] = uint8(b >> 8)
331
                                        i += 3
332
                                }
333
                        }
334
                case cbP8:
335
                        if p, _ := m.(*image.Paletted); p != nil {
336
                                offset := (y - b.Min.Y) * p.Stride
337
                                copy(cr[0][1:], p.Pix[offset:offset+b.Dx()])
338
                        } else {
339
                                pi := m.(image.PalettedImage)
340
                                for x := b.Min.X; x < b.Max.X; x++ {
341
                                        cr[0][i] = pi.ColorIndexAt(x, y)
342
                                        i += 1
343
                                }
344
                        }
345
                case cbTCA8:
346
                        // Convert from image.Image (which is alpha-premultiplied) to PNG's non-alpha-premultiplied.
347
                        for x := b.Min.X; x < b.Max.X; x++ {
348
                                c := color.NRGBAModel.Convert(m.At(x, y)).(color.NRGBA)
349
                                cr[0][i+0] = c.R
350
                                cr[0][i+1] = c.G
351
                                cr[0][i+2] = c.B
352
                                cr[0][i+3] = c.A
353
                                i += 4
354
                        }
355
                case cbG16:
356
                        for x := b.Min.X; x < b.Max.X; x++ {
357
                                c := color.Gray16Model.Convert(m.At(x, y)).(color.Gray16)
358
                                cr[0][i+0] = uint8(c.Y >> 8)
359
                                cr[0][i+1] = uint8(c.Y)
360
                                i += 2
361
                        }
362
                case cbTC16:
363
                        // We have previously verified that the alpha value is fully opaque.
364
                        for x := b.Min.X; x < b.Max.X; x++ {
365
                                r, g, b, _ := m.At(x, y).RGBA()
366
                                cr[0][i+0] = uint8(r >> 8)
367
                                cr[0][i+1] = uint8(r)
368
                                cr[0][i+2] = uint8(g >> 8)
369
                                cr[0][i+3] = uint8(g)
370
                                cr[0][i+4] = uint8(b >> 8)
371
                                cr[0][i+5] = uint8(b)
372
                                i += 6
373
                        }
374
                case cbTCA16:
375
                        // Convert from image.Image (which is alpha-premultiplied) to PNG's non-alpha-premultiplied.
376
                        for x := b.Min.X; x < b.Max.X; x++ {
377
                                c := color.NRGBA64Model.Convert(m.At(x, y)).(color.NRGBA64)
378
                                cr[0][i+0] = uint8(c.R >> 8)
379
                                cr[0][i+1] = uint8(c.R)
380
                                cr[0][i+2] = uint8(c.G >> 8)
381
                                cr[0][i+3] = uint8(c.G)
382
                                cr[0][i+4] = uint8(c.B >> 8)
383
                                cr[0][i+5] = uint8(c.B)
384
                                cr[0][i+6] = uint8(c.A >> 8)
385
                                cr[0][i+7] = uint8(c.A)
386
                                i += 8
387
                        }
388
                }
389
 
390
                // Apply the filter.
391
                f := filter(&cr, pr, bpp)
392
 
393
                // Write the compressed bytes.
394
                _, err = zw.Write(cr[f])
395
                if err != nil {
396
                        return err
397
                }
398
 
399
                // The current row for y is the previous row for y+1.
400
                pr, cr[0] = cr[0], pr
401
        }
402
        return nil
403
}
404
 
405
// Write the actual image data to one or more IDAT chunks.
406
func (e *encoder) writeIDATs() {
407
        if e.err != nil {
408
                return
409
        }
410
        var bw *bufio.Writer
411
        bw = bufio.NewWriterSize(e, 1<<15)
412
        e.err = writeImage(bw, e.m, e.cb)
413
        if e.err != nil {
414
                return
415
        }
416
        e.err = bw.Flush()
417
}
418
 
419
func (e *encoder) writeIEND() { e.writeChunk(e.tmp[0:0], "IEND") }
420
 
421
// Encode writes the Image m to w in PNG format. Any Image may be encoded, but
422
// images that are not image.NRGBA might be encoded lossily.
423
func Encode(w io.Writer, m image.Image) error {
424
        // Obviously, negative widths and heights are invalid. Furthermore, the PNG
425
        // spec section 11.2.2 says that zero is invalid. Excessively large images are
426
        // also rejected.
427
        mw, mh := int64(m.Bounds().Dx()), int64(m.Bounds().Dy())
428
        if mw <= 0 || mh <= 0 || mw >= 1<<32 || mh >= 1<<32 {
429
                return FormatError("invalid image size: " + strconv.FormatInt(mw, 10) + "x" + strconv.FormatInt(mw, 10))
430
        }
431
 
432
        var e encoder
433
        e.w = w
434
        e.m = m
435
 
436
        var pal color.Palette
437
        // cbP8 encoding needs PalettedImage's ColorIndexAt method.
438
        if _, ok := m.(image.PalettedImage); ok {
439
                pal, _ = m.ColorModel().(color.Palette)
440
        }
441
        if pal != nil {
442
                e.cb = cbP8
443
        } else {
444
                switch m.ColorModel() {
445
                case color.GrayModel:
446
                        e.cb = cbG8
447
                case color.Gray16Model:
448
                        e.cb = cbG16
449
                case color.RGBAModel, color.NRGBAModel, color.AlphaModel:
450
                        if opaque(m) {
451
                                e.cb = cbTC8
452
                        } else {
453
                                e.cb = cbTCA8
454
                        }
455
                default:
456
                        if opaque(m) {
457
                                e.cb = cbTC16
458
                        } else {
459
                                e.cb = cbTCA16
460
                        }
461
                }
462
        }
463
 
464
        _, e.err = io.WriteString(w, pngHeader)
465
        e.writeIHDR()
466
        if pal != nil {
467
                e.writePLTE(pal)
468
                e.maybeWritetRNS(pal)
469
        }
470
        e.writeIDATs()
471
        e.writeIEND()
472
        return e.err
473
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.