Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4680 right-hear 1
#include "fitz.h"
2
#include "muxps.h"
3
 
4
#include 
5
 
6
struct info
7
{
8
	int width, height, depth, n;
9
	int interlace, indexed;
10
	int size;
11
	unsigned char *samples;
12
	unsigned char palette[256*4];
13
	int transparency;
14
	int trns[3];
15
	int xres, yres;
16
};
17
 
18
static inline int getint(unsigned char *p)
19
{
20
	return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
21
}
22
 
23
static inline int getcomp(unsigned char *line, int x, int bpc)
24
{
25
	switch (bpc)
26
	{
27
	case 1: return (line[x >> 3] >> ( 7 - (x & 7) ) ) & 1;
28
	case 2: return (line[x >> 2] >> ( ( 3 - (x & 3) ) << 1 ) ) & 3;
29
	case 4: return (line[x >> 1] >> ( ( 1 - (x & 1) ) << 2 ) ) & 15;
30
	case 8: return line[x];
31
	case 16: return line[x << 1] << 8 | line[(x << 1) + 1];
32
	}
33
	return 0;
34
}
35
 
36
static inline void putcomp(unsigned char *line, int x, int bpc, int value)
37
{
38
	int maxval = (1 << bpc) - 1;
39
 
40
	switch (bpc)
41
	{
42
	case 1: line[x >> 3] &= ~(maxval << (7 - (x & 7))); break;
43
	case 2: line[x >> 2] &= ~(maxval << ((3 - (x & 3)) << 1)); break;
44
	case 4: line[x >> 1] &= ~(maxval << ((1 - (x & 1)) << 2)); break;
45
	}
46
 
47
	switch (bpc)
48
	{
49
	case 1: line[x >> 3] |= value << (7 - (x & 7)); break;
50
	case 2: line[x >> 2] |= value << ((3 - (x & 3)) << 1); break;
51
	case 4: line[x >> 1] |= value << ((1 - (x & 1)) << 2); break;
52
	case 8: line[x] = value; break;
53
	case 16: line[x << 1] = value >> 8; line[(x << 1) + 1] = value & 0xFF; break;
54
	}
55
}
56
 
57
static const unsigned char png_signature[8] =
58
{
59
	137, 80, 78, 71, 13, 10, 26, 10
60
};
61
 
62
static void *zalloc(void *opaque, unsigned int items, unsigned int size)
63
{
64
	return fz_calloc(items, size);
65
}
66
 
67
static void zfree(void *opaque, void *address)
68
{
69
	fz_free(address);
70
}
71
 
72
static inline int paeth(int a, int b, int c)
73
{
74
	/* The definitions of ac and bc are correct, not a typo. */
75
	int ac = b - c, bc = a - c, abcc = ac + bc;
76
	int pa = (ac < 0 ? -ac : ac);
77
	int pb = (bc < 0 ? -bc : bc);
78
	int pc = (abcc < 0 ? -abcc : abcc);
79
	return pa <= pb && pa <= pc ? a : pb <= pc ? b : c;
80
}
81
 
