indie-raster 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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