diff options
Diffstat (limited to 'src/pkg/image/png')
-rw-r--r-- | src/pkg/image/png/reader_test.go | 20 | ||||
-rw-r--r-- | src/pkg/image/png/testdata/pngsuite/README | 3 | ||||
-rw-r--r-- | src/pkg/image/png/testdata/pngsuite/basn3p08-trns.png | bin | 0 -> 1538 bytes | |||
-rw-r--r-- | src/pkg/image/png/testdata/pngsuite/basn3p08-trns.sng | 301 | ||||
-rw-r--r-- | src/pkg/image/png/writer.go | 98 | ||||
-rw-r--r-- | src/pkg/image/png/writer_test.go | 73 |
6 files changed, 429 insertions, 66 deletions
diff --git a/src/pkg/image/png/reader_test.go b/src/pkg/image/png/reader_test.go index efa6336d7..bcc1a3db4 100644 --- a/src/pkg/image/png/reader_test.go +++ b/src/pkg/image/png/reader_test.go @@ -28,6 +28,7 @@ var filenames = []string{ "basn3p02", "basn3p04", "basn3p08", + "basn3p08-trns", "basn4a08", "basn4a16", "basn6a08", @@ -98,17 +99,30 @@ func sng(w io.WriteCloser, filename string, png image.Image) { // (the PNG spec section 11.3 says "Ancillary chunks may be ignored by a decoder"). io.WriteString(w, "gAMA {1.0000}\n") - // Write the PLTE (if applicable). + // Write the PLTE and tRNS (if applicable). if cpm != nil { + lastAlpha := -1 io.WriteString(w, "PLTE {\n") - for i := 0; i < len(cpm); i++ { - r, g, b, _ := cpm[i].RGBA() + for i, c := range cpm { + r, g, b, a := c.RGBA() + if a != 0xffff { + lastAlpha = i + } r >>= 8 g >>= 8 b >>= 8 fmt.Fprintf(w, " (%3d,%3d,%3d) # rgb = (0x%02x,0x%02x,0x%02x)\n", r, g, b, r, g, b) } io.WriteString(w, "}\n") + if lastAlpha != -1 { + io.WriteString(w, "tRNS {\n") + for i := 0; i <= lastAlpha; i++ { + _, _, _, a := cpm[i].RGBA() + a >>= 8 + fmt.Fprintf(w, " %d", a) + } + io.WriteString(w, "}\n") + } } // Write the IMAGE. diff --git a/src/pkg/image/png/testdata/pngsuite/README b/src/pkg/image/png/testdata/pngsuite/README index abe3ecb20..c0f78bde8 100644 --- a/src/pkg/image/png/testdata/pngsuite/README +++ b/src/pkg/image/png/testdata/pngsuite/README @@ -10,6 +10,9 @@ The files basn0g01-30.png, basn0g02-29.png and basn0g04-31.png are in fact not part of pngsuite but were created from files in pngsuite. Their non-power- of-two sizes makes them useful for testing bit-depths smaller than a byte. +basn3a08.png was generated from basn6a08.png using the pngnq tool, which +converted it to the 8-bit paletted image with alpha values in tRNS chunk. + The *.sng files in this directory were generated from the *.png files by the sng command-line tool and some hand editing. The files basn0g0{1,2,4}.sng were actually generated by first converting the PNG diff --git a/src/pkg/image/png/testdata/pngsuite/basn3p08-trns.png b/src/pkg/image/png/testdata/pngsuite/basn3p08-trns.png Binary files differnew file mode 100644 index 000000000..b0fc0c1be --- /dev/null +++ b/src/pkg/image/png/testdata/pngsuite/basn3p08-trns.png diff --git a/src/pkg/image/png/testdata/pngsuite/basn3p08-trns.sng b/src/pkg/image/png/testdata/pngsuite/basn3p08-trns.sng new file mode 100644 index 000000000..78dc367bb --- /dev/null +++ b/src/pkg/image/png/testdata/pngsuite/basn3p08-trns.sng @@ -0,0 +1,301 @@ +#SNG: from basn3p08-trns.png +IHDR { + width: 32; height: 32; bitdepth: 8; + using color palette; +} +gAMA {1.0000} +PLTE { + (255, 3, 7) # rgb = (0xff,0x03,0x07) + (255, 4, 7) # rgb = (0xff,0x04,0x07) + (255, 9, 7) # rgb = (0xff,0x09,0x07) + (217, 14, 7) # rgb = (0xd9,0x0e,0x07) + (255, 14, 7) # rgb = (0xff,0x0e,0x07) + ( 2, 22, 19) # rgb = (0x02,0x16,0x13) + (255, 26, 7) # rgb = (0xff,0x1a,0x07) + (255, 31, 7) # rgb = (0xff,0x1f,0x07) + ( 10, 37, 14) # rgb = (0x0a,0x25,0x0e) + (179, 37, 6) # rgb = (0xb3,0x25,0x06) + (254, 42, 7) # rgb = (0xfe,0x2a,0x07) + (255, 45, 7) # rgb = (0xff,0x2d,0x07) + ( 25, 46, 9) # rgb = (0x19,0x2e,0x09) + ( 0, 48,254) # rgb = (0x00,0x30,0xfe) + ( 0, 48,255) # rgb = (0x00,0x30,0xff) + ( 0, 49,255) # rgb = (0x00,0x31,0xff) + ( 0, 51,254) # rgb = (0x00,0x33,0xfe) + ( 0, 52,255) # rgb = (0x00,0x34,0xff) + (255, 53, 7) # rgb = (0xff,0x35,0x07) + ( 0, 54,252) # rgb = (0x00,0x36,0xfc) + (254, 57, 7) # rgb = (0xfe,0x39,0x07) + (251, 57, 7) # rgb = (0xfb,0x39,0x07) + (247, 59, 7) # rgb = (0xf7,0x3b,0x07) + ( 0, 59, 61) # rgb = (0x00,0x3b,0x3d) + ( 0, 62,255) # rgb = (0x00,0x3e,0xff) + (142, 63, 5) # rgb = (0x8e,0x3f,0x05) + ( 0, 63,250) # rgb = (0x00,0x3f,0xfa) + (255, 63, 7) # rgb = (0xff,0x3f,0x07) + (253, 68, 7) # rgb = (0xfd,0x44,0x07) + ( 0, 73,255) # rgb = (0x00,0x49,0xff) + ( 0, 73,246) # rgb = (0x00,0x49,0xf6) + (255, 75, 7) # rgb = (0xff,0x4b,0x07) + ( 82, 85, 9) # rgb = (0x52,0x55,0x09) + (255, 85, 7) # rgb = (0xff,0x55,0x07) + ( 0, 89,255) # rgb = (0x00,0x59,0xff) + ( 0, 91,237) # rgb = (0x00,0x5b,0xed) + (255, 94, 7) # rgb = (0xff,0x5e,0x07) + (241,100, 7) # rgb = (0xf1,0x64,0x07) + ( 0,101,255) # rgb = (0x00,0x65,0xff) + (253,105, 7) # rgb = (0xfd,0x69,0x07) + ( 0,107,223) # rgb = (0x00,0x6b,0xdf) + (255,106, 7) # rgb = (0xff,0x6a,0x07) + ( 1,110, 95) # rgb = (0x01,0x6e,0x5f) + (255,115, 7) # rgb = (0xff,0x73,0x07) + ( 0,117,255) # rgb = (0x00,0x75,0xff) + (255,124, 7) # rgb = (0xff,0x7c,0x07) + (118,126, 10) # rgb = (0x76,0x7e,0x0a) + ( 0,130,250) # rgb = (0x00,0x82,0xfa) + ( 0,132,255) # rgb = (0x00,0x84,0xff) + ( 0,134,207) # rgb = (0x00,0x86,0xcf) + (255,134, 7) # rgb = (0xff,0x86,0x07) + ( 0,136,249) # rgb = (0x00,0x88,0xf9) + (219,140, 6) # rgb = (0xdb,0x8c,0x06) + ( 0,140,252) # rgb = (0x00,0x8c,0xfc) + ( 0,140,255) # rgb = (0x00,0x8c,0xff) + ( 1,142,136) # rgb = (0x01,0x8e,0x88) + (255,143, 7) # rgb = (0xff,0x8f,0x07) + (243,150, 7) # rgb = (0xf3,0x96,0x07) + (198,152, 7) # rgb = (0xc6,0x98,0x07) + (165,153, 7) # rgb = (0xa5,0x99,0x07) + ( 0,157,255) # rgb = (0x00,0x9d,0xff) + (255,158, 7) # rgb = (0xff,0x9e,0x07) + ( 70,159, 4) # rgb = (0x46,0x9f,0x04) + ( 0,160,251) # rgb = (0x00,0xa0,0xfb) + (203,163, 6) # rgb = (0xcb,0xa3,0x06) + ( 0,163,239) # rgb = (0x00,0xa3,0xef) + ( 1,164,178) # rgb = (0x01,0xa4,0xb2) + (255,166, 7) # rgb = (0xff,0xa6,0x07) + ( 1,169,165) # rgb = (0x01,0xa9,0xa5) + ( 1,170,255) # rgb = (0x01,0xaa,0xff) + (232,172, 6) # rgb = (0xe8,0xac,0x06) + (255,175, 7) # rgb = (0xff,0xaf,0x07) + (185,176,131) # rgb = (0xb9,0xb0,0x83) + ( 1,179,225) # rgb = (0x01,0xb3,0xe1) + (188,179,118) # rgb = (0xbc,0xb3,0x76) + (199,180, 6) # rgb = (0xc7,0xb4,0x06) + ( 1,182,255) # rgb = (0x01,0xb6,0xff) + ( 1,184,249) # rgb = (0x01,0xb8,0xf9) + (255,184, 7) # rgb = (0xff,0xb8,0x07) + (207,186, 71) # rgb = (0xcf,0xba,0x47) + (193,187, 6) # rgb = (0xc1,0xbb,0x06) + (253,191, 7) # rgb = (0xfd,0xbf,0x07) + (218,193, 48) # rgb = (0xda,0xc1,0x30) + ( 1,193,157) # rgb = (0x01,0xc1,0x9d) + ( 1,196,244) # rgb = (0x01,0xc4,0xf4) + ( 1,196,254) # rgb = (0x01,0xc4,0xfe) + ( 48,199, 3) # rgb = (0x30,0xc7,0x03) + (164,199, 5) # rgb = (0xa4,0xc7,0x05) + (220,202, 6) # rgb = (0xdc,0xca,0x06) + (253,203, 7) # rgb = (0xfd,0xcb,0x07) + ( 1,204,204) # rgb = (0x01,0xcc,0xcc) + (251,209, 7) # rgb = (0xfb,0xd1,0x07) + (231,208, 24) # rgb = (0xe7,0xd0,0x18) + ( 1,210,254) # rgb = (0x01,0xd2,0xfe) + ( 2,211,146) # rgb = (0x02,0xd3,0x92) + ( 1,212,156) # rgb = (0x01,0xd4,0x9c) + ( 1,213,252) # rgb = (0x01,0xd5,0xfc) + (237,219, 15) # rgb = (0xed,0xdb,0x0f) + ( 1,218,240) # rgb = (0x01,0xda,0xf0) + (165,220, 5) # rgb = (0xa5,0xdc,0x05) + ( 1,221,250) # rgb = (0x01,0xdd,0xfa) + (249,221, 6) # rgb = (0xf9,0xdd,0x06) + (146,222, 4) # rgb = (0x92,0xde,0x04) + ( 1,224,184) # rgb = (0x01,0xe0,0xb8) + ( 2,224,155) # rgb = (0x02,0xe0,0x9b) + (244,225, 10) # rgb = (0xf4,0xe1,0x0a) + (249,227, 7) # rgb = (0xf9,0xe3,0x07) + ( 2,229,133) # rgb = (0x02,0xe5,0x85) + (192,228, 6) # rgb = (0xc0,0xe4,0x06) + ( 37,230, 3) # rgb = (0x25,0xe6,0x03) + (246,230, 7) # rgb = (0xf6,0xe6,0x07) + (143,232, 4) # rgb = (0x8f,0xe8,0x04) + (244,233, 8) # rgb = (0xf4,0xe9,0x08) + ( 2,236,139) # rgb = (0x02,0xec,0x8b) + ( 1,236,227) # rgb = (0x01,0xec,0xe3) + ( 1,238,238) # rgb = (0x01,0xee,0xee) + (101,241, 4) # rgb = (0x65,0xf1,0x04) + ( 1,241,218) # rgb = (0x01,0xf1,0xda) + ( 1,240,232) # rgb = (0x01,0xf0,0xe8) + (167,240, 5) # rgb = (0xa7,0xf0,0x05) + ( 27,243, 2) # rgb = (0x1b,0xf3,0x02) + (126,243, 4) # rgb = (0x7e,0xf3,0x04) + ( 2,246,113) # rgb = (0x02,0xf6,0x71) + (133,248, 5) # rgb = (0x85,0xf8,0x05) + ( 22,250, 1) # rgb = (0x16,0xfa,0x01) + ( 2,249,219) # rgb = (0x02,0xf9,0xdb) + (148,250, 5) # rgb = (0x94,0xfa,0x05) + ( 2,250,199) # rgb = (0x02,0xfa,0xc7) + (183,252, 5) # rgb = (0xb7,0xfc,0x05) + (176,252, 5) # rgb = (0xb0,0xfc,0x05) + ( 2,252,211) # rgb = (0x02,0xfc,0xd3) + ( 2,252,190) # rgb = (0x02,0xfc,0xbe) + (164,251, 5) # rgb = (0xa4,0xfb,0x05) + ( 12,254,128) # rgb = (0x0c,0xfe,0x80) + (192,253, 5) # rgb = (0xc0,0xfd,0x05) + (164,253, 5) # rgb = (0xa4,0xfd,0x05) + ( 26,254, 85) # rgb = (0x1a,0xfe,0x55) + ( 14,254, 1) # rgb = (0x0e,0xfe,0x01) + (133,253, 5) # rgb = (0x85,0xfd,0x05) + ( 4,253,180) # rgb = (0x04,0xfd,0xb4) + (196,253, 5) # rgb = (0xc4,0xfd,0x05) + ( 2,253,198) # rgb = (0x02,0xfd,0xc6) + ( 3,255, 91) # rgb = (0x03,0xff,0x5b) + ( 3,255, 80) # rgb = (0x03,0xff,0x50) + (186,255, 5) # rgb = (0xba,0xff,0x05) + ( 9,255, 2) # rgb = (0x09,0xff,0x02) + ( 3,255,118) # rgb = (0x03,0xff,0x76) + ( 9,255, 3) # rgb = (0x09,0xff,0x03) + ( 10,255, 1) # rgb = (0x0a,0xff,0x01) + ( 3,255, 76) # rgb = (0x03,0xff,0x4c) + ( 3,255, 86) # rgb = (0x03,0xff,0x56) + ( 3,255, 82) # rgb = (0x03,0xff,0x52) + ( 13,255, 1) # rgb = (0x0d,0xff,0x01) + ( 3,255, 49) # rgb = (0x03,0xff,0x31) + ( 3,255,101) # rgb = (0x03,0xff,0x65) + ( 61,255, 32) # rgb = (0x3d,0xff,0x20) + (129,255, 5) # rgb = (0x81,0xff,0x05) + (177,255, 5) # rgb = (0xb1,0xff,0x05) + ( 3,255, 37) # rgb = (0x03,0xff,0x25) + (149,255, 5) # rgb = (0x95,0xff,0x05) + ( 7,255, 6) # rgb = (0x07,0xff,0x06) + (192,255, 5) # rgb = (0xc0,0xff,0x05) + ( 2,255,131) # rgb = (0x02,0xff,0x83) + ( 3,255, 98) # rgb = (0x03,0xff,0x62) + ( 85,255, 11) # rgb = (0x55,0xff,0x0b) + ( 2,255,163) # rgb = (0x02,0xff,0xa3) + ( 2,255,149) # rgb = (0x02,0xff,0x95) + ( 4,255, 23) # rgb = (0x04,0xff,0x17) + ( 6,255, 12) # rgb = (0x06,0xff,0x0c) + ( 3,255, 67) # rgb = (0x03,0xff,0x43) + (160,255, 5) # rgb = (0xa0,0xff,0x05) + (119,255, 6) # rgb = (0x77,0xff,0x06) + (102,255, 8) # rgb = (0x66,0xff,0x08) + (255,255,255) # rgb = (0xff,0xff,0xff) + (254,254,254) # rgb = (0xfe,0xfe,0xfe) + (254,254,254) # rgb = (0xfe,0xfe,0xfe) + (252,252,252) # rgb = (0xfc,0xfc,0xfc) + (252,252,252) # rgb = (0xfc,0xfc,0xfc) + (250,250,250) # rgb = (0xfa,0xfa,0xfa) + (250,250,250) # rgb = (0xfa,0xfa,0xfa) + (248,248,248) # rgb = (0xf8,0xf8,0xf8) + (248,248,248) # rgb = (0xf8,0xf8,0xf8) + (247,247,247) # rgb = (0xf7,0xf7,0xf7) + (245,245,245) # rgb = (0xf5,0xf5,0xf5) + (245,245,245) # rgb = (0xf5,0xf5,0xf5) + (243,243,243) # rgb = (0xf3,0xf3,0xf3) + (243,243,243) # rgb = (0xf3,0xf3,0xf3) + (241,241,241) # rgb = (0xf1,0xf1,0xf1) + (241,241,241) # rgb = (0xf1,0xf1,0xf1) + (239,239,239) # rgb = (0xef,0xef,0xef) + (238,238,238) # rgb = (0xee,0xee,0xee) + (238,238,238) # rgb = (0xee,0xee,0xee) + (236,236,236) # rgb = (0xec,0xec,0xec) + (236,236,236) # rgb = (0xec,0xec,0xec) + (234,234,234) # rgb = (0xea,0xea,0xea) + (234,234,234) # rgb = (0xea,0xea,0xea) + (232,232,232) # rgb = (0xe8,0xe8,0xe8) + (231,231,231) # rgb = (0xe7,0xe7,0xe7) + (231,231,231) # rgb = (0xe7,0xe7,0xe7) + (229,229,229) # rgb = (0xe5,0xe5,0xe5) + (229,229,229) # rgb = (0xe5,0xe5,0xe5) + (227,227,227) # rgb = (0xe3,0xe3,0xe3) + (226,226,226) # rgb = (0xe2,0xe2,0xe2) + (226,226,226) # rgb = (0xe2,0xe2,0xe2) + (224,224,224) # rgb = (0xe0,0xe0,0xe0) + (224,224,224) # rgb = (0xe0,0xe0,0xe0) + (222,222,222) # rgb = (0xde,0xde,0xde) + (222,222,222) # rgb = (0xde,0xde,0xde) + (220,220,220) # rgb = (0xdc,0xdc,0xdc) + (219,219,219) # rgb = (0xdb,0xdb,0xdb) + (219,219,219) # rgb = (0xdb,0xdb,0xdb) + (217,217,217) # rgb = (0xd9,0xd9,0xd9) + (217,217,217) # rgb = (0xd9,0xd9,0xd9) + (215,215,215) # rgb = (0xd7,0xd7,0xd7) + (214,214,214) # rgb = (0xd6,0xd6,0xd6) + (214,214,214) # rgb = (0xd6,0xd6,0xd6) + (212,212,212) # rgb = (0xd4,0xd4,0xd4) + (212,212,212) # rgb = (0xd4,0xd4,0xd4) + (210,210,210) # rgb = (0xd2,0xd2,0xd2) + (209,209,209) # rgb = (0xd1,0xd1,0xd1) + (209,209,209) # rgb = (0xd1,0xd1,0xd1) + (207,207,207) # rgb = (0xcf,0xcf,0xcf) + (205,205,205) # rgb = (0xcd,0xcd,0xcd) + (205,205,205) # rgb = (0xcd,0xcd,0xcd) + (204,204,204) # rgb = (0xcc,0xcc,0xcc) + (204,204,204) # rgb = (0xcc,0xcc,0xcc) + (202,202,202) # rgb = (0xca,0xca,0xca) + (201,201,201) # rgb = (0xc9,0xc9,0xc9) + (201,201,201) # rgb = (0xc9,0xc9,0xc9) + (199,199,199) # rgb = (0xc7,0xc7,0xc7) + (199,199,199) # rgb = (0xc7,0xc7,0xc7) + (197,197,197) # rgb = (0xc5,0xc5,0xc5) + (196,196,196) # rgb = (0xc4,0xc4,0xc4) + (196,196,196) # rgb = (0xc4,0xc4,0xc4) + (194,194,194) # rgb = (0xc2,0xc2,0xc2) + (193,193,193) # rgb = (0xc1,0xc1,0xc1) + (193,193,193) # rgb = (0xc1,0xc1,0xc1) + (191,191,191) # rgb = (0xbf,0xbf,0xbf) + (191,191,191) # rgb = (0xbf,0xbf,0xbf) + (189,189,189) # rgb = (0xbd,0xbd,0xbd) + (188,188,188) # rgb = (0xbc,0xbc,0xbc) + (188,188,188) # rgb = (0xbc,0xbc,0xbc) + (186,186,186) # rgb = (0xba,0xba,0xba) + (185,185,185) # rgb = (0xb9,0xb9,0xb9) + (185,185,185) # rgb = (0xb9,0xb9,0xb9) + (183,183,183) # rgb = (0xb7,0xb7,0xb7) + (182,182,182) # rgb = (0xb6,0xb6,0xb6) + (182,182,182) # rgb = (0xb6,0xb6,0xb6) + (180,180,180) # rgb = (0xb4,0xb4,0xb4) + (178,178,178) # rgb = (0xb2,0xb2,0xb2) + (178,178,178) # rgb = (0xb2,0xb2,0xb2) + (177,177,177) # rgb = (0xb1,0xb1,0xb1) + (177,177,177) # rgb = (0xb1,0xb1,0xb1) + (175,175,175) # rgb = (0xaf,0xaf,0xaf) + (174,174,174) # rgb = (0xae,0xae,0xae) + (174,174,174) # rgb = (0xae,0xae,0xae) +} +tRNS { + 197 187 190 194 186 4 186 189 4 195 84 191 5 193 175 163 205 150 191 213 88 75 67 8 147 191 220 203 95 151 223 199 8 207 156 227 199 65 163 98 226 204 12 202 167 201 11 65 178 228 205 74 59 87 178 19 201 99 18 14 184 204 184 96 22 61 227 199 22 193 97 197 254 59 253 28 192 102 199 247 58 198 244 30 109 202 188 32 96 196 60 203 239 202 230 41 207 237 119 53 213 209 37 55 45 230 214 233 92 185 223 50 230 57 124 217 43 133 221 95 198 47 233 99 194 221 107 138 152 144 226 140 133 220 172 125 218 196 118 225 161 223 235 238 200 155 147 146 172 236 236 151 183 150 234 216 217 211 151 219 132 185 145 147 217 138 144 137 142 151 217 217 213} +IMAGE { + pixels hex +0520201616160a0a0a0a0a0a0a0a010101010101010101000000000000000000 +053a3a161616160a0a0a0a0a0a0a0a0a0a06060606060607070707070707071b +053a3a3a161616161615151c1c1c1c1c1c1c12121212121b1b1b1b1b1b1b1b1b +053a3a3a3a252525252527272727272727272724242424242424212121212121 +053a3a3a4034343425252727272727393939392d2d2d2d2d2d2d323232323232 +053a3a404034343434343939393939393939394747474343433d3d3d3d3d3d3d +053a404b4b4b50505046464646464646464659595959595151514e5b5b616161 +053a404b4b4b50505058585858585858588c8c8c595959595b656a6e70707070 +053a4b4b4b4b5050506c5858585858588c8c8c8c8c8c5965656a6a6e70707070 +053b4b4b4b636363506c6c6c6c6c6c8781808c8c8c86a1a1a1906e6e70707070 +053b4b5757636363636c6c6c6c7787878181808c8c86a1a190909d9d9d9daa70 +053b576666666f6363777777777e8787848481808086a19090aaaaaaaa9f9f9f +053b576666797979797b7b7b7b7b8a8a8a8a848480809c9c9c9c9c9c9c9c9c9c +053b66747474747474747b7b7b7b8a8a8a8a8a8aacacacacacacacacacaca4a4 +052e7474747474747474747b7b7b8a8a8a6d6d6d6d6d6d6da4a4a4a4a4a4a4a4 +052e7474747474747474a0a0a0a0a0a09393936d6d6d6d787878787878787878 +05207474747474a0a0a0a0a0a0a0a0a093939191949494948989898989898989 +052a2a2a7171717171a7a7a7a7a7a7a7a7a79e9e9e9e9e9e9e9e959595959595 +052a53536871717171717171a9a9a9a9a9a9a9a9a9a9a9a99595959595959595 +053753536871717171717171a3a3a3a3a3a3a3a3979797979a9a9a9a8e8e8e8e +05445353686871717171717171a5a2a2a2a2a2929292928585857a7a7a7a7a7a +054453535f68687171717171a5a5a5a5a5a5a6a6a6a6a68b8b8b8b8b8b8b8b6b +054444535f686767676767677272727f7f8383838383838d8d8d8d8d8d8d8b8b +054444535f6767675a5a5a627272727275757f7f7f7f5d73737d7d7d82828282 +0544445367675a5a5a5a4d546262727272757575755d5d5d7373737376767676 +054444535349495a5a5a4d4d54626262626275754c5d5d5d5d60646464767676 +054444444949494949494d4d4d5454546262624c4c4c4c4c5555556060646464 +05444444444941414133353f3f3f3f3f3f4d3636363c3c454545454531313131 +05444444442f2f2f2f333535353535352c2c2c2c2c3030303030282828282828 +053744442f2f2f2f2f2f333535351d1d22222222262626262323232323232323 +053737372f2f2f2f2f2f2f331818181818181d1d1d1d1d131a1a1a1a1a1e1e1e +052a37372f2f2f2f2f2f18111111110f0e0e0e0e0d0d0d0d0d0d0d0d0d0d0d13 +} diff --git a/src/pkg/image/png/writer.go b/src/pkg/image/png/writer.go index 2d593f6a7..d770cfad5 100644 --- a/src/pkg/image/png/writer.go +++ b/src/pkg/image/png/writer.go @@ -130,12 +130,8 @@ func (e *encoder) writePLTE(p image.PalettedColorModel) { e.err = FormatError("bad palette length: " + strconv.Itoa(len(p))) return } - for i := 0; i < len(p); i++ { - r, g, b, a := p[i].RGBA() - if a != 0xffff { - e.err = UnsupportedError("non-opaque palette color") - return - } + for i, c := range p { + r, g, b, _ := c.RGBA() e.tmp[3*i+0] = uint8(r >> 8) e.tmp[3*i+1] = uint8(g >> 8) e.tmp[3*i+2] = uint8(b >> 8) @@ -143,6 +139,21 @@ func (e *encoder) writePLTE(p image.PalettedColorModel) { e.writeChunk(e.tmp[0:3*len(p)], "PLTE") } +func (e *encoder) maybeWritetRNS(p image.PalettedColorModel) { + last := -1 + for i, c := range p { + _, _, _, a := c.RGBA() + if a != 0xffff { + last = i + } + e.tmp[i] = uint8(a >> 8) + } + if last == -1 { + return + } + e.writeChunk(e.tmp[:last+1], "tRNS") +} + // An encoder is an io.Writer that satisfies writes by writing PNG IDAT chunks, // including an 8-byte header and 4-byte CRC checksum per Write call. Such calls // should be relatively infrequent, since writeIDATs uses a bufio.Writer. @@ -163,7 +174,7 @@ func (e *encoder) Write(b []byte) (int, os.Error) { // Chooses the filter to use for encoding the current row, and applies it. // The return value is the index of the filter and also of the row in cr that has had it applied. -func filter(cr [][]byte, pr []byte, bpp int) int { +func filter(cr *[nFilter][]byte, pr []byte, bpp int) int { // We try all five filter types, and pick the one that minimizes the sum of absolute differences. // This is the same heuristic that libpng uses, although the filters are attempted in order of // estimated most likely to be minimal (ftUp, ftPaeth, ftNone, ftSub, ftAverage), rather than @@ -293,7 +304,7 @@ func writeImage(w io.Writer, m image.Image, cb int) os.Error { // The +1 is for the per-row filter type, which is at cr[*][0]. b := m.Bounds() var cr [nFilter][]uint8 - for i := 0; i < len(cr); i++ { + for i := range cr { cr[i] = make([]uint8, 1+bpp*b.Dx()) cr[i][0] = uint8(i) } @@ -301,78 +312,84 @@ func writeImage(w io.Writer, m image.Image, cb int) os.Error { for y := b.Min.Y; y < b.Max.Y; y++ { // Convert from colors to bytes. + i := 1 switch cb { case cbG8: for x := b.Min.X; x < b.Max.X; x++ { c := image.GrayColorModel.Convert(m.At(x, y)).(image.GrayColor) - cr[0][x+1] = c.Y + cr[0][i] = c.Y + i++ } case cbTC8: // We have previously verified that the alpha value is fully opaque. cr0 := cr[0] if rgba != nil { yoff := y * rgba.Stride - xoff := 3*b.Min.X + 1 for _, color := range rgba.Pix[yoff+b.Min.X : yoff+b.Max.X] { - cr0[xoff] = color.R - cr0[xoff+1] = color.G - cr0[xoff+2] = color.B - xoff += 3 + cr0[i+0] = color.R + cr0[i+1] = color.G + cr0[i+2] = color.B + i += 3 } } else { for x := b.Min.X; x < b.Max.X; x++ { r, g, b, _ := m.At(x, y).RGBA() - cr0[3*x+1] = uint8(r >> 8) - cr0[3*x+2] = uint8(g >> 8) - cr0[3*x+3] = uint8(b >> 8) + cr0[i+0] = uint8(r >> 8) + cr0[i+1] = uint8(g >> 8) + cr0[i+2] = uint8(b >> 8) + i += 3 } } case cbP8: rowOffset := y * paletted.Stride - copy(cr[0][b.Min.X+1:], paletted.Pix[rowOffset+b.Min.X:rowOffset+b.Max.X]) + copy(cr[0][1:], paletted.Pix[rowOffset+b.Min.X:rowOffset+b.Max.X]) case cbTCA8: // Convert from image.Image (which is alpha-premultiplied) to PNG's non-alpha-premultiplied. for x := b.Min.X; x < b.Max.X; x++ { c := image.NRGBAColorModel.Convert(m.At(x, y)).(image.NRGBAColor) - cr[0][4*x+1] = c.R - cr[0][4*x+2] = c.G - cr[0][4*x+3] = c.B - cr[0][4*x+4] = c.A + cr[0][i+0] = c.R + cr[0][i+1] = c.G + cr[0][i+2] = c.B + cr[0][i+3] = c.A + i += 4 } case cbG16: for x := b.Min.X; x < b.Max.X; x++ { c := image.Gray16ColorModel.Convert(m.At(x, y)).(image.Gray16Color) - cr[0][2*x+1] = uint8(c.Y >> 8) - cr[0][2*x+2] = uint8(c.Y) + cr[0][i+0] = uint8(c.Y >> 8) + cr[0][i+1] = uint8(c.Y) + i += 2 } case cbTC16: + // We have previously verified that the alpha value is fully opaque. for x := b.Min.X; x < b.Max.X; x++ { - // We have previously verified that the alpha value is fully opaque. r, g, b, _ := m.At(x, y).RGBA() - cr[0][6*x+1] = uint8(r >> 8) - cr[0][6*x+2] = uint8(r) - cr[0][6*x+3] = uint8(g >> 8) - cr[0][6*x+4] = uint8(g) - cr[0][6*x+5] = uint8(b >> 8) - cr[0][6*x+6] = uint8(b) + cr[0][i+0] = uint8(r >> 8) + cr[0][i+1] = uint8(r) + cr[0][i+2] = uint8(g >> 8) + cr[0][i+3] = uint8(g) + cr[0][i+4] = uint8(b >> 8) + cr[0][i+5] = uint8(b) + i += 6 } case cbTCA16: // Convert from image.Image (which is alpha-premultiplied) to PNG's non-alpha-premultiplied. for x := b.Min.X; x < b.Max.X; x++ { c := image.NRGBA64ColorModel.Convert(m.At(x, y)).(image.NRGBA64Color) - cr[0][8*x+1] = uint8(c.R >> 8) - cr[0][8*x+2] = uint8(c.R) - cr[0][8*x+3] = uint8(c.G >> 8) - cr[0][8*x+4] = uint8(c.G) - cr[0][8*x+5] = uint8(c.B >> 8) - cr[0][8*x+6] = uint8(c.B) - cr[0][8*x+7] = uint8(c.A >> 8) - cr[0][8*x+8] = uint8(c.A) + cr[0][i+0] = uint8(c.R >> 8) + cr[0][i+1] = uint8(c.R) + cr[0][i+2] = uint8(c.G >> 8) + cr[0][i+3] = uint8(c.G) + cr[0][i+4] = uint8(c.B >> 8) + cr[0][i+5] = uint8(c.B) + cr[0][i+6] = uint8(c.A >> 8) + cr[0][i+7] = uint8(c.A) + i += 8 } } // Apply the filter. - f := filter(cr[0:nFilter], pr, bpp) + f := filter(&cr, pr, bpp) // Write the compressed bytes. _, err = zw.Write(cr[f]) @@ -447,6 +464,7 @@ func Encode(w io.Writer, m image.Image) os.Error { e.writeIHDR() if pal != nil { e.writePLTE(pal.Palette) + e.maybeWritetRNS(pal.Palette) } e.writeIDATs() e.writeIEND() diff --git a/src/pkg/image/png/writer_test.go b/src/pkg/image/png/writer_test.go index 6b054aaa8..271519a11 100644 --- a/src/pkg/image/png/writer_test.go +++ b/src/pkg/image/png/writer_test.go @@ -5,9 +5,9 @@ package png import ( + "bytes" "fmt" "image" - "io" "io/ioutil" "os" "testing" @@ -15,21 +15,38 @@ import ( func diff(m0, m1 image.Image) os.Error { b0, b1 := m0.Bounds(), m1.Bounds() - if !b0.Eq(b1) { + if !b0.Size().Eq(b1.Size()) { return fmt.Errorf("dimensions differ: %v vs %v", b0, b1) } + dx := b1.Min.X - b0.Min.X + dy := b1.Min.Y - b0.Min.Y for y := b0.Min.Y; y < b0.Max.Y; y++ { for x := b0.Min.X; x < b0.Max.X; x++ { - r0, g0, b0, a0 := m0.At(x, y).RGBA() - r1, g1, b1, a1 := m1.At(x, y).RGBA() + c0 := m0.At(x, y) + c1 := m1.At(x+dx, y+dy) + r0, g0, b0, a0 := c0.RGBA() + r1, g1, b1, a1 := c1.RGBA() if r0 != r1 || g0 != g1 || b0 != b1 || a0 != a1 { - return fmt.Errorf("colors differ at (%d, %d): %v vs %v", x, y, m0.At(x, y), m1.At(x, y)) + return fmt.Errorf("colors differ at (%d, %d): %v vs %v", x, y, c0, c1) } } } return nil } +func encodeDecode(m image.Image) (image.Image, os.Error) { + b := bytes.NewBuffer(nil) + err := Encode(b, m) + if err != nil { + return nil, err + } + m, err = Decode(b) + if err != nil { + return nil, err + } + return m, nil +} + func TestWriter(t *testing.T) { // The filenames variable is declared in reader_test.go. names := filenames @@ -44,26 +61,16 @@ func TestWriter(t *testing.T) { t.Error(fn, err) continue } - // Read the image again, and push it through a pipe that encodes at the write end, and decodes at the read end. - pr, pw := io.Pipe() - defer pr.Close() - go func() { - defer pw.Close() - m1, err := readPng(qfn) - if err != nil { - t.Error(fn, err) - return - } - err = Encode(pw, m1) - if err != nil { - t.Error(fn, err) - return - } - }() - m2, err := Decode(pr) + // Read the image again, encode it, and decode it. + m1, err := readPng(qfn) if err != nil { t.Error(fn, err) - continue + return + } + m2, err := encodeDecode(m1) + if err != nil { + t.Error(fn, err) + return } // Compare the two. err = diff(m0, m2) @@ -74,6 +81,26 @@ func TestWriter(t *testing.T) { } } +func TestSubimage(t *testing.T) { + m0 := image.NewRGBA(256, 256) + for y := 0; y < 256; y++ { + for x := 0; x < 256; x++ { + m0.Set(x, y, image.RGBAColor{uint8(x), uint8(y), 0, 255}) + } + } + m0.Rect = image.Rect(50, 30, 250, 130) + m1, err := encodeDecode(m0) + if err != nil { + t.Error(err) + return + } + err = diff(m0, m1) + if err != nil { + t.Error(err) + return + } +} + func BenchmarkEncodePaletted(b *testing.B) { b.StopTimer() img := image.NewPaletted(640, 480, |