82
static void
83
png_predict(unsigned char *samples, int width, int height, int n, int depth)
84
{
85
	int stride = (width * n * depth + 7) / 8;
86
	int bpp = (n * depth + 7) / 8;
87
	int i, row;
88
 
89
	for (row = 0; row < height; row ++)
90
	{
91
		unsigned char *src = samples + (stride + 1) * row;
92
		unsigned char *dst = samples + stride * row;
93
 
94
		unsigned char *a = dst;
95
		unsigned char *b = dst - stride;
96
		unsigned char *c = dst - stride;
97
 
98
		switch (*src++)
99
		{
100
		default:
101
		case 0: /* None */
102
			for (i = 0; i < stride; i++)
103
				*dst++ = *src++;
104
			break;
105
 
106
		case 1: /* Sub */
107
			for (i = 0; i < bpp; i++)
108
				*dst++ = *src++;
109
			for (i = bpp; i < stride; i++)
110
				*dst++ = *src++ + *a++;
111
			break;
112
 
113
		case 2: /* Up */
114
			if (row == 0)
115
				for (i = 0; i < stride; i++)
116
					*dst++ = *src++;
117
			else
118
				for (i = 0; i < stride; i++)
119
					*dst++ = *src++ + *b++;
120
			break;
121
 
122
		case 3: /* Average */
123
			if (row == 0)
124
			{
125
				for (i = 0; i < bpp; i++)
126
					*dst++ = *src++;
127
				for (i = bpp; i < stride; i++)
128
					*dst++ = *src++ + (*a++ >> 1);
129
			}
130
			else
131
			{
132
				for (i = 0; i < bpp; i++)
133
					*dst++ = *src++ + (*b++ >> 1);
134
				for (i = bpp; i < stride; i++)
135
					*dst++ = *src++ + ((*b++ + *a++) >> 1);
136
			}
137
			break;
138
 
139
		case 4: /* Paeth */
140
			if (row == 0)
141
			{
142
				for (i = 0; i < bpp; i++)
143
					*dst++ = *src++ + paeth(0, 0, 0);
144
				for (i = bpp; i < stride; i++)
145
					*dst++ = *src++ + paeth(*a++, 0, 0);
146
			}
147
			else
148
			{
149
				for (i = 0; i < bpp; i++)
150
					*dst++ = *src++ + paeth(0, *b++, 0);
151
				for (i = bpp; i < stride; i++)
152
					*dst++ = *src++ + paeth(*a++, *b++, *c++);
153
			}
154
			break;
155
		}
156
	}
157
}
158
 
159
static const int adam7_ix[7] = { 0, 4, 0, 2, 0, 1, 0 };
160
static const int adam7_dx[7] = { 8, 8, 4, 4, 2, 2, 1 };
161
static const int adam7_iy[7] = { 0, 0, 4, 0, 2, 0, 1 };
162
static const int adam7_dy[7] = { 8, 8, 8, 4, 4, 2, 2 };
163
 
164
static void
165
png_deinterlace_passes(struct info *info, int *w, int *h, int *ofs)
166
{
167
	int p, bpp = info->depth * info->n;
168
	ofs[0] = 0;
169
	for (p = 0; p < 7; p++)
170
	{
171
		w[p] = (info->width + adam7_dx[p] - adam7_ix[p] - 1) / adam7_dx[p];
172
		h[p] = (info->height + adam7_dy[p] - adam7_iy[p] - 1) / adam7_dy[p];
173
		if (w[p] == 0) h[p] = 0;
174
		if (h[p] == 0) w[p] = 0;
175
		if (w[p] && h[p])
176
			ofs[p + 1] = ofs[p] + h[p] * (1 + (w[p] * bpp + 7) / 8);
177
		else
178
			ofs[p + 1] = ofs[p];
179
	}
180
}
181
 
182
static void
183
png_deinterlace(struct info *info, int *passw, int *passh, int *passofs)
184
{
185
	int n = info->n;
186
	int depth = info->depth;
187
	int stride = (info->width * n * depth + 7) / 8;
188
	unsigned char *output;
189
	int p, x, y, k;
190
 
191
	output = fz_calloc(info->height, stride);
192
 
193
	for (p = 0; p < 7; p++)
194
	{
195
		unsigned char *sp = info->samples + passofs[p];
196
		int w = passw[p];
197
		int h = passh[p];
198
 
199
		png_predict(sp, w, h, n, depth);
200
		for (y = 0; y < h; y++)
201
		{
202
			for (x = 0; x < w; x++)
203
			{
204
				int outx = x * adam7_dx[p] + adam7_ix[p];
205
				int outy = y * adam7_dy[p] + adam7_iy[p];
206
				unsigned char *dp = output + outy * stride;
207
				for (k = 0; k < n; k++)
208
				{
209
					int v = getcomp(sp, x * n + k, depth);
210
					putcomp(dp, outx * n + k, depth, v);
211
				}
212
			}
213
			sp += (w * depth * n + 7) / 8;
214
		}
215
	}
216
 
217
	fz_free(info->samples);
218
	info->samples = output;
219
}
220
 
