indie-raster 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/.gitignore +5 -0
  2. data/LICENSE.txt +23 -0
  3. data/README.md +98 -0
  4. data/Rakefile +6 -0
  5. data/build-c/indie-raster +0 -0
  6. data/docs/PRF.md +41 -0
  7. data/fonts/README-fonts.md +26 -0
  8. data/fonts/fonts_prf1/dsm-22-italic.prf1 +0 -0
  9. data/fonts/fonts_prf1/dsm-22.prf1 +0 -0
  10. data/fonts/fonts_prf1/dsm-24.prf1 +0 -0
  11. data/fonts/fonts_prf1/dsm-56-bold-inverted.prf1 +0 -0
  12. data/fonts/fonts_vector/dsm/DroidSansMono.ttf +0 -0
  13. data/fonts/fonts_vector/dsm/DroidSansMono.webloc +8 -0
  14. data/fonts/fonts_vector/dsm/LICENSE.txt +202 -0
  15. data/fonts/fonts_vector/dsm/chars-all.json +201 -0
  16. data/fonts/fonts_vector/dsm/chars.json +5 -0
  17. data/fonts/fonts_vector/dsm/chars.txt +22 -0
  18. data/fonts/glyphs/dsm-22-italic.png +0 -0
  19. data/fonts/glyphs/dsm-22.png +0 -0
  20. data/fonts/glyphs/dsm-24.png +0 -0
  21. data/fonts/glyphs/dsm-56-bold-inverted.png +0 -0
  22. data/fonts/make-fonts.sh +20 -0
  23. data/fonts/scripts/html-entities.json +255 -0
  24. data/fonts/scripts/pack-font.coffee +55 -0
  25. data/fonts/scripts/splitter.c +55 -0
  26. data/fonts/scripts/splitter.sh +5 -0
  27. data/fonts/scripts/text-from-json.coffee +20 -0
  28. data/fonts/scripts/util.coffee +39 -0
  29. data/indie-raster.gemspec +19 -0
  30. data/make.sh +13 -0
  31. data/src-c/canvas.c +93 -0
  32. data/src-c/canvas.h +29 -0
  33. data/src-c/commands.c +148 -0
  34. data/src-c/commands.h +26 -0
  35. data/src-c/fonts.c +66 -0
  36. data/src-c/fonts.h +26 -0
  37. data/src-c/main.c +16 -0
  38. data/src-c/make.sh +11 -0
  39. data/src-c/pnm.c +109 -0
  40. data/src-c/pnm.h +20 -0
  41. data/src-c/session.c +36 -0
  42. data/src-c/session.h +24 -0
  43. data/src-c/upc.c +83 -0
  44. data/src-c/upc.h +9 -0
  45. data/src-ruby/indie-raster.rb +95 -0
  46. metadata +99 -0
