├── sample
├── build.hxml
├── output
│ ├── index.html
│ ├── PNGlibSample.js
│ └── pnglib.js
└── Sample.hx
├── circles.png
├── haxe-PNGlib.zip
├── js
└── PNGlib.hx
├── haxelib.json
├── .gitignore
├── LICENSE
├── README.md
├── .gitattributes
└── libs
└── pnglib.js
/sample/build.hxml:
--------------------------------------------------------------------------------
1 | -lib PNGlib
2 | -main Sample
3 | -js output/PNGlibSample.js
--------------------------------------------------------------------------------
/circles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamaluik/haxe-PNGlib/master/circles.png
--------------------------------------------------------------------------------
/haxe-PNGlib.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamaluik/haxe-PNGlib/master/haxe-PNGlib.zip
--------------------------------------------------------------------------------
/sample/output/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | PNGlib Sample
4 |
5 |
6 |
7 | PNGlib Sample
8 |
9 |
10 |
--------------------------------------------------------------------------------
/js/PNGlib.hx:
--------------------------------------------------------------------------------
1 | package js;
2 |
3 | @:native('PNGlib')
4 | extern class PNGlib {
5 | public function new(width:Int, height:Int, colourDepth:Int);
6 | public function index(x:Int, y:Int):Int;
7 | public function color(red:Int, green:Int, blue:Int, ?alpha:Int):Int;
8 | public function getBase64():String;
9 | public function getDump():String;
10 | public var buffer:Array;
11 | }
--------------------------------------------------------------------------------
/haxelib.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "PNGlib",
3 | "url" : "https://github.com/FuzzyWuzzie/haxe-PNGlib",
4 | "license": "MIT",
5 | "tags": ["js"],
6 | "description": "Haxe externs for the pnglib.js library (for saving files from the browser).",
7 | "version": "1.0.0",
8 | "releasenote": "Initial release, everything is working correctly.",
9 | "contributors": ["FuzzyWuzzie"],
10 | "dependencies": {}
11 | }
--------------------------------------------------------------------------------
/sample/output/PNGlibSample.js:
--------------------------------------------------------------------------------
1 | (function (console) { "use strict";
2 | var Sample = function() { };
3 | Sample.main = function() {
4 | var p = new PNGlib(256,256,256);
5 | var background = p.color(0,0,0,0);
6 | var _g = 0;
7 | while(_g < 256) {
8 | var i = _g++;
9 | var _g1 = 0;
10 | while(_g1 < 256) {
11 | var j = _g1++;
12 | var dist = Math.sqrt((i - 128) * (i - 128) + (j - 128) * (j - 128));
13 | if(dist < 32) p.buffer[p.index(i,j)] = p.color(255,255,255); else if(dist < 64) p.buffer[p.index(i,j)] = p.color(251,199,7); else if(dist < 96) p.buffer[p.index(i,j)] = p.color(234,130,32); else if(dist < 128) p.buffer[p.index(i,j)] = p.color(168,75,56); else if(dist < 160) p.buffer[p.index(i,j)] = p.color(20,20,25);
14 | }
15 | }
16 | var base64 = p.getBase64();
17 | window.document.write("
");
18 | };
19 | Sample.main();
20 | })(typeof console != "undefined" ? console : {log:function(){}});
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ### Windows ###
2 | # Windows image file caches
3 | Thumbs.db
4 | ehthumbs.db
5 |
6 | # Folder config file
7 | Desktop.ini
8 |
9 | # Recycle Bin used on file shares
10 | $RECYCLE.BIN/
11 |
12 | # Windows Installer files
13 | *.cab
14 | *.msi
15 | *.msm
16 | *.msp
17 |
18 | # Windows shortcuts
19 | *.lnk
20 |
21 |
22 | ### OSX ###
23 | .DS_Store
24 | .AppleDouble
25 | .LSOverride
26 |
27 | # Icon must end with two \r
28 | Icon
29 |
30 |
31 | # Thumbnails
32 | ._*
33 |
34 | # Files that might appear in the root of a volume
35 | .DocumentRevisions-V100
36 | .fseventsd
37 | .Spotlight-V100
38 | .TemporaryItems
39 | .Trashes
40 | .VolumeIcon.icns
41 |
42 | # Directories potentially created on remote AFP share
43 | .AppleDB
44 | .AppleDesktop
45 | Network Trash Folder
46 | Temporary Items
47 | .apdisk
48 |
49 |
50 | ### Linux ###
51 | *~
52 |
53 | # KDE directory preferences
54 | .directory
55 |
56 | # Linux trash folder which might appear on any partition or disk
57 | .Trash-*
--------------------------------------------------------------------------------
/sample/Sample.hx:
--------------------------------------------------------------------------------
1 | import js.PNGlib;
2 |
3 | class Sample {
4 | static public function main() {
5 | var p:PNGlib = new PNGlib(256, 256, 256);
6 | var background:Int = p.color(0, 0, 0, 0);
7 |
8 | var num:Float = 200 / 10;
9 | var i:Float = 0;
10 | while(i <= num) {
11 | var x:Float = i * 10;
12 | var y = Math.sin(i) * Math.sin(i) * 50 + 50;
13 |
14 | // use a color triad of Microsofts million dollar color
15 | p.buffer[p.index(Math.floor(x), Math.floor(y - 10))] = p.color(0x00, 0x44, 0xcc);
16 | p.buffer[p.index(Math.floor(x), Math.floor(y))] = p.color(0xcc, 0x00, 0x44);
17 | p.buffer[p.index(Math.floor(x), Math.floor(y + 10))] = p.color(0x00, 0xcc, 0x44);
18 |
19 | i += 0.01;
20 | }
21 |
22 | for(i in 0...50) {
23 | for(j in 0...50) {
24 | p.buffer[p.index(i + 90, j + 135)] = p.color(0xcc, 0x00, 0x44);
25 | p.buffer[p.index(i + 80, j + 120)] = p.color(0x00, 0x44, 0xcc);
26 | p.buffer[p.index(i + 100, j + 130)] = p.color(0x00, 0xcc, 0x44);
27 | }
28 | }
29 |
30 | var base64:String = p.getBase64();
31 | js.Browser.document.write('
');
32 | }
33 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Kenton Hamaluik
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # haxe-PNGlib
2 | [](https://github.com/FuzzyWuzzie/haxe-PNGlib/blob/master/LICENSE)
3 | [](http://www.opensource.org/licenses/bsd-license.php)
4 |
5 | Haxe externs for the [PNGlib][1] library.
6 |
7 | ## Usage
8 |
9 | ```haxe
10 | // create a new PNG image
11 | var p:PNGlib = new PNGlib(width, height, colourDepth);
12 |
13 | // access colours in the buffer
14 | p.buffer[p.index(x, y)] = p.color(red, green, blue, alpha);
15 |
16 | // output strings describing the file
17 | var outputB64:String = p.getBase64();
18 | var outputPNG:String = p.getDump();
19 | ```
20 |
21 | **NOTE**: You must import the [PNGlib][1] library into your HTML file for this to work. In case the source ever goes offline, a copy can be found here: https://github.com/FuzzyWuzzie/haxe-PNGlib/blob/master/libs/pnglib.js
22 |
23 | ## Examples
24 |
25 | ### Drawing Some Circles
26 |
27 | ```haxe
28 | var p:PNGlib = new PNGlib(256, 256, 256);
29 | var background:Int = p.color(0, 0, 0, 0);
30 |
31 | for(i in 0...256) {
32 | for(j in 0...256) {
33 | var dist:Float = Math.sqrt((i - 128)*(i - 128) + (j - 128)*(j - 128));
34 | if(dist < 32) {
35 | p.buffer[p.index(i, j)] = p.color(255, 255, 255);
36 | }
37 | else if(dist < 64) {
38 | p.buffer[p.index(i, j)] = p.color(251,199,7);
39 | }
40 | else if(dist < 96) {
41 | p.buffer[p.index(i, j)] = p.color(234, 130, 32);
42 | }
43 | else if(dist < 128) {
44 | p.buffer[p.index(i, j)] = p.color(168,75,56);
45 | }
46 | else if(dist < 160) {
47 | p.buffer[p.index(i, j)] = p.color(20, 20, 25);
48 | }
49 | }
50 | }
51 |
52 | var base64:String = p.getBase64();
53 | js.Browser.document.write('
');
54 | ```
55 |
56 | Results in:
57 |
58 | 
59 |
60 | ### Live Sample
61 |
62 | A [live sample](http://FuzzyWuzzie.github.io/haxe-PNGlib/) is available which generates a PNG image and embeds it in a webpage.
63 |
64 |
65 | [1]: http://www.xarg.org/2010/03/generate-client-side-png-files-using-javascript/
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Apply native OS line-endings on checkout of these files...
2 | *.boo text
3 | *.c text
4 | *.cginc text
5 | *.config text
6 | *.contentproj text
7 | *.cpp text
8 | *.cs text
9 | *.css text
10 | *.dae text
11 | *.DAE text
12 | *.dtd text
13 | *.fx text
14 | *.glsl text
15 | *.h text
16 | *.htm text
17 | *.html text
18 | *.inc text
19 | *.ini text
20 | *.js text
21 | *.JSFL text
22 | *.jsfl text
23 | *.json text
24 | *.log text
25 | *.md text
26 | *.mel text
27 | *.php text
28 | *.shader text
29 | *.txt text
30 | *.TXT text
31 | *.xaml text
32 | *.xml text
33 | *.xsd text
34 | .gitattributes text
35 | .gitignore text
36 | COPYING text
37 | INSTALL* text
38 | KEYS* text
39 | LICENSE* text
40 | NEWS* text
41 | NOTICE* text
42 | README* text
43 | TODO* text
44 | WHATSNEW* text
45 |
46 | # Apply Unix-style LF line-endings on checkout of these files...
47 | *.meta text eol=lf
48 | *.sh text eol=lf
49 | *.vspscc text eol=lf
50 | .htaccess text eol=lf
51 |
52 | # Apply Windows/DOS-style CR-LF line-endings on checkout of these files...
53 | *.bat text eol=crlf
54 | *.cmd text eol=crlf
55 | *.csproj text eol=crlf
56 | *.sln text eol=crlf
57 | *.user text eol=crlf
58 | *.vcproj text eol=crlf
59 |
60 | # No end-of-line conversions are applied (i.e., "-text -diff") to these files...
61 | *.7z binary
62 | *.ai binary
63 | *.anim binary
64 | *.apk binary
65 | *.asset binary
66 | *.bin binary
67 | *.bmp binary
68 | *.BMP binary
69 | *.com binary
70 | *.COM binary
71 | *.controller binary
72 | *.cubemap binary
73 | *.dex binary
74 | *.dll binary
75 | *.DLL binary
76 | *.dylib binary
77 | *.eps binary
78 | *.exe binary
79 | *.EXE binary
80 | *.exr binary
81 | *.fbx binary
82 | *.FBX binary
83 | *.fla binary
84 | *.flare binary
85 | *.flv binary
86 | *.gif binary
87 | *.guiskin binary
88 | *.gz binary
89 | *.ht binary
90 | *.ico binary
91 | *.jpeg binary
92 | *.jpg binary
93 | *.keystore binary
94 | *.mask binary
95 | *.mat binary
96 | *.mb binary
97 | *.mp3 binary
98 | *.mp4 binary
99 | *.mpg binary
100 | *.ogg binary
101 | *.PCX binary
102 | *.pcx binary
103 | *.pdb binary
104 | *.pdf binary
105 | *.physicMaterial binary
106 | *.physicmaterial binary
107 | *.png binary
108 | *.prefab binary
109 | *.ps binary
110 | *.psd binary
111 | *.qt binary
112 | *.so binary
113 | *.swf binary
114 | *.tga binary
115 | *.tif binary
116 | *.tiff binary
117 | *.ttf binary
118 | *.TTF binary
119 | *.unity binary
120 | *.unitypackage binary
121 | *.unityPackage binary
122 | *.wav binary
123 | *.wmv binary
124 | *.zip binary
125 | *.ZIP binary
--------------------------------------------------------------------------------
/libs/pnglib.js:
--------------------------------------------------------------------------------
1 | /**
2 | * A handy class to calculate color values.
3 | *
4 | * @version 1.0
5 | * @author Robert Eisele
6 | * @copyright Copyright (c) 2010, Robert Eisele
7 | * @link http://www.xarg.org/2010/03/generate-client-side-png-files-using-javascript/
8 | * @license http://www.opensource.org/licenses/bsd-license.php BSD License
9 | *
10 | */
11 |
12 | (function() {
13 |
14 | // helper functions for that ctx
15 | function write(buffer, offs) {
16 | for (var i = 2; i < arguments.length; i++) {
17 | for (var j = 0; j < arguments[i].length; j++) {
18 | buffer[offs++] = arguments[i].charAt(j);
19 | }
20 | }
21 | }
22 |
23 | function byte2(w) {
24 | return String.fromCharCode((w >> 8) & 255, w & 255);
25 | }
26 |
27 | function byte4(w) {
28 | return String.fromCharCode((w >> 24) & 255, (w >> 16) & 255, (w >> 8) & 255, w & 255);
29 | }
30 |
31 | function byte2lsb(w) {
32 | return String.fromCharCode(w & 255, (w >> 8) & 255);
33 | }
34 |
35 | window.PNGlib = function(width,height,depth) {
36 |
37 | this.width = width;
38 | this.height = height;
39 | this.depth = depth;
40 |
41 | // pixel data and row filter identifier size
42 | this.pix_size = height * (width + 1);
43 |
44 | // deflate header, pix_size, block headers, adler32 checksum
45 | this.data_size = 2 + this.pix_size + 5 * Math.floor((0xfffe + this.pix_size) / 0xffff) + 4;
46 |
47 | // offsets and sizes of Png chunks
48 | this.ihdr_offs = 0; // IHDR offset and size
49 | this.ihdr_size = 4 + 4 + 13 + 4;
50 | this.plte_offs = this.ihdr_offs + this.ihdr_size; // PLTE offset and size
51 | this.plte_size = 4 + 4 + 3 * depth + 4;
52 | this.trns_offs = this.plte_offs + this.plte_size; // tRNS offset and size
53 | this.trns_size = 4 + 4 + depth + 4;
54 | this.idat_offs = this.trns_offs + this.trns_size; // IDAT offset and size
55 | this.idat_size = 4 + 4 + this.data_size + 4;
56 | this.iend_offs = this.idat_offs + this.idat_size; // IEND offset and size
57 | this.iend_size = 4 + 4 + 4;
58 | this.buffer_size = this.iend_offs + this.iend_size; // total PNG size
59 |
60 | this.buffer = new Array();
61 | this.palette = new Object();
62 | this.pindex = 0;
63 |
64 | var _crc32 = new Array();
65 |
66 | // initialize buffer with zero bytes
67 | for (var i = 0; i < this.buffer_size; i++) {
68 | this.buffer[i] = "\x00";
69 | }
70 |
71 | // initialize non-zero elements
72 | write(this.buffer, this.ihdr_offs, byte4(this.ihdr_size - 12), 'IHDR', byte4(width), byte4(height), "\x08\x03");
73 | write(this.buffer, this.plte_offs, byte4(this.plte_size - 12), 'PLTE');
74 | write(this.buffer, this.trns_offs, byte4(this.trns_size - 12), 'tRNS');
75 | write(this.buffer, this.idat_offs, byte4(this.idat_size - 12), 'IDAT');
76 | write(this.buffer, this.iend_offs, byte4(this.iend_size - 12), 'IEND');
77 |
78 | // initialize deflate header
79 | var header = ((8 + (7 << 4)) << 8) | (3 << 6);
80 | header+= 31 - (header % 31);
81 |
82 | write(this.buffer, this.idat_offs + 8, byte2(header));
83 |
84 | // initialize deflate block headers
85 | for (var i = 0; (i << 16) - 1 < this.pix_size; i++) {
86 | var size, bits;
87 | if (i + 0xffff < this.pix_size) {
88 | size = 0xffff;
89 | bits = "\x00";
90 | } else {
91 | size = this.pix_size - (i << 16) - i;
92 | bits = "\x01";
93 | }
94 | write(this.buffer, this.idat_offs + 8 + 2 + (i << 16) + (i << 2), bits, byte2lsb(size), byte2lsb(~size));
95 | }
96 |
97 | /* Create crc32 lookup table */
98 | for (var i = 0; i < 256; i++) {
99 | var c = i;
100 | for (var j = 0; j < 8; j++) {
101 | if (c & 1) {
102 | c = -306674912 ^ ((c >> 1) & 0x7fffffff);
103 | } else {
104 | c = (c >> 1) & 0x7fffffff;
105 | }
106 | }
107 | _crc32[i] = c;
108 | }
109 |
110 | // compute the index into a png for a given pixel
111 | this.index = function(x,y) {
112 | var i = y * (this.width + 1) + x + 1;
113 | var j = this.idat_offs + 8 + 2 + 5 * Math.floor((i / 0xffff) + 1) + i;
114 | return j;
115 | }
116 |
117 | // convert a color and build up the palette
118 | this.color = function(red, green, blue, alpha) {
119 |
120 | alpha = alpha >= 0 ? alpha : 255;
121 | var color = (((((alpha << 8) | red) << 8) | green) << 8) | blue;
122 |
123 | if (typeof this.palette[color] == "undefined") {
124 | if (this.pindex == this.depth) return "\x00";
125 |
126 | var ndx = this.plte_offs + 8 + 3 * this.pindex;
127 |
128 | this.buffer[ndx + 0] = String.fromCharCode(red);
129 | this.buffer[ndx + 1] = String.fromCharCode(green);
130 | this.buffer[ndx + 2] = String.fromCharCode(blue);
131 | this.buffer[this.trns_offs+8+this.pindex] = String.fromCharCode(alpha);
132 |
133 | this.palette[color] = String.fromCharCode(this.pindex++);
134 | }
135 | return this.palette[color];
136 | }
137 |
138 | // output a PNG string, Base64 encoded
139 | this.getBase64 = function() {
140 |
141 | var s = this.getDump();
142 |
143 | var ch = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
144 | var c1, c2, c3, e1, e2, e3, e4;
145 | var l = s.length;
146 | var i = 0;
147 | var r = "";
148 |
149 | do {
150 | c1 = s.charCodeAt(i);
151 | e1 = c1 >> 2;
152 | c2 = s.charCodeAt(i+1);
153 | e2 = ((c1 & 3) << 4) | (c2 >> 4);
154 | c3 = s.charCodeAt(i+2);
155 | if (l < i+2) { e3 = 64; } else { e3 = ((c2 & 0xf) << 2) | (c3 >> 6); }
156 | if (l < i+3) { e4 = 64; } else { e4 = c3 & 0x3f; }
157 | r+= ch.charAt(e1) + ch.charAt(e2) + ch.charAt(e3) + ch.charAt(e4);
158 | } while ((i+= 3) < l);
159 | return r;
160 | }
161 |
162 | // output a PNG string
163 | this.getDump = function() {
164 |
165 | // compute adler32 of output pixels + row filter bytes
166 | var BASE = 65521; /* largest prime smaller than 65536 */
167 | var NMAX = 5552; /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
168 | var s1 = 1;
169 | var s2 = 0;
170 | var n = NMAX;
171 |
172 | for (var y = 0; y < this.height; y++) {
173 | for (var x = -1; x < this.width; x++) {
174 | s1+= this.buffer[this.index(x, y)].charCodeAt(0);
175 | s2+= s1;
176 | if ((n-= 1) == 0) {
177 | s1%= BASE;
178 | s2%= BASE;
179 | n = NMAX;
180 | }
181 | }
182 | }
183 | s1%= BASE;
184 | s2%= BASE;
185 | write(this.buffer, this.idat_offs + this.idat_size - 8, byte4((s2 << 16) | s1));
186 |
187 | // compute crc32 of the PNG chunks
188 | function crc32(png, offs, size) {
189 | var crc = -1;
190 | for (var i = 4; i < size-4; i += 1) {
191 | crc = _crc32[(crc ^ png[offs+i].charCodeAt(0)) & 0xff] ^ ((crc >> 8) & 0x00ffffff);
192 | }
193 | write(png, offs+size-4, byte4(crc ^ -1));
194 | }
195 |
196 | crc32(this.buffer, this.ihdr_offs, this.ihdr_size);
197 | crc32(this.buffer, this.plte_offs, this.plte_size);
198 | crc32(this.buffer, this.trns_offs, this.trns_size);
199 | crc32(this.buffer, this.idat_offs, this.idat_size);
200 | crc32(this.buffer, this.iend_offs, this.iend_size);
201 |
202 | // convert PNG to string
203 | return "\211PNG\r\n\032\n"+this.buffer.join('');
204 | }
205 | }
206 |
207 | })();
208 |
--------------------------------------------------------------------------------
/sample/output/pnglib.js:
--------------------------------------------------------------------------------
1 | /**
2 | * A handy class to calculate color values.
3 | *
4 | * @version 1.0
5 | * @author Robert Eisele
6 | * @copyright Copyright (c) 2010, Robert Eisele
7 | * @link http://www.xarg.org/2010/03/generate-client-side-png-files-using-javascript/
8 | * @license http://www.opensource.org/licenses/bsd-license.php BSD License
9 | *
10 | */
11 |
12 | (function() {
13 |
14 | // helper functions for that ctx
15 | function write(buffer, offs) {
16 | for (var i = 2; i < arguments.length; i++) {
17 | for (var j = 0; j < arguments[i].length; j++) {
18 | buffer[offs++] = arguments[i].charAt(j);
19 | }
20 | }
21 | }
22 |
23 | function byte2(w) {
24 | return String.fromCharCode((w >> 8) & 255, w & 255);
25 | }
26 |
27 | function byte4(w) {
28 | return String.fromCharCode((w >> 24) & 255, (w >> 16) & 255, (w >> 8) & 255, w & 255);
29 | }
30 |
31 | function byte2lsb(w) {
32 | return String.fromCharCode(w & 255, (w >> 8) & 255);
33 | }
34 |
35 | window.PNGlib = function(width,height,depth) {
36 |
37 | this.width = width;
38 | this.height = height;
39 | this.depth = depth;
40 |
41 | // pixel data and row filter identifier size
42 | this.pix_size = height * (width + 1);
43 |
44 | // deflate header, pix_size, block headers, adler32 checksum
45 | this.data_size = 2 + this.pix_size + 5 * Math.floor((0xfffe + this.pix_size) / 0xffff) + 4;
46 |
47 | // offsets and sizes of Png chunks
48 | this.ihdr_offs = 0; // IHDR offset and size
49 | this.ihdr_size = 4 + 4 + 13 + 4;
50 | this.plte_offs = this.ihdr_offs + this.ihdr_size; // PLTE offset and size
51 | this.plte_size = 4 + 4 + 3 * depth + 4;
52 | this.trns_offs = this.plte_offs + this.plte_size; // tRNS offset and size
53 | this.trns_size = 4 + 4 + depth + 4;
54 | this.idat_offs = this.trns_offs + this.trns_size; // IDAT offset and size
55 | this.idat_size = 4 + 4 + this.data_size + 4;
56 | this.iend_offs = this.idat_offs + this.idat_size; // IEND offset and size
57 | this.iend_size = 4 + 4 + 4;
58 | this.buffer_size = this.iend_offs + this.iend_size; // total PNG size
59 |
60 | this.buffer = new Array();
61 | this.palette = new Object();
62 | this.pindex = 0;
63 |
64 | var _crc32 = new Array();
65 |
66 | // initialize buffer with zero bytes
67 | for (var i = 0; i < this.buffer_size; i++) {
68 | this.buffer[i] = "\x00";
69 | }
70 |
71 | // initialize non-zero elements
72 | write(this.buffer, this.ihdr_offs, byte4(this.ihdr_size - 12), 'IHDR', byte4(width), byte4(height), "\x08\x03");
73 | write(this.buffer, this.plte_offs, byte4(this.plte_size - 12), 'PLTE');
74 | write(this.buffer, this.trns_offs, byte4(this.trns_size - 12), 'tRNS');
75 | write(this.buffer, this.idat_offs, byte4(this.idat_size - 12), 'IDAT');
76 | write(this.buffer, this.iend_offs, byte4(this.iend_size - 12), 'IEND');
77 |
78 | // initialize deflate header
79 | var header = ((8 + (7 << 4)) << 8) | (3 << 6);
80 | header+= 31 - (header % 31);
81 |
82 | write(this.buffer, this.idat_offs + 8, byte2(header));
83 |
84 | // initialize deflate block headers
85 | for (var i = 0; (i << 16) - 1 < this.pix_size; i++) {
86 | var size, bits;
87 | if (i + 0xffff < this.pix_size) {
88 | size = 0xffff;
89 | bits = "\x00";
90 | } else {
91 | size = this.pix_size - (i << 16) - i;
92 | bits = "\x01";
93 | }
94 | write(this.buffer, this.idat_offs + 8 + 2 + (i << 16) + (i << 2), bits, byte2lsb(size), byte2lsb(~size));
95 | }
96 |
97 | /* Create crc32 lookup table */
98 | for (var i = 0; i < 256; i++) {
99 | var c = i;
100 | for (var j = 0; j < 8; j++) {
101 | if (c & 1) {
102 | c = -306674912 ^ ((c >> 1) & 0x7fffffff);
103 | } else {
104 | c = (c >> 1) & 0x7fffffff;
105 | }
106 | }
107 | _crc32[i] = c;
108 | }
109 |
110 | // compute the index into a png for a given pixel
111 | this.index = function(x,y) {
112 | var i = y * (this.width + 1) + x + 1;
113 | var j = this.idat_offs + 8 + 2 + 5 * Math.floor((i / 0xffff) + 1) + i;
114 | return j;
115 | }
116 |
117 | // convert a color and build up the palette
118 | this.color = function(red, green, blue, alpha) {
119 |
120 | alpha = alpha >= 0 ? alpha : 255;
121 | var color = (((((alpha << 8) | red) << 8) | green) << 8) | blue;
122 |
123 | if (typeof this.palette[color] == "undefined") {
124 | if (this.pindex == this.depth) return "\x00";
125 |
126 | var ndx = this.plte_offs + 8 + 3 * this.pindex;
127 |
128 | this.buffer[ndx + 0] = String.fromCharCode(red);
129 | this.buffer[ndx + 1] = String.fromCharCode(green);
130 | this.buffer[ndx + 2] = String.fromCharCode(blue);
131 | this.buffer[this.trns_offs+8+this.pindex] = String.fromCharCode(alpha);
132 |
133 | this.palette[color] = String.fromCharCode(this.pindex++);
134 | }
135 | return this.palette[color];
136 | }
137 |
138 | // output a PNG string, Base64 encoded
139 | this.getBase64 = function() {
140 |
141 | var s = this.getDump();
142 |
143 | var ch = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
144 | var c1, c2, c3, e1, e2, e3, e4;
145 | var l = s.length;
146 | var i = 0;
147 | var r = "";
148 |
149 | do {
150 | c1 = s.charCodeAt(i);
151 | e1 = c1 >> 2;
152 | c2 = s.charCodeAt(i+1);
153 | e2 = ((c1 & 3) << 4) | (c2 >> 4);
154 | c3 = s.charCodeAt(i+2);
155 | if (l < i+2) { e3 = 64; } else { e3 = ((c2 & 0xf) << 2) | (c3 >> 6); }
156 | if (l < i+3) { e4 = 64; } else { e4 = c3 & 0x3f; }
157 | r+= ch.charAt(e1) + ch.charAt(e2) + ch.charAt(e3) + ch.charAt(e4);
158 | } while ((i+= 3) < l);
159 | return r;
160 | }
161 |
162 | // output a PNG string
163 | this.getDump = function() {
164 |
165 | // compute adler32 of output pixels + row filter bytes
166 | var BASE = 65521; /* largest prime smaller than 65536 */
167 | var NMAX = 5552; /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
168 | var s1 = 1;
169 | var s2 = 0;
170 | var n = NMAX;
171 |
172 | for (var y = 0; y < this.height; y++) {
173 | for (var x = -1; x < this.width; x++) {
174 | s1+= this.buffer[this.index(x, y)].charCodeAt(0);
175 | s2+= s1;
176 | if ((n-= 1) == 0) {
177 | s1%= BASE;
178 | s2%= BASE;
179 | n = NMAX;
180 | }
181 | }
182 | }
183 | s1%= BASE;
184 | s2%= BASE;
185 | write(this.buffer, this.idat_offs + this.idat_size - 8, byte4((s2 << 16) | s1));
186 |
187 | // compute crc32 of the PNG chunks
188 | function crc32(png, offs, size) {
189 | var crc = -1;
190 | for (var i = 4; i < size-4; i += 1) {
191 | crc = _crc32[(crc ^ png[offs+i].charCodeAt(0)) & 0xff] ^ ((crc >> 8) & 0x00ffffff);
192 | }
193 | write(png, offs+size-4, byte4(crc ^ -1));
194 | }
195 |
196 | crc32(this.buffer, this.ihdr_offs, this.ihdr_size);
197 | crc32(this.buffer, this.plte_offs, this.plte_size);
198 | crc32(this.buffer, this.trns_offs, this.trns_size);
199 | crc32(this.buffer, this.idat_offs, this.idat_size);
200 | crc32(this.buffer, this.iend_offs, this.iend_size);
201 |
202 | // convert PNG to string
203 | return "\211PNG\r\n\032\n"+this.buffer.join('');
204 | }
205 | }
206 |
207 | })();
208 |
--------------------------------------------------------------------------------