221
static int
222
png_read_ihdr(struct info *info, unsigned char *p, int size)
223
{
224
	int color, compression, filter;
225
 
226
	if (size != 13)
227
		return fz_throw("IHDR chunk is the wrong size");
228
 
229
	info->width = getint(p + 0);
230
	info->height = getint(p + 4);
231
	info->depth = p[8];
232
 
233
	color = p[9];
234
	compression = p[10];
235
	filter = p[11];
236
	info->interlace = p[12];
237
 
238
	if (info->width <= 0)
239
		return fz_throw("image width must be > 0");
240
	if (info->height <= 0)
241
		return fz_throw("image height must be > 0");
242
 
243
	if (info->depth != 1 && info->depth != 2 && info->depth != 4 &&
244
			info->depth != 8 && info->depth != 16)
245
		return fz_throw("image bit depth must be one of 1, 2, 4, 8, 16");
246
	if (color == 2 && info->depth < 8)
247
		return fz_throw("illegal bit depth for truecolor");
248
	if (color == 3 && info->depth > 8)
249
		return fz_throw("illegal bit depth for indexed");
250
	if (color == 4 && info->depth < 8)
251
		return fz_throw("illegal bit depth for grayscale with alpha");
252
	if (color == 6 && info->depth < 8)
253
		return fz_throw("illegal bit depth for truecolor with alpha");
254
 
255
	info->indexed = 0;
256
	if (color == 0) /* gray */
257
		info->n = 1;
258
	else if (color == 2) /* rgb */
259
		info->n = 3;
260
	else if (color == 4) /* gray alpha */
261
		info->n = 2;
262
	else if (color == 6) /* rgb alpha */
263
		info->n = 4;
264
	else if (color == 3) /* indexed */
265
	{
266
		info->indexed = 1;
267
		info->n = 1;
268
	}
269
	else
270
		return fz_throw("unknown color type");
271
 
272
	if (compression != 0)
273
		return fz_throw("unknown compression method");
274
	if (filter != 0)
275
		return fz_throw("unknown filter method");
276
	if (info->interlace != 0 && info->interlace != 1)
277
		return fz_throw("interlace method not supported");
278
 
279
	return fz_okay;
280
}
281
 
282
static int
283
png_read_plte(struct info *info, unsigned char *p, int size)
284
{
285
	int n = size / 3;
286
	int i;
287
 
288
	if (n > 256 || n > (1 << info->depth))
289
		return fz_throw("too many samples in palette");
290
 
291
	for (i = 0; i < n; i++)
292
	{
293
		info->palette[i * 4] = p[i * 3];
294
		info->palette[i * 4 + 1] = p[i * 3 + 1];
295
		info->palette[i * 4 + 2] = p[i * 3 + 2];
296
	}
297
 
298
	return fz_okay;
299
}
300
 
301
static int
302
png_read_trns(struct info *info, unsigned char *p, int size)
303
{
304
	int i;
305
 
306
	info->transparency = 1;
307
 
308
	if (info->indexed)
309
	{
310
		if (size > 256 || size > (1 << info->depth))
311
			return fz_throw("too many samples in transparency table");
312
		for (i = 0; i < size; i++)
313
			info->palette[i * 4 + 3] = p[i];
314
	}
315
	else
316
	{
317
		if (size != info->n * 2)
318
			return fz_throw("tRNS chunk is the wrong size");
319
		for (i = 0; i < info->n; i++)
320
			info->trns[i] = (p[i * 2] << 8 | p[i * 2 + 1]) & ((1 << info->depth) - 1);
321
	}
322
 
323
	return fz_okay;
324
}
325
 
