Commit 4951c793 authored by Nigel Tao's avatar Nigel Tao

image/png: implement truecolor transparency.

Change-Id: I99b9a51db29d514ebaa9c1cfde65c0b5184c0f42
Reviewed-on: https://go-review.googlesource.com/32140Reviewed-by: 's avatarRob Pike <r@golang.org>
parent 0dabbcdc
......@@ -113,6 +113,11 @@ type decoder struct {
idatLength uint32
tmp [3 * 256]byte
interlace int
// useTransparent and transparent are used for grayscale and truecolor
// transparency, as opposed to palette transparency.
useTransparent bool
transparent [6]byte
}
// A FormatError reports that the input is not a valid PNG.
......@@ -252,20 +257,33 @@ func (d *decoder) parsePLTE(length uint32) error {
}
func (d *decoder) parsetRNS(length uint32) error {
if length > 256 {
return FormatError("bad tRNS length")
}
n, err := io.ReadFull(d.r, d.tmp[:length])
if err != nil {
return err
}
d.crc.Write(d.tmp[:n])
switch d.cb {
case cbG8, cbG16:
case cbG1, cbG2, cbG4, cbG8, cbG16:
return UnsupportedError("grayscale transparency")
case cbTC8, cbTC16:
return UnsupportedError("truecolor transparency")
if length != 6 {
return FormatError("bad tRNS length")
}
n, err := io.ReadFull(d.r, d.tmp[:length])
if err != nil {
return err
}
d.crc.Write(d.tmp[:n])
copy(d.transparent[:], d.tmp[:length])
d.useTransparent = true
case cbP1, cbP2, cbP4, cbP8:
if length > 256 {
return FormatError("bad tRNS length")
}
n, err := io.ReadFull(d.r, d.tmp[:length])
if err != nil {
return err
}
d.crc.Write(d.tmp[:n])
if len(d.palette) < n {
d.palette = d.palette[:n]
}
......@@ -273,7 +291,8 @@ func (d *decoder) parsetRNS(length uint32) error {
rgba := d.palette[i].(color.RGBA)
d.palette[i] = color.NRGBA{rgba.R, rgba.G, rgba.B, d.tmp[i]}
}
case cbGA8, cbGA16, cbTCA8, cbTCA16:
default:
return FormatError("tRNS, color type mismatch")
}
return d.verifyChecksum()
......@@ -366,7 +385,7 @@ func (d *decoder) decode() (image.Image, error) {
// readImagePass reads a single image pass, sized according to the pass number.
func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image.Image, error) {
var bitsPerPixel int = 0
bitsPerPixel := 0
pixOffset := 0
var (
gray *image.Gray
......@@ -402,8 +421,13 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
img = nrgba
case cbTC8:
bitsPerPixel = 24
rgba = image.NewRGBA(image.Rect(0, 0, width, height))
img = rgba
if d.useTransparent {
nrgba = image.NewNRGBA(image.Rect(0, 0, width, height))
img = nrgba
} else {
rgba = image.NewRGBA(image.Rect(0, 0, width, height))
img = rgba
}
case cbP1, cbP2, cbP4, cbP8:
bitsPerPixel = d.depth
paletted = image.NewPaletted(image.Rect(0, 0, width, height), d.palette)
......@@ -422,8 +446,13 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
img = nrgba64
case cbTC16:
bitsPerPixel = 48
rgba64 = image.NewRGBA64(image.Rect(0, 0, width, height))
img = rgba64
if d.useTransparent {
nrgba64 = image.NewNRGBA64(image.Rect(0, 0, width, height))
img = nrgba64
} else {
rgba64 = image.NewRGBA64(image.Rect(0, 0, width, height))
img = rgba64
}
case cbTCA16:
bitsPerPixel = 64
nrgba64 = image.NewNRGBA64(image.Rect(0, 0, width, height))
......@@ -515,16 +544,37 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
nrgba.SetNRGBA(x, y, color.NRGBA{ycol, ycol, ycol, cdat[2*x+1]})
}
case cbTC8:
pix, i, j := rgba.Pix, pixOffset, 0
for x := 0; x < width; x++ {
pix[i+0] = cdat[j+0]
pix[i+1] = cdat[j+1]
pix[i+2] = cdat[j+2]
pix[i+3] = 0xff
i += 4
j += 3
if d.useTransparent {
pix, i, j := nrgba.Pix, pixOffset, 0
tr, tg, tb := d.transparent[1], d.transparent[3], d.transparent[5]
for x := 0; x < width; x++ {
r := cdat[j+0]
g := cdat[j+1]
b := cdat[j+2]
a := byte(0xff)
if r == tr && g == tg && b == tb {
a = 0x00
}
pix[i+0] = r
pix[i+1] = g
pix[i+2] = b
pix[i+3] = a
i += 4
j += 3
}
pixOffset += nrgba.Stride
} else {
pix, i, j := rgba.Pix, pixOffset, 0
for x := 0; x < width; x++ {
pix[i+0] = cdat[j+0]
pix[i+1] = cdat[j+1]
pix[i+2] = cdat[j+2]
pix[i+3] = 0xff
i += 4
j += 3
}
pixOffset += rgba.Stride
}
pixOffset += rgba.Stride
case cbP1:
for x := 0; x < width; x += 8 {
b := cdat[x/8]
......@@ -586,11 +636,27 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
nrgba64.SetNRGBA64(x, y, color.NRGBA64{ycol, ycol, ycol, acol})
}
case cbTC16:
for x := 0; x < width; x++ {
rcol := uint16(cdat[6*x+0])<<8 | uint16(cdat[6*x+1])
gcol := uint16(cdat[6*x+2])<<8 | uint16(cdat[6*x+3])
bcol := uint16(cdat[6*x+4])<<8 | uint16(cdat[6*x+5])
rgba64.SetRGBA64(x, y, color.RGBA64{rcol, gcol, bcol, 0xffff})
if d.useTransparent {
tr := uint16(d.transparent[0])<<8 | uint16(d.transparent[1])
tg := uint16(d.transparent[2])<<8 | uint16(d.transparent[3])
tb := uint16(d.transparent[4])<<8 | uint16(d.transparent[5])
for x := 0; x < width; x++ {
rcol := uint16(cdat[6*x+0])<<8 | uint16(cdat[6*x+1])
gcol := uint16(cdat[6*x+2])<<8 | uint16(cdat[6*x+3])
bcol := uint16(cdat[6*x+4])<<8 | uint16(cdat[6*x+5])
acol := uint16(0xffff)
if rcol == tr && gcol == tg && bcol == tb {
acol = 0x0000
}
nrgba64.SetNRGBA64(x, y, color.NRGBA64{rcol, gcol, bcol, acol})
}
} else {
for x := 0; x < width; x++ {
rcol := uint16(cdat[6*x+0])<<8 | uint16(cdat[6*x+1])
gcol := uint16(cdat[6*x+2])<<8 | uint16(cdat[6*x+3])
bcol := uint16(cdat[6*x+4])<<8 | uint16(cdat[6*x+5])
rgba64.SetRGBA64(x, y, color.RGBA64{rcol, gcol, bcol, 0xffff})
}
}
case cbTCA16:
for x := 0; x < width; x++ {
......
......@@ -39,6 +39,21 @@ var filenames = []string{
"basn4a16",
"basn6a08",
"basn6a16",
//"ftbbn0g01", // TODO: grayscale transparency.
//"ftbbn0g02", // TODO: grayscale transparency.
//"ftbbn0g04", // TODO: grayscale transparency.
"ftbbn2c16",
"ftbbn3p08",
"ftbgn2c16",
"ftbgn3p08",
"ftbrn2c08",
//"ftbwn0g16", // TODO: grayscale transparency.
"ftbwn3p08",
"ftbyn3p08",
"ftp0n0g08",
"ftp0n2c08",
"ftp0n3p08",
"ftp1n3p08",
}
var filenamesPaletted = []string{
......@@ -64,6 +79,38 @@ func readPNG(filename string) (image.Image, error) {
return Decode(f)
}
// fakebKGDs maps from filenames to fake bKGD chunks for our approximation to
// the sng command-line tool. Package png doesn't keep that metadata when
// png.Decode returns an image.Image.
var fakebKGDs = map[string]string{
"ftbbn0g01": "bKGD {gray: 0;}\n",
"ftbbn0g02": "bKGD {gray: 0;}\n",
"ftbbn0g04": "bKGD {gray: 0;}\n",
"ftbbn2c16": "bKGD {red: 0; green: 0; blue: 65535;}\n",
"ftbbn3p08": "bKGD {index: 245}\n",
"ftbgn2c16": "bKGD {red: 0; green: 65535; blue: 0;}\n",
"ftbgn3p08": "bKGD {index: 245}\n",
"ftbrn2c08": "bKGD {red: 255; green: 0; blue: 0;}\n",
"ftbwn0g16": "bKGD {gray: 65535;}\n",
"ftbwn3p08": "bKGD {index: 0}\n",
"ftbyn3p08": "bKGD {index: 245}\n",
}
// fakeIHDRUsings maps from filenames to fake IHDR "using" lines for our
// approximation to the sng command-line tool. The PNG model is that
// transparency (in the tRNS chunk) is separate to the color/grayscale/palette
// color model (in the IHDR chunk). The Go model is that the concrete
// image.Image type returned by png.Decode, such as image.RGBA (with all pixels
// having 100% alpha) or image.NRGBA, encapsulates whether or not the image has
// transparency. This map is a hack to work around the fact that the Go model
// can't otherwise discriminate PNG's "IHDR says color (with no alpha) but tRNS
// says alpha" and "IHDR says color with alpha".
var fakeIHDRUsings = map[string]string{
"ftbbn2c16": " using color;\n",
"ftbgn2c16": " using color;\n",
"ftbrn2c08": " using color;\n",
}
// An approximation of the sng command-line tool.
func sng(w io.WriteCloser, filename string, png image.Image) {
defer w.Close()
......@@ -95,25 +142,31 @@ func sng(w io.WriteCloser, filename string, png image.Image) {
// Write the filename and IHDR.
io.WriteString(w, "#SNG: from "+filename+".png\nIHDR {\n")
fmt.Fprintf(w, " width: %d; height: %d; bitdepth: %d;\n", bounds.Dx(), bounds.Dy(), bitdepth)
switch {
case cm == color.RGBAModel, cm == color.RGBA64Model:
io.WriteString(w, " using color;\n")
case cm == color.NRGBAModel, cm == color.NRGBA64Model:
io.WriteString(w, " using color alpha;\n")
case cm == color.GrayModel, cm == color.Gray16Model:
io.WriteString(w, " using grayscale;\n")
case cpm != nil:
io.WriteString(w, " using color palette;\n")
default:
io.WriteString(w, "unknown PNG decoder color model\n")
if s, ok := fakeIHDRUsings[filename]; ok {
io.WriteString(w, s)
} else {
switch {
case cm == color.RGBAModel, cm == color.RGBA64Model:
io.WriteString(w, " using color;\n")
case cm == color.NRGBAModel, cm == color.NRGBA64Model:
io.WriteString(w, " using color alpha;\n")
case cm == color.GrayModel, cm == color.Gray16Model:
io.WriteString(w, " using grayscale;\n")
case cpm != nil:
io.WriteString(w, " using color palette;\n")
default:
io.WriteString(w, "unknown PNG decoder color model\n")
}
}
io.WriteString(w, "}\n")
// We fake a gAMA output. The test files have a gAMA chunk but the go PNG parser ignores it
// (the PNG spec section 11.3 says "Ancillary chunks may be ignored by a decoder").
// We fake a gAMA chunk. The test files have a gAMA chunk but the go PNG
// parser ignores it (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 and tRNS (if applicable).
useTransparent := false
if cpm != nil {
lastAlpha := -1
io.WriteString(w, "PLTE {\n")
......@@ -133,6 +186,9 @@ func sng(w io.WriteCloser, filename string, png image.Image) {
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 s, ok := fakebKGDs[filename]; ok {
io.WriteString(w, s)
}
if lastAlpha != -1 {
io.WriteString(w, "tRNS {\n")
for i := 0; i <= lastAlpha; i++ {
......@@ -142,6 +198,28 @@ func sng(w io.WriteCloser, filename string, png image.Image) {
}
io.WriteString(w, "}\n")
}
} else if strings.HasPrefix(filename, "ft") {
if s, ok := fakebKGDs[filename]; ok {
io.WriteString(w, s)
}
// We fake a tRNS chunk. The test files' grayscale and truecolor
// transparent images all have their top left corner transparent.
switch c := png.At(0, 0).(type) {
case color.NRGBA:
if c.A == 0 {
useTransparent = true
io.WriteString(w, "tRNS {\n")
fmt.Fprintf(w, " red: %d; green: %d; blue: %d;\n", c.R, c.G, c.B)
io.WriteString(w, "}\n")
}
case color.NRGBA64:
if c.A == 0 {
useTransparent = true
io.WriteString(w, "tRNS {\n")
fmt.Fprintf(w, " red: %d; green: %d; blue: %d;\n", c.R, c.G, c.B)
io.WriteString(w, "}\n")
}
}
}
// Write the IMAGE.
......@@ -171,12 +249,20 @@ func sng(w io.WriteCloser, filename string, png image.Image) {
case cm == color.NRGBAModel:
for x := bounds.Min.X; x < bounds.Max.X; x++ {
nrgba := png.At(x, y).(color.NRGBA)
fmt.Fprintf(w, "%02x%02x%02x%02x ", nrgba.R, nrgba.G, nrgba.B, nrgba.A)
if useTransparent {
fmt.Fprintf(w, "%02x%02x%02x ", nrgba.R, nrgba.G, nrgba.B)
} else {
fmt.Fprintf(w, "%02x%02x%02x%02x ", nrgba.R, nrgba.G, nrgba.B, nrgba.A)
}
}
case cm == color.NRGBA64Model:
for x := bounds.Min.X; x < bounds.Max.X; x++ {
nrgba64 := png.At(x, y).(color.NRGBA64)
fmt.Fprintf(w, "%04x%04x%04x%04x ", nrgba64.R, nrgba64.G, nrgba64.B, nrgba64.A)
if useTransparent {
fmt.Fprintf(w, "%04x%04x%04x ", nrgba64.R, nrgba64.G, nrgba64.B)
} else {
fmt.Fprintf(w, "%04x%04x%04x%04x ", nrgba64.R, nrgba64.G, nrgba64.B, nrgba64.A)
}
}
case cpm != nil:
var b, c int
......@@ -256,8 +342,23 @@ func TestReader(t *testing.T) {
}
ps := pb.Text()
ss := sb.Text()
// Newer versions of the sng command line tool append an optional
// color name to the RGB tuple. For example:
// # rgb = (0xff,0xff,0xff) grey100
// # rgb = (0x00,0x00,0xff) blue1
// instead of the older version's plainer:
// # rgb = (0xff,0xff,0xff)
// # rgb = (0x00,0x00,0xff)
// We strip any such name.
if strings.Contains(ss, "# rgb = (") && !strings.HasSuffix(ss, ")") {
if i := strings.LastIndex(ss, ") "); i >= 0 {
ss = ss[:i+1]
}
}
if ps != ss {
t.Errorf("%s: Mismatch\n%sversus\n%s\n", fn, ps, ss)
t.Errorf("%s: Mismatch\n%s\nversus\n%s\n", fn, ps, ss)
break
}
}
......
The *.png and README.original files in this directory are copied from
libpng.org, specifically contrib/pngsuite/* in libpng-1.2.40.tar.gz.
libpng.org, specifically contrib/pngsuite/* in libpng 1.6.26.
README.original gives the following license for those files:
Permission to use, copy, and distribute these images for any purpose
and without fee is hereby granted.
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.
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-2
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
to a bitdepth of 8 and then running sng on them. basn4a08.sng was generated
by from a 16-bit rgba version of basn4a08.png rather than the original
gray + alpha.
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 to a bitdepth of 8 and then
running sng on them. basn4a08.sng was generated from a 16-bit rgba version of
basn4a08.png rather than the original gray + alpha.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#SNG: from ftbrn2c08.png
IHDR {
width: 32; height: 32; bitdepth: 8;
using color;
}
gAMA {1.0000}
bKGD {red: 255; green: 0; blue: 0;}
tRNS {
red: 255; green: 255; blue: 255;
}
IMAGE {
pixels hex
ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff e3e3e3 c9c9c9 f1f1f1 ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff e8e8e8 b5b5b5 7e7e7e 656565 6e5252 7e2e2e a64343 c79090 ebdddd ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff eeeeee bfbfbf 898989 676767 6b5d5d 7a3939 8a1212 8d0000 850000 770000 840000 9a0101 a22d2d bf7d7d ddd0d0 fcfcfc ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
ffffff ffffff ffffff ffffff ffffff f2f2f2 c4c4c4 959595 727272 6f6b6b 774444 871e1e 950101 9f0000 910000 800000 720c0c 612d2d 530e0e 500000 590000 850000 920606 7a6666 a0a0a0 cfcfcf f8f8f8 ffffff ffffff ffffff ffffff ffffff
ffffff ffffff f7f7f7 cacaca 9a9a9a 767676 737373 7c5d5d 872e2e 930707 9e0000 a90000 b00000 c90000 cf0000 b90000 a20101 8c1919 852a2a 7f1313 810000 960000 8f0000 6b5353 6e6e6e 737373 767676 9b9b9b c4c4c4 eeeeee ffffff ffffff
ffffff ffffff cccccc 7f7f7f 767676 757575 757575 962f2f b80000 b40000 b60000 ad0c0c 943a3a 925050 b92323 d60202 e20000 ef0000 e70000 da0000 cf0000 ba0000 7d0101 6f6b6b 757575 757575 757575 757575 6a6a6a 9a9a9a ffffff ffffff
ffffff ffffff dcdcdc 858585 888888 848484 7b7b7b 855454 b71313 a91d1d 8d4f4f 787575 777777 777777 777777 816b6b aa4141 d62020 ec1010 e90c0c d01212 a52828 7b5858 777777 777777 777777 707070 5c5c5c 525252 bdbdbd ffffff ffffff
ffffff ffffff eaeaea 848484 818181 858885 8e8e8e 898989 7f7f7f 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 767676 636363 545454 505050 4c4c4c e6e6e6 ffffff ffffff
ffffff ffffff f8f8f8 7f847f 259725 04a504 39a439 8b948b 939393 8f8f8f 838383 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7a7a7a 7a7a7a 797979 6a6a6a 575757 505050 4c4c4c 494949 595959 ffffff ffffff ffffff
ffffff ffffff ffffff 8a8a8a 01b301 00c600 00f200 59b659 929292 959595 979797 949494 878787 7c7c7c 7c7c7c 7c7c7c 7c7c7c 7c7c7c 7c7c7c 7c7c7c 7c7c7c 717171 5a5a60 282885 040493 0c0c78 282858 46464a 828282 ffffff ffffff ffffff
ffffff ffffff ffffff 929292 0cab0c 00bd00 00f400 20dd20 919191 949494 979797 999999 9b9b9b 999999 8b8b8b 7f7f7f 7e7e7e 7e7e7e 7d7d7d 777777 626262 535360 1212be 0000cc 000092 000069 000067 2a2a55 acacac ffffff ffffff ffffff
ffffff ffffff ffffff 949494 16a116 00b400 00e200 00f400 76a276 939393 8d978d 469e46 46a746 8e9e8e 9e9e9e 9c9c9c 8e8e8e 7e7e7e 6a6a6a 5a5a5a 57575a 1818cd 0000f0 0000a0 020260 01013d 000061 1d1d59 d6d6d6 ffffff ffffff ffffff
ffffff ffffff ffffff a4a4a4 219821 00aa00 00c800 00f400 3bca3b 929292 4aac4a 00bc00 00a900 2f9a2f 9d9d9d 9f9f9f a0a0a0 7a7a7a 5a5a5a 595959 3131a1 0000ff 0000c6 03035b 191924 0c0c15 0c0c55 3b3b53 fbfbfb ffffff ffffff ffffff
ffffff ffffff ffffff b6b6b6 2b8f2b 00a200 00ad00 00eb00 07ed07 899589 43a743 00c900 009900 389538 9c9c9c 9e9e9e 9f9f9f 747474 595959 505067 0505f5 0000f0 030370 383846 484848 161639 2b2b55 727272 ffffff ffffff ffffff ffffff
ffffff ffffff ffffff c7c7c7 348634 00b100 008d00 00d200 00f300 4c9b4c 3b9e3b 00c700 009800 3d943d 9b9b9b 9d9d9d 9e9e9e 6e6e6e 595959 2b2bad 0000ff 0000a6 252559 43434f 16167e 00009f 01018e 9c9ca1 ffffff ffffff ffffff ffffff
ffffff ffffff ffffff d8d8d8 3e7d3e 00b100 007b00 00b800 00f100 178b17 3b9c3b 00c600 009700 3d933d 9a9a9a 9b9b9b 9d9d9d 676767 575759 0909ee 0000f0 04046b 33335a 070790 00009e 00007c 0d0d5d c7c7c7 ffffff ffffff ffffff ffffff
ffffff ffffff ffffff eaeaea 477447 00ad00 008500 099809 00dc00 00a700 239823 00c300 009600 3f923f 989898 9a9a9a 9c9c9c 616161 42427f 0000ff 0000b9 1a1a5d 161649 00007b 00006b 00006b 1c1c56 f4f4f4 ffffff ffffff ffffff ffffff
ffffff ffffff ffffff fcfcfc 506c50 00a900 009500 2d772d 00c100 00c500 019301 00c100 009000 4b914b 979797 999999 9a9a9a 5a5a5a 2b2ba4 0000f6 000086 2f2f53 191930 020263 000073 00009b 4d4d70 ffffff ffffff ffffff ffffff ffffff
ffffff ffffff ffffff ffffff 687368 00a400 00a400 3e653e 14a514 00d400 008b00 00bf00 008e00 4a904a 959595 979797 969696 575757 1a1ab5 0000de 000068 3f3f4b 2b2b2b 0c0c6d 0000b3 00006b 868692 ffffff ffffff ffffff ffffff ffffff
ffffff ffffff ffffff ffffff 8c8c8c 059e05 00b000 346634 408540 00ca00 009700 00bc00 008c00 498e49 939393 959595 8f8f8f 565656 0f0fb7 0000b9 030366 474747 2f2f64 0000a2 00009d 090958 c5c5c5 ffffff ffffff ffffff ffffff ffffff
ffffff ffffff ffffff ffffff fafafa 90b090 348534 616461 636a63 06af06 00ae00 00b900 008b00 538d53 919191 939393 898989 555555 0a0aa8 00009d 070763 34345c 04049b 0000b1 1a1a4d b5b5bb ffffff ffffff ffffff ffffff ffffff ffffff
ffffff ffffff ffffff ffffff ffffff ffffff d0d0d0 6d6d6d 656565 2d8f2d 00b200 00b600 008900 558b55 8f8f8f 919191 818181 555555 15157e 000084 010165 010184 000091 1c1c6e ceced0 ffffff ffffff ffffff ffffff ffffff ffffff ffffff
ffffff ffffff ffffff ffffff ffffff ffffff ffffff ececec 868686 587058 00af00 00b300 008800 538953 8d8d8d 8f8f8f 7a7a7a 545454 2c2c49 02026b 000064 000063 292974 dfdfe5 ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff fcfcfc aaaaaa 219821 00b000 008600 578757 8b8b8b 8d8d8d 747474 535353 3d3d3d 1a1a23 0d0d43 474772 ededef ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff d1d6d1 389b38 2d772d 7d817d 888888 8b8b8b 6d6d6d 525252 4f4f4f 373737 777777 fafafa ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff efefef a0a0a0 838383 868686 888888 676767 515151 505050 a0a0a0 fdfdfd ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff fefefe c0c0c0 858585 868686 616161 525252 b7b7b7 ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff dedede 909090 656565 cccccc ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff f5f5f5 e3e3e3 ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
}
This diff is collapsed.
This diff is collapsed.
#SNG: from ftp0n0g08.png
IHDR {
width: 32; height: 32; bitdepth: 8;
using grayscale;
}
gAMA {1.0000}
IMAGE {
pixels hex
7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f
7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f
7f7f7f7f7f7f7f7f7f7f7f7f7f7fe3c9f17f7f7f7f7f7f7f7f7f7f7f7f7f7f7f
7f7f7f7f7f7f7f7f7f7f7fe8b57e655a4661a1e17f7f7f7f7f7f7f7f7f7f7f7f
7f7f7f7f7f7f7f7feebf8967614d362a2824282f5091d4fc7f7f7f7f7f7f7f7f
7f7f7f7f7ff2c495726c533e2e302c272b3d23181b28306ca0cff87f7f7f7f7f
7f7ff7ca9a76736649313033353c3e38313c4533272d2b5a6e73769bc4ee7f7f
7f7fcc7f7675754e3736373c55645042444845423e38266c757575756a9a7f7f
7f7fdc8588847b6344476276777777726157524e4b4e63777777705c52bd7f7f
7f7fea8481878e897f797979797979797979797979797979766354504ce67f7f
7f7ff88268627890938f837b7b7b7b7b7b7b7b7b7a7a796a57504c49597f7f7f
7f7f7f8a69748e8f92959794877c7c7c7c7c7c7c7c715b3314182d46827f7f7f
7f7f7f92696f8f8f919497999b998b7f7e7e7d7762542517110c0c2fac7f7f7f
7f7f7f946769848f9093937a7f979e9c8e7e6a5a572d1b120d080b24d67f7f7f
7f7f7fa46764758f8f92836e636e9d9fa07a5a593e1d160d1a0d143efb7f7f7f
7f7f7fb6665f658a8e907e765a6e9c9e9f745953201b0f3a481a30727f7f7f7f
7f7f7fc76468537b8e7a757559709b9d9e6e593a1d132b442212119d7f7f7f7f
7f7f7fd86368486c8d5b7474586f9a9b9d6757231b103717120e16c77f7f7f7f
7f7f7fea61654e5d816268725870989a9c61491d15221c0e0c0c23f47f7f7f7f
7f7f7ffc6063575871735771547497999a5a391c0f331c0d0d12517f7f7f7f7f
7f7f7f7f6e606055697c51705373959796572c190c402b17140c877f7f7f7f7f
7f7f7f7f8c5f67516876586e527193958f5622150e4735121212c57f7f7f7f7f
7f7f7f7ffaa363636769666c5175919389551c121139151420b67f7f7f7f7f7f
7f7f7f7f7f7fd06d6566686b50758f918155210f0c101025ce7f7f7f7f7f7f7f
7f7f7f7f7f7f7fec8666676950738d8f7a542f0e0b0b31e07f7f7f7f7f7f7f7f
7f7f7f7f7f7f7f7ffcaa67674f738b8d74533d1b134ced7f7f7f7f7f7f7f7f7f
7f7f7f7f7f7f7f7f7f7fd472587f888b6d524f3777fa7f7f7f7f7f7f7f7f7f7f
7f7f7f7f7f7f7f7f7f7f7fefa0838688675150a0fd7f7f7f7f7f7f7f7f7f7f7f
7f7f7f7f7f7f7f7f7f7f7f7ffec085866152b77f7f7f7f7f7f7f7f7f7f7f7f7f
7f7f7f7f7f7f7f7f7f7f7f7f7f7fde9065cc7f7f7f7f7f7f7f7f7f7f7f7f7f7f
7f7f7f7f7f7f7f7f7f7f7f7f7f7f7ff5e37f7f7f7f7f7f7f7f7f7f7f7f7f7f7f
7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f
}
#SNG: from ftp0n2c08.png
IHDR {
width: 32; height: 32; bitdepth: 8;
using color;
}
gAMA {1.0000}
IMAGE {
pixels hex
7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f e3e3e3 c9c9c9 f1f1f1 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f e8e8e8 b5b5b5 7e7e7e 656565 6e5252 7e2e2e a64343 c79090 ebdddd 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f eeeeee bfbfbf 898989 676767 6b5d5d 7a3939 8a1212 8d0000 850000 770000 840000 9a0101 a22d2d bf7d7d ddd0d0 fcfcfc 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f f2f2f2 c4c4c4 959595 727272 6f6b6b 774444 871e1e 950101 9f0000 910000 800000 720c0c 612d2d 530e0e 500000 590000 850000 920606 7a6666 a0a0a0 cfcfcf f8f8f8 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
7f7f7f 7f7f7f f7f7f7 cacaca 9a9a9a 767676 737373 7c5d5d 872e2e 930707 9e0000 a90000 b00000 c90000 cf0000 b90000 a20101 8c1919 852a2a 7f1313 810000 960000 8f0000 6b5353 6e6e6e 737373 767676 9b9b9b c4c4c4 eeeeee 7f7f7f 7f7f7f
7f7f7f 7f7f7f cccccc 7f7f7f 767676 757575 757575 962f2f b80000 b40000 b60000 ad0c0c 943a3a 925050 b92323 d60202 e20000 ef0000 e70000 da0000 cf0000 ba0000 7d0101 6f6b6b 757575 757575 757575 757575 6a6a6a 9a9a9a 7f7f7f 7f7f7f
7f7f7f 7f7f7f dcdcdc 858585 888888 848484 7b7b7b 855454 b71313 a91d1d 8d4f4f 787575 777777 777777 777777 816b6b aa4141 d62020 ec1010 e90c0c d01212 a52828 7b5858 777777 777777 777777 707070 5c5c5c 525252 bdbdbd 7f7f7f 7f7f7f
7f7f7f 7f7f7f eaeaea 848484 818181 858885 8e8e8e 898989 7f7f7f 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 767676 636363 545454 505050 4c4c4c e6e6e6 7f7f7f 7f7f7f
7f7f7f 7f7f7f f8f8f8 7f847f 259725 04a504 39a439 8b948b 939393 8f8f8f 838383 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7a7a7a 7a7a7a 797979 6a6a6a 575757 505050 4c4c4c 494949 595959 7f7f7f 7f7f7f 7f7f7f
7f7f7f 7f7f7f 7f7f7f 8a8a8a 01b301 00c600 00f200 59b659 929292 959595 979797 949494 878787 7c7c7c 7c7c7c 7c7c7c 7c7c7c 7c7c7c 7c7c7c 7c7c7c 7c7c7c 717171 5a5a60 282885 040493 0c0c78 282858 46464a 828282 7f7f7f 7f7f7f 7f7f7f
7f7f7f 7f7f7f 7f7f7f 929292 0cab0c 00bd00 00f400 20dd20 919191 949494 979797 999999 9b9b9b 999999 8b8b8b 7f7f7f 7e7e7e 7e7e7e 7d7d7d 777777 626262 535360 1212be 0000cc 000092 000069 000067 2a2a55 acacac 7f7f7f 7f7f7f 7f7f7f
7f7f7f 7f7f7f 7f7f7f 949494 16a116 00b400 00e200 00f400 76a276 939393 8d978d 469e46 46a746 8e9e8e 9e9e9e 9c9c9c 8e8e8e 7e7e7e 6a6a6a 5a5a5a 57575a 1818cd 0000f0 0000a0 020260 01013d 000061 1d1d59 d6d6d6 7f7f7f 7f7f7f 7f7f7f
7f7f7f 7f7f7f 7f7f7f a4a4a4 219821 00aa00 00c800 00f400 3bca3b 929292 4aac4a 00bc00 00a900 2f9a2f 9d9d9d 9f9f9f a0a0a0 7a7a7a 5a5a5a 595959 3131a1 0000ff 0000c6 03035b 191924 0c0c15 0c0c55 3b3b53 fbfbfb 7f7f7f 7f7f7f 7f7f7f
7f7f7f 7f7f7f 7f7f7f b6b6b6 2b8f2b 00a200 00ad00 00eb00 07ed07 899589 43a743 00c900 009900 389538 9c9c9c 9e9e9e 9f9f9f 747474 595959 505067 0505f5 0000f0 030370 383846 484848 161639 2b2b55 727272 7f7f7f 7f7f7f 7f7f7f 7f7f7f
7f7f7f 7f7f7f 7f7f7f c7c7c7 348634 00b100 008d00 00d200 00f300 4c9b4c 3b9e3b 00c700 009800 3d943d 9b9b9b 9d9d9d 9e9e9e 6e6e6e 595959 2b2bad 0000ff 0000a6 252559 43434f 16167e 00009f 01018e 9c9ca1 7f7f7f 7f7f7f 7f7f7f 7f7f7f
7f7f7f 7f7f7f 7f7f7f d8d8d8 3e7d3e 00b100 007b00 00b800 00f100 178b17 3b9c3b 00c600 009700 3d933d 9a9a9a 9b9b9b 9d9d9d 676767 575759 0909ee 0000f0 04046b 33335a 070790 00009e 00007c 0d0d5d c7c7c7 7f7f7f 7f7f7f 7f7f7f 7f7f7f
7f7f7f 7f7f7f 7f7f7f eaeaea 477447 00ad00 008500 099809 00dc00 00a700 239823 00c300 009600 3f923f 989898 9a9a9a 9c9c9c 616161 42427f 0000ff 0000b9 1a1a5d 161649 00007b 00006b 00006b 1c1c56 f4f4f4 7f7f7f 7f7f7f 7f7f7f 7f7f7f
7f7f7f 7f7f7f 7f7f7f fcfcfc 506c50 00a900 009500 2d772d 00c100 00c500 019301 00c100 009000 4b914b 979797 999999 9a9a9a 5a5a5a 2b2ba4 0000f6 000086 2f2f53 191930 020263 000073 00009b 4d4d70 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
7f7f7f 7f7f7f 7f7f7f 7f7f7f 687368 00a400 00a400 3e653e 14a514 00d400 008b00 00bf00 008e00 4a904a 959595 979797 969696 575757 1a1ab5 0000de 000068 3f3f4b 2b2b2b 0c0c6d 0000b3 00006b 868692 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
7f7f7f 7f7f7f 7f7f7f 7f7f7f 8c8c8c 059e05 00b000 346634 408540 00ca00 009700 00bc00 008c00 498e49 939393 959595 8f8f8f 565656 0f0fb7 0000b9 030366 474747 2f2f64 0000a2 00009d 090958 c5c5c5 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
7f7f7f 7f7f7f 7f7f7f 7f7f7f fafafa 90b090 348534 616461 636a63 06af06 00ae00 00b900 008b00 538d53 919191 939393 898989 555555 0a0aa8 00009d 070763 34345c 04049b 0000b1 1a1a4d b5b5bb 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f d0d0d0 6d6d6d 656565 2d8f2d 00b200 00b600 008900 558b55 8f8f8f 919191 818181 555555 15157e 000084 010165 010184 000091 1c1c6e ceced0 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f ececec 868686 587058 00af00 00b300 008800 538953 8d8d8d 8f8f8f 7a7a7a 545454 2c2c49 02026b 000064 000063 292974 dfdfe5 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f fcfcfc aaaaaa 219821 00b000 008600 578757 8b8b8b 8d8d8d 747474 535353 3d3d3d 1a1a23 0d0d43 474772 ededef 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f d1d6d1 389b38 2d772d 7d817d 888888 8b8b8b 6d6d6d 525252 4f4f4f 373737 777777 fafafa 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f efefef a0a0a0 838383 868686 888888 676767 515151 505050 a0a0a0 fdfdfd 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f fefefe c0c0c0 858585 868686 616161 525252 b7b7b7 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f dedede 909090 656565 cccccc 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f f5f5f5 e3e3e3 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
}
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment