/[james]/archive/pngrender/pngrender.c
ViewVC logotype

Contents of /archive/pngrender/pngrender.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 17 - (show annotations) (download) (as text)
Tue Feb 11 09:59:30 2003 UTC (21 years, 10 months ago) by james
File MIME type: text/x-csrc
File size: 18740 byte(s)
Initial import.

1 /*
2 * pngrender.c
3 */
4
5 /*
6 ________________________________________________________________________________
7
8 Copyright (c) 2001 James Bursa
9
10 All rights reserved.
11
12 Permission is hereby granted, free of charge, to any person obtaining a
13 copy of this software and associated documentation files (the
14 "Software"), to deal in the Software without restriction, including
15 without limitation the rights to use, copy, modify, merge, publish,
16 distribute, and/or sell copies of the Software, and to permit persons
17 to whom the Software is furnished to do so, provided that the above
18 copyright notice(s) and this permission notice appear in all copies of
19 the Software and that both the above copyright notice(s) and this
20 permission notice appear in supporting documentation.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
25 OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
26 HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
27 INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
28 FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
29 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
30 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
31
32 Except as contained in this notice, the name of a copyright holder
33 shall not be used in advertising or otherwise to promote the sale, use
34 or other dealings in this Software without prior written authorization
35 of the copyright holder.
36
37 ________________________________________________________________________________
38
39 james.bursa@strcprstskrzkrk.co.uk
40 http://www.strcprstskrzkrk.co.uk/
41
42 ________________________________________________________________________________
43 */
44
45 #include <stdio.h>
46 #include <stdlib.h>
47
48 #include <png.h>
49
50 #include <colourtrans.h>
51 #include <os.h>
52
53 /********************************************************************************/
54
55 int render_png_file(const char *path, signed int x, signed int y);
56 int load_png_file(png_struct *png, png_info *info, const char *path);
57 int render_png_to_screen(png_struct *png, png_info *info, signed int value_list[],
58 signed int x, signed int y);
59 void png_render_32(png_byte *prows[], unsigned char *srow, signed int x0,
60 signed int y0, signed int x1, signed int y1, signed int sx,
61 unsigned int sline_length, unsigned int pchannels);
62 void png_render_16(png_byte *prows[], unsigned char *srow, signed int x0,
63 signed int y0, signed int x1, signed int y1, signed int sx,
64 unsigned int sline_length, unsigned int pchannels);
65 int png_render_8(png_byte *prows[], unsigned char *srow, signed int x0,
66 signed int y0, signed int x1, signed int y1, signed int sx,
67 unsigned int sline_length, unsigned int pchannels);
68 int png_render_4(png_byte *prows[], unsigned char *srow, signed int x0,
69 signed int y0, signed int x1, signed int y1, signed int sx,
70 unsigned int sline_length, unsigned int pchannels);
71 os_palette *read_palette();
72
73 /********************************************************************************/
74
75 float alpha_table[] = {
76 0.0, 1.0/255, 2.0/255, 3.0/255, 4.0/255, 5.0/255,
77 6.0/255, 7.0/255, 8.0/255, 9.0/255, 10.0/255, 11.0/255,
78 12.0/255, 13.0/255, 14.0/255, 15.0/255, 16.0/255, 17.0/255,
79 18.0/255, 19.0/255, 20.0/255, 21.0/255, 22.0/255, 23.0/255,
80 24.0/255, 25.0/255, 26.0/255, 27.0/255, 28.0/255, 29.0/255,
81 30.0/255, 31.0/255, 32.0/255, 33.0/255, 34.0/255, 35.0/255,
82 36.0/255, 37.0/255, 38.0/255, 39.0/255, 40.0/255, 41.0/255,
83 42.0/255, 43.0/255, 44.0/255, 45.0/255, 46.0/255, 47.0/255,
84 48.0/255, 49.0/255, 50.0/255, 51.0/255, 52.0/255, 53.0/255,
85 54.0/255, 55.0/255, 56.0/255, 57.0/255, 58.0/255, 59.0/255,
86 60.0/255, 61.0/255, 62.0/255, 63.0/255, 64.0/255, 65.0/255,
87 66.0/255, 67.0/255, 68.0/255, 69.0/255, 70.0/255, 71.0/255,
88 72.0/255, 73.0/255, 74.0/255, 75.0/255, 76.0/255, 77.0/255,
89 78.0/255, 79.0/255, 80.0/255, 81.0/255, 82.0/255, 83.0/255,
90 84.0/255, 85.0/255, 86.0/255, 87.0/255, 88.0/255, 89.0/255,
91 90.0/255, 91.0/255, 92.0/255, 93.0/255, 94.0/255, 95.0/255,
92 96.0/255, 97.0/255, 98.0/255, 99.0/255, 100.0/255, 101.0/255,
93 102.0/255, 103.0/255, 104.0/255, 105.0/255, 106.0/255, 107.0/255,
94 108.0/255, 109.0/255, 110.0/255, 111.0/255, 112.0/255, 113.0/255,
95 114.0/255, 115.0/255, 116.0/255, 117.0/255, 118.0/255, 119.0/255,
96 120.0/255, 121.0/255, 122.0/255, 123.0/255, 124.0/255, 125.0/255,
97 126.0/255, 127.0/255, 128.0/255, 129.0/255, 130.0/255, 131.0/255,
98 132.0/255, 133.0/255, 134.0/255, 135.0/255, 136.0/255, 137.0/255,
99 138.0/255, 139.0/255, 140.0/255, 141.0/255, 142.0/255, 143.0/255,
100 144.0/255, 145.0/255, 146.0/255, 147.0/255, 148.0/255, 149.0/255,
101 150.0/255, 151.0/255, 152.0/255, 153.0/255, 154.0/255, 155.0/255,
102 156.0/255, 157.0/255, 158.0/255, 159.0/255, 160.0/255, 161.0/255,
103 162.0/255, 163.0/255, 164.0/255, 165.0/255, 166.0/255, 167.0/255,
104 168.0/255, 169.0/255, 170.0/255, 171.0/255, 172.0/255, 173.0/255,
105 174.0/255, 175.0/255, 176.0/255, 177.0/255, 178.0/255, 179.0/255,
106 180.0/255, 181.0/255, 182.0/255, 183.0/255, 184.0/255, 185.0/255,
107 186.0/255, 187.0/255, 188.0/255, 189.0/255, 190.0/255, 191.0/255,
108 192.0/255, 193.0/255, 194.0/255, 195.0/255, 196.0/255, 197.0/255,
109 198.0/255, 199.0/255, 200.0/255, 201.0/255, 202.0/255, 203.0/255,
110 204.0/255, 205.0/255, 206.0/255, 207.0/255, 208.0/255, 209.0/255,
111 210.0/255, 211.0/255, 212.0/255, 213.0/255, 214.0/255, 215.0/255,
112 216.0/255, 217.0/255, 218.0/255, 219.0/255, 220.0/255, 221.0/255,
113 222.0/255, 223.0/255, 224.0/255, 225.0/255, 226.0/255, 227.0/255,
114 228.0/255, 229.0/255, 230.0/255, 231.0/255, 232.0/255, 233.0/255,
115 234.0/255, 235.0/255, 236.0/255, 237.0/255, 238.0/255, 239.0/255,
116 240.0/255, 241.0/255, 242.0/255, 243.0/255, 244.0/255, 245.0/255,
117 246.0/255, 247.0/255, 248.0/255, 249.0/255, 250.0/255, 251.0/255,
118 252.0/255, 253.0/255, 254.0/255, 1.0 };
119
120 /********************************************************************************/
121
122 int main(int argc, char *argv[])
123 {
124 char *end;
125
126 if (argc != 4)
127 {
128 fprintf(stderr, "Usage: pngrender file x y\n");
129 exit(1);
130 }
131
132 return render_png_file(argv[1], strtol(argv[2], &end, 10), strtol(argv[3], &end, 10));
133 }
134
135 /********************************************************************************
136 * render a png file to the screen
137 * => path -- filename of png file to render
138 * x, y -- position of bottom-left corner in os units from screen bottom-left
139 * <= return code:
140 * 0 - OK
141 * -1 - file failed to open
142 * -2 - couldn't read header
143 * -3 - not a png
144 * -4 - bpp of png not understood
145 * -5 - malloc or colourtrans failed
146 * other - os error number from OS_ReadVduVariables
147 */
148
149 int render_png_file(const char *path, signed int x, signed int y)
150 {
151 unsigned int status;
152 signed int value_list[20];
153 png_struct *png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
154 png_info *info = png_create_info_struct(png);
155 const os_vdu_var var_list[] = {os_MODEVAR_LINE_LENGTH, os_MODEVAR_LOG2_BPP,
156 os_MODEVAR_XEIG_FACTOR, os_MODEVAR_YEIG_FACTOR,
157 os_VDUVAR_GWL_COL, os_VDUVAR_GWB_ROW, os_VDUVAR_GWR_COL, os_VDUVAR_GWT_ROW,
158 os_VDUVAR_ORGX, os_VDUVAR_ORGY, os_VDUVAR_SCREEN_START,
159 os_MODEVAR_YWIND_LIMIT, -1};
160 os_error const *error;
161
162 status = load_png_file(png, info, path);
163 if (status)
164 {
165 png_destroy_read_struct(&png, &info, (png_info **) NULL);
166 return status;
167 }
168
169 error = xos_read_vdu_variables((os_vdu_var_list *) &var_list, value_list);
170 if (error)
171 {
172 png_destroy_read_struct(&png, &info, (png_info **) NULL);
173 return error->errnum;
174 }
175
176 status = render_png_to_screen(png, info, value_list, x, y);
177 png_destroy_read_struct(&png, &info, (png_info **) NULL);
178 return status;
179 }
180
181 /********************************************************************************/
182
183 int load_png_file(png_struct *png, png_info *info, const char *path)
184 {
185 unsigned char buf[10];
186 FILE *file;
187
188 if (!(file = fopen(path, "rb"))) return -1;
189 if (fread(buf, 1, 8, file) < 8) return -2;
190 if (png_sig_cmp(buf, 0, 8) != 0) return -3;
191
192 rewind(file);
193
194 png_init_io(png, file);
195 png_read_png(png, info,
196 PNG_TRANSFORM_STRIP_16 // Strip 16-bit samples to 8 bits
197 | PNG_TRANSFORM_PACKING // Expand 1, 2 and 4-bit samples to bytes
198 | PNG_TRANSFORM_EXPAND // Perform set_expand()
199 , NULL);
200
201 fclose(file);
202
203 return 0;
204 }
205
206 /********************************************************************************/
207
208 int render_png_to_screen(png_struct *png, png_info *info, signed int value_list[],
209 signed int sx, signed int sy)
210 {
211 unsigned char *srow;
212 unsigned int pwidth, pheight, pchannels, sbpp, sline_length, ox, oy;
213 signed int x0, y0, x1, y1;
214 png_byte **prows;
215
216 pchannels = png_get_channels(png, info); /* png channels, including alpha */
217 pwidth = png_get_image_width(png, info); /* png width / pixels */
218 pheight = png_get_image_height(png, info); /* png height / pixels */
219 prows = png_get_rows(png, info); /* array of png rows data */
220
221 sline_length = value_list[0]; /* screen line length / bytes */
222 sbpp = 1 << value_list[1]; /* screen depth */
223
224 ox = value_list[8] >> value_list[2]; /* graphics origin / pixels */
225 oy = value_list[9] >> value_list[2];
226 sx = (sx >> value_list[2]) + ox; /* x / pixels */
227 sy = (sy >> value_list[3]) + oy; /* y / pixels */
228
229 x0 = value_list[4] - sx; /* graphics window relative to */
230 y0 = value_list[5] - sy; /* image origin / pixels */
231 x1 = value_list[6] - sx;
232 y1 = value_list[7] - sy;
233
234 if (x0 < 0) x0 = 0; /* region of image to render */
235 if (y0 < 0) y0 = 0;
236 if (x1 >= pwidth) x1 = pwidth - 1;
237 if (y1 >= pheight) y1 = pheight - 1;
238
239 if (x0 >= pwidth) return 0; /* outside graphics window */
240 if (y0 >= pheight) return 0;
241 if (x1 < 0) return 0;
242 if (y1 < 0) return 0;
243
244 srow = (unsigned char *) (value_list[10] +
245 (value_list[11] - sy - pheight + 1) * sline_length);
246
247 switch (sbpp)
248 {
249 case 32:
250 png_render_32(prows, srow, x0, pheight - 1 - y1, x1, pheight - 1 - y0,
251 sx, sline_length, pchannels);
252 break;
253
254 case 16:
255 png_render_16(prows, srow, x0, pheight - 1 - y1, x1, pheight - 1 - y0,
256 sx, sline_length, pchannels);
257 break;
258
259 case 8:
260 return png_render_8(prows, srow, x0, pheight - 1 - y1, x1, pheight - 1 - y0,
261 sx, sline_length, pchannels);
262
263 case 4:
264 return png_render_4(prows, srow, x0, pheight - 1 - y1, x1, pheight - 1 - y0,
265 sx, sline_length, pchannels);
266 }
267
268 return 0;
269 }
270
271 /********************************************************************************/
272
273 void png_render_32(png_byte *prows[], unsigned char *srow, signed int x0,
274 signed int y0, signed int x1, signed int y1, signed int sx,
275 unsigned int sline_length, unsigned int pchannels)
276 {
277 unsigned char pr, pg, pb, sr, sb, sg, *pbyte, *sbyte;
278 unsigned int prow, pcol, palpha;
279 float alphaf, ialphaf;
280
281 for (prow = y0; prow <= y1; prow++)
282 {
283 pbyte = prows[prow] + (x0 * pchannels);
284 sbyte = srow + sline_length * prow + (sx + x0) * 4;
285
286 for (pcol = x0; pcol <= x1; pcol++)
287 {
288 pr = *pbyte++;
289 if (pchannels == 1 || pchannels == 2) pg = pb = pr; /* greyscale */
290 else { pg = *pbyte++; pb = *pbyte++; } /* colour */
291
292 palpha = (pchannels == 4 || pchannels == 2 ? *pbyte++ : 255);
293
294 if (palpha == 0) { sbyte += 4; continue; } /* fully transparent */
295
296 if (palpha != 255) /* partially transparent */
297 {
298 alphaf = alpha_table[palpha];
299 ialphaf = alpha_table[255 - palpha];
300
301 sr = *sbyte; sg = *(sbyte + 1); sb = *(sbyte + 2);
302
303 pr = alphaf * pr + ialphaf * sr;
304 pg = alphaf * pg + ialphaf * sg;
305 pb = alphaf * pb + ialphaf * sb;
306 }
307
308 *sbyte++ = pr; *sbyte++ = pg; *sbyte++ = pb; sbyte++;
309 }
310 }
311 }
312
313 /********************************************************************************/
314
315 void png_render_16(png_byte *prows[], unsigned char *srow, signed int x0,
316 signed int y0, signed int x1, signed int y1, signed int sx,
317 unsigned int sline_length, unsigned int pchannels)
318 {
319 unsigned char pr, pg, pb, sr, sb, sg, *pbyte, *sbyte;
320 unsigned int prow, pcol, palpha;
321 float alphaf, ialphaf;
322
323 for (prow = y0; prow <= y1; prow++)
324 {
325 pbyte = prows[prow] + (x0 * pchannels);
326 sbyte = srow + sline_length * prow + (sx + x0) * 2;
327
328 for (pcol = x0; pcol <= x1; pcol++)
329 {
330 pr = *pbyte++ >> 3;
331 if (pchannels == 1 || pchannels == 2) pg = pb = pr;
332 else { pg = *pbyte++ >> 3; pb = *pbyte++ >> 3; }
333
334 palpha = (pchannels == 4 || pchannels == 2 ? *pbyte++ : 255);
335
336 if (palpha == 0) { sbyte += 2; continue; }
337
338 if (palpha != 255)
339 {
340 alphaf = alpha_table[palpha];
341 ialphaf = alpha_table[255 - palpha];
342
343 sr = *sbyte & 0x1f;
344 sg = (*sbyte >> 5) | ((*(sbyte + 1) & 0x3) << 3);
345 sb = (*(sbyte + 1) >> 2) & 0x1f;
346
347 pr = alphaf * pr + ialphaf * sr;
348 pg = alphaf * pg + ialphaf * sg;
349 pb = alphaf * pb + ialphaf * sb;
350 }
351
352 *sbyte++ = (pg << 5) | pr;
353 *sbyte++ = (pb << 2) | (pg >> 3);
354 }
355 }
356 }
357
358 /********************************************************************************/
359
360 int png_render_8(png_byte *prows[], unsigned char *srow, signed int x0,
361 signed int y0, signed int x1, signed int y1, signed int sx,
362 unsigned int sline_length, unsigned int pchannels)
363 {
364 unsigned char pr, pg, pb, sr, sb, sg, *pbyte, *sbyte, map[0x1000];
365 unsigned int prow, pcol, palpha, colour;
366 float alphaf, ialphaf;
367 os_palette *palette;
368 os_colour scolour;
369
370 palette = read_palette();
371 if (!palette) return -5;
372
373 for (colour = 0; colour < 0x1000; colour++)
374 {
375 map[colour] = colourtrans_return_colour_number(
376 ((colour & 0xf) << 8) | /* red */
377 ((colour & 0xf) << 12) |
378 (((colour >> 4) & 0xf) << 16) | /* green */
379 (((colour >> 4) & 0xf) << 20) |
380 (((colour >> 8) & 0xf) << 24) | /* blue */
381 (((colour >> 8) & 0xf) << 28));
382 }
383
384 /* render image */
385 for (prow = y0; prow <= y1; prow++)
386 {
387 pbyte = prows[prow] + (x0 * pchannels);
388 sbyte = srow + sline_length * prow + sx + x0;
389
390 for (pcol = x0; pcol <= x1; pcol++)
391 {
392 pr = *pbyte++;
393 if (pchannels == 1 || pchannels == 2) pg = pb = pr;
394 else { pg = *pbyte++; pb = *pbyte++; }
395
396 palpha = (pchannels == 4 || pchannels == 2 ? *pbyte++ : 255);
397
398 if (palpha == 0) { sbyte++; continue; }
399
400 if (palpha != 255)
401 {
402 alphaf = alpha_table[palpha];
403 ialphaf = alpha_table[255 - palpha];
404
405 scolour = palette->entries[*sbyte];
406 sr = (scolour >> 8) & 0xff;
407 sg = (scolour >> 16) & 0xff;
408 sb = (scolour >> 24) & 0xff;
409
410 pr = alphaf * pr + ialphaf * sr;
411 pg = alphaf * pg + ialphaf * sg;
412 pb = alphaf * pb + ialphaf * sb;
413 }
414
415 *sbyte++ = map[(pr >> 4) | (pg & 0xf0) | ((pb << 4) & 0xf00)];
416 }
417 }
418
419 free(palette);
420
421 return 0;
422 }
423
424 /********************************************************************************/
425
426 int png_render_4(png_byte *prows[], unsigned char *srow, signed int x0,
427 signed int y0, signed int x1, signed int y1, signed int sx,
428 unsigned int sline_length, unsigned int pchannels)
429 {
430 unsigned char pr, pg, pb, sr, sb, sg, *pbyte, *sbyte, map[0x1000];
431 unsigned int prow, pcol, palpha, spix, colour;
432 float alphaf, ialphaf;
433 os_palette *palette;
434 os_colour scolour;
435
436 palette = read_palette();
437 if (!palette) return -5;
438
439 for (colour = 0; colour < 0x1000; colour++)
440 {
441 map[colour] = colourtrans_return_colour_number(
442 ((colour & 0xf) << 8) | /* red */
443 ((colour & 0xf) << 12) |
444 (((colour >> 4) & 0xf) << 16) | /* green */
445 (((colour >> 4) & 0xf) << 20) |
446 (((colour >> 8) & 0xf) << 24) | /* blue */
447 (((colour >> 8) & 0xf) << 28));
448 }
449
450 /* render image */
451 for (prow = y0; prow <= y1; prow++)
452 {
453 pbyte = prows[prow] + (x0 * pchannels);
454 sbyte = srow + sline_length * prow + (sx + x0) / 2;
455 spix = (sx + x0) & 1;
456
457 for (pcol = x0; pcol <= x1; pcol++)
458 {
459 pr = *pbyte++;
460 if (pchannels == 1 || pchannels == 2) pg = pb = pr;
461 else { pg = *pbyte++; pb = *pbyte++; }
462
463 palpha = (pchannels == 4 || pchannels == 2 ? *pbyte++ : 255);
464
465 if (palpha == 0)
466 {
467 spix = 1 - spix;
468 if (spix == 0) sbyte++;
469 continue;
470 }
471
472 if (palpha != 255)
473 {
474 alphaf = alpha_table[palpha];
475 ialphaf = alpha_table[255 - palpha];
476
477 scolour = (spix ? palette->entries[(*sbyte >> 4) & 0xf]
478 : palette->entries[*sbyte & 0xf]);
479 sr = (scolour >> 8) & 0xff;
480 sg = (scolour >> 16) & 0xff;
481 sb = (scolour >> 24) & 0xff;
482
483 pr = alphaf * pr + ialphaf * sr;
484 pg = alphaf * pg + ialphaf * sg;
485 pb = alphaf * pb + ialphaf * sb;
486 }
487
488 *sbyte = (spix ?
489 (map[(pr >> 4) | (pg & 0xf0) | ((pb << 4) & 0xf00)] << 4) | (*sbyte & 0xf) :
490 map[(pr >> 4) | (pg & 0xf0) | ((pb << 4) & 0xf00)] | (*sbyte & 0xf0));
491
492 spix = 1 - spix;
493 if (spix == 0) sbyte++;
494 }
495 }
496
497 free(palette);
498
499 return 0;
500 }
501
502 /********************************************************************************
503 * read screen palette
504 */
505
506 os_palette *read_palette()
507 {
508 unsigned int size;
509 os_palette *palette;
510 os_error const *error;
511
512 error = xcolourtrans_read_palette((osspriteop_area const *) -1, (osspriteop_id) -1,
513 (os_palette *) 0, 0, 0, &size);
514 if (error) return 0;
515
516 palette = malloc(size);
517 if (!palette) return 0;
518
519 error = xcolourtrans_read_palette((osspriteop_area const *) -1, (osspriteop_id) -1,
520 palette, size, 0, NULL);
521 if (error) return 0;
522
523 return palette;
524 }
525
526 /********************************************************************************/

  ViewVC Help
Powered by ViewVC 1.1.26