326
static int
327
png_read_idat(struct info *info, unsigned char *p, int size, z_stream *stm)
328
{
329
	int code;
330
 
331
	stm->next_in = p;
332
	stm->avail_in = size;
333
 
334
	code = inflate(stm, Z_SYNC_FLUSH);
335
	if (code != Z_OK && code != Z_STREAM_END)
336
		return fz_throw("zlib error: %s", stm->msg);
337
	if (stm->avail_in != 0)
338
	{
339
		if (stm->avail_out == 0)
340
			return fz_throw("ran out of output before input");
341
		return fz_throw("inflate did not consume buffer (%d remaining)", stm->avail_in);
342
	}
343
 
344
	return fz_okay;
345
}
346
 
347
static int
348
png_read_phys(struct info *info, unsigned char *p, int size)
349
{
350
	if (size != 9)
351
		return fz_throw("pHYs chunk is the wrong size");
352
	if (p[8] == 1)
353
	{
354
		info->xres = getint(p) * 254 / 10000;
355
		info->yres = getint(p + 4) * 254 / 10000;
356
	}
357
	return fz_okay;
358
}
359
 
360
static int
361
png_read_image(struct info *info, unsigned char *p, int total)
362
{
363
	int passw[7], passh[7], passofs[8];
364
	int code, size;
365
	z_stream stm;
366
 
367
	memset(info, 0, sizeof (struct info));
368
	memset(info->palette, 255, sizeof(info->palette));
369
	info->xres = 96;
370
	info->yres = 96;
371
 
372
	/* Read signature */
373
 
374
	if (total < 8 + 12 || memcmp(p, png_signature, 8))
375
		return fz_throw("not a png image (wrong signature)");
376
 
377
	p += 8;
378
	total -= 8;
379
 
380
	/* Read IHDR chunk (must come first) */
381
 
382
	size = getint(p);
383
 
384
	if (size + 12 > total)
385
		return fz_throw("premature end of data in png image");
386
 
387
	if (!memcmp(p + 4, "IHDR", 4))
388
	{
389
		code = png_read_ihdr(info, p + 8, size);
390
		if (code)
391
			return fz_rethrow(code, "cannot read png header");
392
	}
393
	else
394
		return fz_throw("png file must start with IHDR chunk");
395
 
396
	p += size + 12;
397
	total -= size + 12;
398
 
399
	/* Prepare output buffer */
400
 
401
	if (!info->interlace)
402
	{
403
		info->size = info->height * (1 + (info->width * info->n * info->depth + 7) / 8);
404
	}
405
	else
406
	{
407
		png_deinterlace_passes(info, passw, passh, passofs);
408
		info->size = passofs[7];
409
	}
410
 
411
	info->samples = fz_malloc(info->size);
412
 
413
	stm.zalloc = zalloc;
414
	stm.zfree = zfree;
415
	stm.opaque = NULL;
416
 
417
	stm.next_out = info->samples;
418
	stm.avail_out = info->size;
419
 
420
	code = inflateInit(&stm);
421
	if (code != Z_OK)
422
		return fz_throw("zlib error: %s", stm.msg);
423
 
424
	/* Read remaining chunks until IEND */
425
 
426
	while (total > 8)
427
	{
428
		size = getint(p);
429
 
430
		if (size + 12 > total)
431
			return fz_throw("premature end of data in png image");
432
 
433
		if (!memcmp(p + 4, "PLTE", 4))
434
		{
435
			code = png_read_plte(info, p + 8, size);
436
			if (code)
437
				return fz_rethrow(code, "cannot read png palette");
438
		}
439
 
440
		if (!memcmp(p + 4, "tRNS", 4))
441
		{
442
			code = png_read_trns(info, p + 8, size);
443
			if (code)
444
				return fz_rethrow(code, "cannot read png transparency");
445
		}
446
 
447
		if (!memcmp(p + 4, "pHYs", 4))
448
		{
449
			code = png_read_phys(info, p + 8, size);
450
			if (code)
451
				return fz_rethrow(code, "cannot read png resolution");
452
		}
453
 
454
		if (!memcmp(p + 4, "IDAT", 4))
455
		{
456
			code = png_read_idat(info, p + 8, size, &stm);
457
			if (code)
458
				return fz_rethrow(code, "cannot read png image data");
459
		}
460
 
461
		if (!memcmp(p + 4, "IEND", 4))
462
			break;
463
 
464
		p += size + 12;
465
		total -= size + 12;
466
	}
467
 
468
	code = inflateEnd(&stm);
469
	if (code != Z_OK)
470
		return fz_throw("zlib error: %s", stm.msg);
471
 
472
	/* Apply prediction filter and deinterlacing */
473
 
474
	if (!info->interlace)
475
		png_predict(info->samples, info->width, info->height, info->n, info->depth);
476
	else
477
		png_deinterlace(info, passw, passh, passofs);
478
 
479
	return fz_okay;
480
}
481
 