@@ -0,0 +1,20 @@
1
+
2
+
3
+ cd scripts;
4
+
5
+
6
+ # dsm-56-bold-inverted
7
+ bash splitter.sh ../glyphs/dsm-56-bold-inverted.png 34 56 4 20 21 199 10
8
+ coffee pack-font.coffee --chars=../fonts_vector/dsm/chars-all.json > ../fonts_prf1/dsm-56-bold-inverted.prf1
9
+
10
+ # dsm-22
11
+ bash splitter.sh ../glyphs/dsm-22.png 13 22 4 11 10 199 10
12
+ coffee pack-font.coffee --chars=../fonts_vector/dsm/chars-all.json > ../fonts_prf1/dsm-22.prf1
13
+
14
+ # dsm-22-italic
15
+ bash splitter.sh ../glyphs/dsm-22-italic.png 13 22 6 11 10 199 10
16
+ coffee pack-font.coffee --chars=../fonts_vector/dsm/chars-all.json > ../fonts_prf1/dsm-22-italic.prf1
17
+
18
+ # dsm-24
19
+ bash splitter.sh ../glyphs/dsm-24.png 14 24 4 11 10 199 10
20
+ coffee pack-font.coffee --chars=../fonts_vector/dsm/chars-all.json > ../fonts_prf1/dsm-24.prf1
@@ -0,0 +1,255 @@
1
+ {
2
+ "quot": "\u0022",
3
+ "amp": "\u0026",
4
+ "apos": "\u0027",
5
+ "lt": "\u003C",
6
+ "gt": "\u003E",
7
+ "nbsp": "\u00A0",
8
+ "iexcl": "\u00A1",
9
+ "cent": "\u00A2",
10
+ "pound": "\u00A3",
11
+ "curren": "\u00A4",
12
+ "yen": "\u00A5",
13
+ "brvbar": "\u00A6",
14
+ "sect": "\u00A7",
15
+ "uml": "\u00A8",
16
+ "copy": "\u00A9",
17
+ "ordf": "\u00AA",
18
+ "laquo": "\u00AB",
19
+ "not": "\u00AC",
20
+ "shy": "\u00AD",
21
+ "reg": "\u00AE",
22
+ "macr": "\u00AF",
23
+ "deg": "\u00B0",
24
+ "plusmn": "\u00B1",
25
+ "sup2": "\u00B2",
26
+ "sup3": "\u00B3",
27
+ "acute": "\u00B4",
28
+ "micro": "\u00B5",
29
+ "para": "\u00B6",
30
+ "middot": "\u00B7",
31
+ "cedil": "\u00B8",
32
+ "sup1": "\u00B9",
33
+ "ordm": "\u00BA",
34
+ "raquo": "\u00BB",
35
+ "frac14": "\u00BC",
36
+ "frac12": "\u00BD",
37
+ "frac34": "\u00BE",
38
+ "iquest": "\u00BF",
39
+ "Agrave": "\u00C0",
40
+ "Aacute": "\u00C1",
41
+ "Acirc": "\u00C2",
42
+ "Atilde": "\u00C3",
43
+ "Auml": "\u00C4",
44
+ "Aring": "\u00C5",
45
+ "AElig": "\u00C6",
46
+ "Ccedil": "\u00C7",
47
+ "Egrave": "\u00C8",
48
+ "Eacute": "\u00C9",
49
+ "Ecirc": "\u00CA",
50
+ "Euml": "\u00CB",
51
+ "Igrave": "\u00CC",
52
+ "Iacute": "\u00CD",
53
+ "Icirc": "\u00CE",
54
+ "Iuml": "\u00CF",
55
+ "ETH": "\u00D0",
56
+ "Ntilde": "\u00D1",
57
+ "Ograve": "\u00D2",
58
+ "Oacute": "\u00D3",
59
+ "Ocirc": "\u00D4",
60
+ "Otilde": "\u00D5",
61
+ "Ouml": "\u00D6",
62
+ "times": "\u00D7",
63
+ "Oslash": "\u00D8",
64
+ "Ugrave": "\u00D9",
65
+ "Uacute": "\u00DA",
66
+ "Ucirc": "\u00DB",
67
+ "Uuml": "\u00DC",
68
+ "Yacute": "\u00DD",
69
+ "THORN": "\u00DE",
70
+ "szlig": "\u00DF",
71
+ "agrave": "\u00E0",
72
+ "aacute": "\u00E1",
73
+ "acirc": "\u00E2",
74
+ "atilde": "\u00E3",
75
+ "auml": "\u00E4",
76
+ "aring": "\u00E5",
77
+ "aelig": "\u00E6",
78
+ "ccedil": "\u00E7",
79
+ "egrave": "\u00E8",
80
+ "eacute": "\u00E9",
81
+ "ecirc": "\u00EA",
82
+ "euml": "\u00EB",
83
+ "igrave": "\u00EC",
84
+ "iacute": "\u00ED",
85
+ "icirc": "\u00EE",
86
+ "iuml": "\u00EF",
87
+ "eth": "\u00F0",
88
+ "ntilde": "\u00F1",
89
+ "ograve": "\u00F2",
90
+ "oacute": "\u00F3",
91
+ "ocirc": "\u00F4",
92
+ "otilde": "\u00F5",
93
+ "ouml": "\u00F6",
94
+ "divide": "\u00F7",
95
+ "oslash": "\u00F8",
96
+ "ugrave": "\u00F9",
97
+ "uacute": "\u00FA",
98
+ "ucirc": "\u00FB",
99
+ "uuml": "\u00FC",
100
+ "yacute": "\u00FD",
101
+ "thorn": "\u00FE",
102
+ "yuml": "\u00FF",
103
+ "OElig": "\u0152",
104
+ "oelig": "\u0153",
105
+ "Scaron": "\u0160",
106
+ "scaron": "\u0161",
107
+ "Yuml": "\u0178",
108
+ "fnof": "\u0192",
109
+ "circ": "\u02C6",
110
+ "tilde": "\u02DC",
111
+ "Alpha": "\u0391",
112
+ "Beta": "\u0392",
113
+ "Gamma": "\u0393",
114
+ "Delta": "\u0394",
115
+ "Epsilon": "\u0395",
116
+ "Zeta": "\u0396",
117
+ "Eta": "\u0397",
118
+ "Theta": "\u0398",
119
+ "Iota": "\u0399",
120
+ "Kappa": "\u039A",
121
+ "Lambda": "\u039B",
122
+ "Mu": "\u039C",
123
+ "Nu": "\u039D",
124
+ "Xi": "\u039E",
125
+ "Omicron": "\u039F",
126
+ "Pi": "\u03A0",
127
+ "Rho": "\u03A1",
128
+ "Sigma": "\u03A3",
129
+ "Tau": "\u03A4",
130
+ "Upsilon": "\u03A5",
131
+ "Phi": "\u03A6",
132
+ "Chi": "\u03A7",
133
+ "Psi": "\u03A8",
134
+ "Omega": "\u03A9",
135
+ "alpha": "\u03B1",
136
+ "beta": "\u03B2",
137
+ "gamma": "\u03B3",
138
+ "delta": "\u03B4",
139
+ "epsilon": "\u03B5",
140
+ "zeta": "\u03B6",
141
+ "eta": "\u03B7",
142
+ "theta": "\u03B8",
143
+ "iota": "\u03B9",
144
+ "kappa": "\u03BA",
145
+ "lambda": "\u03BB",
146
+ "mu": "\u03BC",
147
+ "nu": "\u03BD",
148
+ "xi": "\u03BE",
149
+ "omicron": "\u03BF",
150
+ "pi": "\u03C0",
151
+ "rho": "\u03C1",
152
+ "sigmaf": "\u03C2",
153
+ "sigma": "\u03C3",
154
+ "tau": "\u03C4",
155
+ "upsilon": "\u03C5",
156
+ "phi": "\u03C6",
157
+ "chi": "\u03C7",
158
+ "psi": "\u03C8",
159
+ "omega": "\u03C9",
160
+ "thetasym": "\u03D1",
161
+ "upsih": "\u03D2",
162
+ "piv": "\u03D6",
163
+ "ensp": "\u2002",
164
+ "emsp": "\u2003",
165
+ "thinsp": "\u2009",
166
+ "zwnj": "\u200C",
167
+ "zwj": "\u200D",
168
+ "lrm": "\u200E",
169
+ "rlm": "\u200F",
170
+ "ndash": "\u2013",
171
+ "mdash": "\u2014",
172
+ "lsquo": "\u2018",
173
+ "rsquo": "\u2019",
174
+ "sbquo": "\u201A",
175
+ "ldquo": "\u201C",
176
+ "rdquo": "\u201D",
177
+ "bdquo": "\u201E",
178
+ "dagger": "\u2020",
179
+ "Dagger": "\u2021",
180
+ "bull": "\u2022",
181
+ "hellip": "\u2026",
182
+ "permil": "\u2030",
183
+ "prime": "\u2032",
184
+ "Prime": "\u2033",
185
+ "lsaquo": "\u2039",
186
+ "rsaquo": "\u203A",
187
+ "oline": "\u203E",
188
+ "frasl": "\u2044",
189
+ "euro": "\u20AC",
190
+ "image": "\u2111",
191
+ "weierp": "\u2118",
192
+ "real": "\u211C",
193
+ "trade": "\u2122",
194
+ "alefsym": "\u2135",
195
+ "larr": "\u2190",
196
+ "uarr": "\u2191",
197
+ "rarr": "\u2192",
198
+ "darr": "\u2193",
199
+ "harr": "\u2194",
200
+ "crarr": "\u21B5",
201
+ "lArr": "\u21D0",
202
+ "uArr": "\u21D1",
203
+ "rArr": "\u21D2",
204
+ "dArr": "\u21D3",
205
+ "hArr": "\u21D4",
206
+ "forall": "\u2200",
207
+ "part": "\u2202",
208
+ "exist": "\u2203",
209
+ "empty": "\u2205",
210
+ "nabla": "\u2207",
211
+ "isin": "\u2208",
212
+ "notin": "\u2209",
213
+ "ni": "\u220B",
214
+ "prod": "\u220F",
215
+ "sum": "\u2211",
216
+ "minus": "\u2212",
217
+ "lowast": "\u2217",
218
+ "radic": "\u221A",
219
+ "prop": "\u221D",
220
+ "infin": "\u221E",
221
+ "ang": "\u2220",
222
+ "and": "\u2227",
223
+ "or": "\u2228",
224
+ "cap": "\u2229",
225
+ "cup": "\u222A",
226
+ "int": "\u222B",
227
+ "there4": "\u2234",
228
+ "sim": "\u223C",
229
+ "cong": "\u2245",
230
+ "asymp": "\u2248",
231
+ "ne": "\u2260",
232
+ "equiv": "\u2261",
233
+ "le": "\u2264",
234
+ "ge": "\u2265",
235
+ "sub": "\u2282",
236
+ "sup": "\u2283",
237
+ "nsub": "\u2284",
238
+ "sube": "\u2286",
239
+ "supe": "\u2287",
240
+ "oplus": "\u2295",
241
+ "otimes": "\u2297",
242
+ "perp": "\u22A5",
243
+ "sdot": "\u22C5",
244
+ "lceil": "\u2308",
245
+ "rceil": "\u2309",
246
+ "lfloor": "\u230A",
247
+ "rfloor": "\u230B",
248
+ "lang": "\u27E8",
249
+ "rang": "\u27E9",
250
+ "loz": "\u25CA",
251
+ "spades": "\u2660",
252
+ "clubs": "\u2663",
253
+ "hearts": "\u2665",
254
+ "diams": "\u2666"
255
+ }
@@ -0,0 +1,55 @@
1
+ fs = require 'fs'
2
+ assert = require 'assert'
3
+ {charsForJSONPath, uint32le} = require './util'
4
+ {joinBuffers, parsePNM} = require 'tafa-misc-util'
5
+
6
+ ###
7
+
8
+ coffee pack-font.coffee --chars=../fonts_vector/dsm/chars-all.json
9
+ > fonts_prf1/dsm-56-bold-inverted.prf1
10
+
11
+ ###
12
+
13
+ {chars} = require('optimist').demand(['chars']).argv
14
+ chars = charsForJSONPath chars
15
+
16
+ # load images
17
+ filenums = []
18
+ for filename in fs.readdirSync("temp/glyphs")
19
+ if m = filename.match /^([0-9]+).pbm/
20
+ filenums.push parseInt(m[1], 10)
21
+ imgs = []
22
+ filenums.sort (x, y) -> x - y
23
+ for n in filenums
24
+ imgs.push fs.readFileSync "temp/glyphs/#{n}.pbm"
25
+
26
+ # find image width, height
27
+ {w, h} = parsePNM imgs[0]
28
+
29
+
30
+ assert.equal chars.length, imgs.length
31
+
32
+ bufs = [
33
+ new Buffer("PRF1")
34
+ uint32le(chars.length)
35
+ uint32le(w)
36
+ uint32le(h)
37
+ ]
38
+
39
+ # uint32+ char_codes
40
+ for c in chars
41
+ bufs.push uint32le c.charCodeAt 0
42
+
43
+ # uint32+ image_byte_offets
44
+ offset = 4 + 4 + (chars.length * 8)
45
+ for i in [0...chars.length]
46
+ bufs.push uint32le offset
47
+ offset += imgs[i].length
48
+
49
+ # data+ images
50
+ for x in imgs
51
+ bufs.push x
52
+
53
+
54
+ process.stdout.write joinBuffers bufs
55
+
@@ -0,0 +1,55 @@
1
+
2
+ #include <stdio.h>
3
+ #include <stdlib.h>
4
+
5
+ #include "../../src-c/canvas.h"
6
+ #include "../../src-c/pnm.h"
7
+
8
+
9
+ int main(int argc, char *argv[]) {
10
+
11
+ char *path = argv[1];
12
+
13
+ long w = atol(argv[2]);
14
+ long h = atol(argv[3]);
15
+ long x0 = atol(argv[4]);
16
+ long y0 = atol(argv[5]);
17
+ long vs = atol(argv[6]);
18
+ long n = atol(argv[7]);
19
+ long wrap = atol(argv[8]);
20
+
21
+ // glyphs.pbm
22
+ char cmd[1000];
23
+ sprintf(cmd, "convert '%s' temp/glyphs.pbm", path);
24
+ system(cmd);
25
+
26
+ // load it
27
+ FILE *f = fopen("temp/glyphs.pbm", "r");
28
+ Canvas *glyphs = Canvas_readImage(f);
29
+
30
+
31
+ // temp/glyphs/N.pbm
32
+
33
+ long i, x, y, pixelX, pixelY;
34
+ char outpath[1000];
35
+ FILE *outfile;
36
+
37
+ system("mkdir -p temp/glyphs");
38
+ system("rm -rf temp/glyphs");
39
+ system("mkdir -p temp/glyphs");
40
+
41
+ for (i = 0; i < n; i++) {
42
+ x = (i % wrap);
43
+ y = (i / wrap);
44
+ pixelX = x0 + w * x;
45
+ pixelY = y0 + (h + vs) * y;
46
+
47
+
48
+ sprintf(outpath, "temp/glyphs/%ld.pbm", i);
49
+ outfile = fopen(outpath, "w");
50
+ Canvas_writeSubrectP4(glyphs, outfile, pixelX, pixelY, w, h);
51
+ fclose(outfile);
52
+ }
53
+
54
+ return 0;
55
+ }
@@ -0,0 +1,5 @@
1
+
2
+ mkdir -p temp
3
+
4
+ gcc -o temp/splitter splitter.c ../../src-c/pnm.c ../../src-c/canvas.c && temp/splitter $1 $2 $3 $4 $5 $6 $7 $8
5
+
@@ -0,0 +1,20 @@
1
+
2
+ fs = require 'fs'
3
+ {charsForSlug} = require './util'
4
+
5
+ {slug} = require('optimist').demand(['slug']).argv
6
+
7
+
8
+
9
+
10
+ # chars_text
11
+ arr = []
12
+ for char, i in charsForSlug(slug)
13
+ if i % 10 == 0 and i > 0
14
+ arr.push '\n'
15
+ arr.push char
16
+ arr.push '\n\n\n'
17
+ chars_text = arr.join ''
18
+
19
+ fs.writeFileSync "../fonts_vector/#{slug}/chars.txt", new Buffer chars_text
20
+
@@ -0,0 +1,39 @@
1
+
2
+
3
+ fs = require 'fs'
4
+
5
+
6
+ exports.uint32le = (x) ->
7
+ new Buffer [
8
+ x % 0xFF,
9
+ (x >> 8) % 0xFF,
10
+ (x >> 16) % 0xFF,
11
+ (x >> 24) % 0xFF,
12
+ ]
13
+
14
+
15
+ #TODO use the next instead of this
16
+ exports.charsForSlug = charsForSlug = (slug) ->
17
+ char_htmls = JSON.parse fs.readFileSync "../fonts_vector/#{slug}/chars.json"
18
+ for x in char_htmls
19
+ decodeEntityIfNeeded x
20
+
21
+
22
+ exports.charsForJSONPath = charsForJSONPath = (path) ->
23
+ char_htmls = JSON.parse fs.readFileSync path
24
+ for x in char_htmls
25
+ decodeEntityIfNeeded x
26
+
27
+
28
+ entities = JSON.parse fs.readFileSync "html-entities.json"
29
+
30
+ decodeEntityIfNeeded = (s) ->
31
+ if m = s.match /&#([0-9]+);/
32
+ String.fromCharCode parseInt(m[1], 10)
33
+ else if m = s.match /&#x([0-9]+);/
34
+ String.fromCharCode parseInt(m[1], 16)
35
+ else if m = s.match /&(.*);/
36
+ entities[m[1]]
37
+ else
38
+ s
39
+
@@ -0,0 +1,19 @@
1
+
2
+ Gem::Specification.new do |s|
3
+
4
+ s.name = "indie-raster"
5
+ s.version = "0.0.1"
6
+
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = ["ShopKeep"]
9
+ s.email = ["opensource@shopkeep.com"]
10
+ s.homepage = "http://github.com/shopkeep/indie-raster"
11
+ s.summary = "A small raster graphics library."
12
+ s.description = "A small raster graphics library with pixel fonts and no dependencies."
13
+
14
+ s.required_rubygems_version = ">= 1.3.6"
15
+
16
+ s.files = `git ls-files`.split
17
+
18
+ s.require_paths = ["src-ruby"]
19
+ end
data/make.sh ADDED
@@ -0,0 +1,13 @@
1
+ #!/bin/bash
2
+
3
+ gcc \
4
+ -O2 \
5
+ -o build-c/indie-raster \
6
+ src-c/canvas.c \
7
+ src-c/commands.c \
8
+ src-c/fonts.c \
9
+ src-c/main.c \
10
+ src-c/session.c \
11
+ src-c/upc.c \
12
+ src-c/pnm.c
13
+
data/src-c/canvas.c ADDED
@@ -0,0 +1,93 @@
1
+
2
+ #include "canvas.h"
3
+
4
+
5
+ Canvas* Canvas_new(long w, long h) {
6
+ Canvas *c;
7
+ int bpp = 1;
8
+ int size = w * h * bpp;
9
+
10
+ c = (Canvas *)malloc(sizeof(Canvas));
11
+ c->w = w;
12
+ c->h = h;
13
+ c->bpp = bpp;
14
+ c->pixels = (unsigned char *)malloc(size);
15
+ memset(c->pixels, 255, size);
16
+
17
+ return c;
18
+ }
19
+
20
+
21
+ Canvas* Canvas_readImage(FILE *f) {
22
+
23
+ Canvas *c;
24
+ int bpp = 1;
25
+ int size;
26
+
27
+ long w, h;
28
+ int p, maxValue;
29
+ unsigned char *pixels;
30
+
31
+ util_read_pnm_header(f, &p, &w, &h, &maxValue);
32
+
33
+ size = w * h * bpp;
34
+ c = (Canvas *)malloc(sizeof(Canvas));
35
+ c->w = w;
36
+ c->h = h;
37
+ c->bpp = bpp;
38
+
39
+ if (p == 4) {
40
+ util_read_p4_body(f, w, h, &pixels);
41
+ c->pixels = pixels;
42
+ }
43
+ else {
44
+ // HANDLE
45
+ }
46
+
47
+ return c;
48
+ }
49
+
50
+
51
+ void Canvas_free(Canvas **c) {
52
+ free((*c)->pixels);
53
+ free(*c);
54
+ *c = 0;
55
+ }
56
+
57
+
58
+ void Canvas_writeP4(Canvas *c, FILE *f) {
59
+ Canvas_writeSubrectP4(c, f, 0, 0, c->w, c->h);
60
+ }
61
+
62
+
63
+ void Canvas_writeSubrectP4(Canvas *c, FILE *f, long x, long y, long w, long h) {
64
+ if (c->bpp == 1) {
65
+ fprintf(f, "P4\n%ld %ld\n", w, h);
66
+ util_write_p4_body_from_subrect(f, x, y, w, h, c->w, c->pixels);
67
+ }
68
+ else {
69
+ // HANDLE
70
+ }
71
+ }
72
+
73
+
74
+ void Canvas_drawOnto(Canvas *src, Canvas *dest, long x0, long y0) {
75
+
76
+ long n;
77
+ long src_x, src_y, dest_x, dest_y;
78
+
79
+ n = 0;
80
+ for (src_y = 0; src_y < src->h; src_y++) {
81
+ dest_y = src_y + y0;
82
+ if (dest_y < dest->h) {
83
+ for (src_x = 0; src_x < src->w; src_x++) {
84
+ n++;
85
+ dest_x = src_x + x0;
86
+ if (dest_x < dest->w) {
87
+ dest->pixels[(dest_y * dest->w) + dest_x] = src->pixels[(src_y * src->w) + src_x];
88
+ }
89
+ }
90
+ }
91
+ }
92
+ }
93
+
data/src-c/canvas.h ADDED
@@ -0,0 +1,29 @@
1
+
2
+ #ifndef CANVAS_INCLUDED
3
+ #define CANVAS_INCLUDED
4
+
5
+ #include <stdio.h>
6
+ #include <stddef.h>
7
+ #include <stdlib.h>
8
+ #include <string.h>
9
+
10
+ #include "pnm.h"
11
+
12
+
13
+ typedef struct {
14
+ long w;
15
+ long h;
16
+ int bpp;
17
+ unsigned char *pixels;
18
+ } Canvas;
19
+
20
+
21
+ Canvas* Canvas_new(long w, long h);
22
+ Canvas* Canvas_readImage(FILE *f);
23
+
24
+ void Canvas_free(Canvas **c);
25
+ void Canvas_writeP4(Canvas *c, FILE *f);
26
+ void Canvas_writeSubrectP4(Canvas *c, FILE *f, long x, long y, long w, long h);
27
+ void Canvas_drawOnto(Canvas *src, Canvas *dest, long x0, long y0);
28
+
29
+ #endif