482
static fz_pixmap *
483
png_expand_palette(struct info *info, fz_pixmap *src)
484
{
485
	fz_pixmap *dst = fz_new_pixmap(fz_device_rgb, src->w, src->h);
486
	unsigned char *sp = src->samples;
487
	unsigned char *dp = dst->samples;
488
	int x, y;
489
 
490
	dst->xres = src->xres;
491
	dst->yres = src->yres;
492
 
493
	for (y = 0; y < info->height; y++)
494
	{
495
		for (x = 0; x < info->width; x++)
496
		{
497
			int v = *sp << 2;
498
			*dp++ = info->palette[v];
499
			*dp++ = info->palette[v + 1];
500
			*dp++ = info->palette[v + 2];
501
			*dp++ = info->palette[v + 3];
502
			sp += 2;
503
		}
504
	}
505
 
506
	fz_drop_pixmap(src);
507
	return dst;
508
}
509
 
510
static void
511
png_mask_transparency(struct info *info, fz_pixmap *dst)
512
{
513
	int stride = (info->width * info->n * info->depth + 7) / 8;
514
	int depth = info->depth;
515
	int n = info->n;
516
	int x, y, k, t;
517
 
518
	for (y = 0; y < info->height; y++)
519
	{
520
		unsigned char *sp = info->samples + y * stride;
521
		unsigned char *dp = dst->samples + y * dst->w * dst->n;
522
		for (x = 0; x < info->width; x++)
523
		{
524
			t = 1;
525
			for (k = 0; k < n; k++)
526
				if (getcomp(sp, x * n + k, depth) != info->trns[k])
527
					t = 0;
528
			if (t)
529
				dp[x * dst->n + dst->n - 1] = 0;
530
		}
531
	}
532
}
533
 
534
int
535
xps_decode_png(fz_pixmap **imagep, byte *p, int total)
536
{
537
	fz_pixmap *image;
538
	fz_colorspace *colorspace;
539
	struct info png;
540
	int code;
541
	int stride;
542
 
543
	code = png_read_image(&png, p, total);
544
	if (code)
545
		return fz_rethrow(code, "cannot read png image");
546
 
547
	if (png.n == 3 || png.n == 4)
548
		colorspace = fz_device_rgb;
549
	else
550
		colorspace = fz_device_gray;
551
 
552
	stride = (png.width * png.n * png.depth + 7) / 8;
553
 
554
	image = fz_new_pixmap_with_limit(colorspace, png.width, png.height);
555
	if (!image)
556
	{
557
		fz_free(png.samples);
558
		return fz_throw("out of memory");
559
	}
560
 
561
	image->xres = png.xres;
562
	image->yres = png.yres;
563
 
564
	fz_unpack_tile(image, png.samples, png.n, png.depth, stride, png.indexed);
565
 
566
	if (png.indexed)
567
		image = png_expand_palette(&png, image);
568
	else if (png.transparency)
569
		png_mask_transparency(&png, image);
570
 
571
	if (png.transparency || png.n == 2 || png.n == 4)
572
		fz_premultiply_pixmap(image);
573
 
574
	fz_free(png.samples);
575
 
576
	*imagep = image;
577
	return fz_okay;
578
}