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
 
3
static int fz_memory_limit = 256 << 20;
4
static int fz_memory_used = 0;
5
 
6
fz_pixmap *
7
fz_new_pixmap_with_data(fz_colorspace *colorspace, int w, int h, unsigned char *samples)
8
{
9
	fz_pixmap *pix;
10
 
11
	pix = fz_malloc(sizeof(fz_pixmap));
12
	pix->refs = 1;
13
	pix->x = 0;
14
	pix->y = 0;
15
	pix->w = w;
16
	pix->h = h;
17
	pix->mask = NULL;
18
	pix->interpolate = 1;
19
	pix->xres = 96;
20
	pix->yres = 96;
21
	pix->colorspace = NULL;
22
	pix->n = 1;
23
 
24
	if (colorspace)
25
	{
26
		pix->colorspace = fz_keep_colorspace(colorspace);
27
		pix->n = 1 + colorspace->n;
28
	}
29
 
30
	if (samples)
31
	{
32
		pix->samples = samples;
33
		pix->free_samples = 0;
34
	}
35
	else
36
	{
37
		fz_memory_used += pix->w * pix->h * pix->n;
38
		pix->samples = fz_calloc(pix->h, pix->w * pix->n);
39
		pix->free_samples = 1;
40
	}
41
 
42
	return pix;
43
}
44
 
45
fz_pixmap *
46
fz_new_pixmap_with_limit(fz_colorspace *colorspace, int w, int h)
47
{
48
	int n = colorspace ? colorspace->n + 1 : 1;
49
	int size = w * h * n;
50
	if (fz_memory_used + size > fz_memory_limit)
51
	{
52
		fz_warn("pixmap memory exceeds soft limit %dM + %dM > %dM",
53
			fz_memory_used/(1<<20), size/(1<<20), fz_memory_limit/(1<<20));
54
		return NULL;
55
	}
56
	return fz_new_pixmap_with_data(colorspace, w, h, NULL);
57
}
58
 
59
fz_pixmap *
60
fz_new_pixmap(fz_colorspace *colorspace, int w, int h)
61
{
62
	return fz_new_pixmap_with_data(colorspace, w, h, NULL);
63
}
64
 
65
fz_pixmap *
66
fz_new_pixmap_with_rect(fz_colorspace *colorspace, fz_bbox r)
67
{
68
	fz_pixmap *pixmap;
69
	pixmap = fz_new_pixmap(colorspace, r.x1 - r.x0, r.y1 - r.y0);
70
	pixmap->x = r.x0;
71
	pixmap->y = r.y0;
72
	return pixmap;
73
}
74
 
75
fz_pixmap *
76
fz_new_pixmap_with_rect_and_data(fz_colorspace *colorspace, fz_bbox r, unsigned char *samples)
77
{
78
	fz_pixmap *pixmap;
79
	pixmap = fz_new_pixmap_with_data(colorspace, r.x1 - r.x0, r.y1 - r.y0, samples);
80
	pixmap->x = r.x0;
81
	pixmap->y = r.y0;
82
	return pixmap;
83
}
84
 
85
fz_pixmap *
86
fz_keep_pixmap(fz_pixmap *pix)
87
{
88
	pix->refs++;
89
	return pix;
90
}
91
 
92
void
93
fz_drop_pixmap(fz_pixmap *pix)
94
{
95
	if (pix && --pix->refs == 0)
96
	{
97
		fz_memory_used -= pix->w * pix->h * pix->n;
98
		if (pix->mask)
99
			fz_drop_pixmap(pix->mask);
100
		if (pix->colorspace)
101
			fz_drop_colorspace(pix->colorspace);
102
		if (pix->free_samples)
103
			fz_free(pix->samples);
104
		fz_free(pix);
105
	}
106
}
107
 
108
fz_bbox
109
fz_bound_pixmap(fz_pixmap *pix)
110
{
111
	fz_bbox bbox;
112
	bbox.x0 = pix->x;
113
	bbox.y0 = pix->y;
114
	bbox.x1 = pix->x + pix->w;
115
	bbox.y1 = pix->y + pix->h;
116
	return bbox;
117
}
118
 
119
void
120
fz_clear_pixmap(fz_pixmap *pix)
121
{
122
	memset(pix->samples, 0, pix->w * pix->h * pix->n);
123
}
124
 
125
void
126
fz_clear_pixmap_with_color(fz_pixmap *pix, int value)
127
{
128
	if (value == 255)
129
		memset(pix->samples, 255, pix->w * pix->h * pix->n);
130
	else
131
	{
132
		int k, x, y;
133
		unsigned char *s = pix->samples;
134
		for (y = 0; y < pix->h; y++)
135
		{
136
			for (x = 0; x < pix->w; x++)
137
			{
138
				for (k = 0; k < pix->n - 1; k++)
139
					*s++ = value;
140
				*s++ = 255;
141
			}
142
		}
143
	}
144
}
145
 
146
void
147
fz_copy_pixmap_rect(fz_pixmap *dest, fz_pixmap *src, fz_bbox r)
148
{
149
	const unsigned char *srcp;
150
	unsigned char *destp;
151
	int y, w, destspan, srcspan;
152
 
153
	r = fz_intersect_bbox(r, fz_bound_pixmap(dest));
154
	r = fz_intersect_bbox(r, fz_bound_pixmap(src));
155
	w = r.x1 - r.x0;
156
	y = r.y1 - r.y0;
157
	if (w <= 0 || y <= 0)
158
		return;
159
 
160
	w *= src->n;
161
	srcspan = src->w * src->n;
162
	srcp = src->samples + srcspan * (r.y0 - src->y) + src->n * (r.x0 - src->x);
163
	destspan = dest->w * dest->n;
164
	destp = dest->samples + destspan * (r.y0 - dest->y) + dest->n * (r.x0 - dest->x);
165
	do
166
	{
167
		memcpy(destp, srcp, w);
168
		srcp += srcspan;
169
		destp += destspan;
170
	}
171
	while (--y);
172
}
173
 
174
void
175
fz_clear_pixmap_rect_with_color(fz_pixmap *dest, int value, fz_bbox r)
176
{
177
	unsigned char *destp;
178
	int x, y, w, k, destspan;
179
 
180
	r = fz_intersect_bbox(r, fz_bound_pixmap(dest));
181
	w = r.x1 - r.x0;
182
	y = r.y1 - r.y0;
183
	if (w <= 0 || y <= 0)
184
		return;
185
 
186
	destspan = dest->w * dest->n;
187
	destp = dest->samples + destspan * (r.y0 - dest->y) + dest->n * (r.x0 - dest->x);
188
	if (value == 255)
189
		do
190
		{
191
			memset(destp, 255, w * dest->n);
192
			destp += destspan;
193
		}
194
		while (--y);
195
	else
196
		do
197
		{
198
			unsigned char *s = destp;
199
			for (x = 0; x < w; x++)
200
			{
201
				for (k = 0; k < dest->n - 1; k++)
202
					*s++ = value;
203
				*s++ = 255;
204
			}
205
			destp += destspan;
206
		}
207
		while (--y);
208
}
209
 
210
void
211
fz_premultiply_pixmap(fz_pixmap *pix)
212
{
213
	unsigned char *s = pix->samples;
214
	unsigned char a;
215
	int k, x, y;
216
 
217
	for (y = 0; y < pix->h; y++)
218
	{
219
		for (x = 0; x < pix->w; x++)
220
		{
221
			a = s[pix->n - 1];
222
			for (k = 0; k < pix->n - 1; k++)
223
				s[k] = fz_mul255(s[k], a);
224
			s += pix->n;
225
		}
226
	}
227
}
228
 
229
fz_pixmap *
230
fz_alpha_from_gray(fz_pixmap *gray, int luminosity)
231
{
232
	fz_pixmap *alpha;
233
	unsigned char *sp, *dp;
234
	int len;
235
 
236
	assert(gray->n == 2);
237
 
238
	alpha = fz_new_pixmap_with_rect(NULL, fz_bound_pixmap(gray));
239
	dp = alpha->samples;
240
	sp = gray->samples;
241
	if (!luminosity)
242
		sp ++;
243
 
244
	len = gray->w * gray->h;
245
	while (len--)
246
	{
247
		*dp++ = sp[0];
248
		sp += 2;
249
	}
250
 
251
	return alpha;
252
}
253
 
254
void
255
fz_invert_pixmap(fz_pixmap *pix)
256
{
257
	unsigned char *s = pix->samples;
258
	int k, x, y;
259
 
260
	for (y = 0; y < pix->h; y++)
261
	{
262
		for (x = 0; x < pix->w; x++)
263
		{
264
			for (k = 0; k < pix->n - 1; k++)
265
				s[k] = 255 - s[k];
266
			s += pix->n;
267
		}
268
	}
269
}
270
 
271
void
272
fz_gamma_pixmap(fz_pixmap *pix, float gamma)
273
{
274
	unsigned char gamma_map[256];
275
	unsigned char *s = pix->samples;
276
	int k, x, y;
277
 
278
	for (k = 0; k < 256; k++)
279
		gamma_map[k] = pow(k / 255.0f, gamma) * 255;
280
 
281
	for (y = 0; y < pix->h; y++)
282
	{
283
		for (x = 0; x < pix->w; x++)
284
		{
285
			for (k = 0; k < pix->n - 1; k++)
286
				s[k] = gamma_map[s[k]];
287
			s += pix->n;
288
		}
289
	}
290
}
291
 
292
/*
293
 * Write pixmap to PNM file (without alpha channel)
294
 */
295
 
296
fz_error
297
fz_write_pnm(fz_pixmap *pixmap, char *filename)
298
{
299
	FILE *fp;
300
	unsigned char *p;
301
	int len;
302
 
303
	if (pixmap->n != 1 && pixmap->n != 2 && pixmap->n != 4)
304
		return fz_throw("pixmap must be grayscale or rgb to write as pnm");
305
 
306
	fp = fopen(filename, "wb");
307
	if (!fp)
308
		return fz_throw("cannot open file '%s': %s", filename, strerror(errno));
309
 
310
	if (pixmap->n == 1 || pixmap->n == 2)
311
		fprintf(fp, "P5\n");
312
	if (pixmap->n == 4)
313
		fprintf(fp, "P6\n");
314
	fprintf(fp, "%d %d\n", pixmap->w, pixmap->h);
315
	fprintf(fp, "255\n");
316
 
317
	len = pixmap->w * pixmap->h;
318
	p = pixmap->samples;
319
 
320
	switch (pixmap->n)
321
	{
322
	case 1:
323
		fwrite(p, 1, len, fp);
324
		break;
325
	case 2:
326
		while (len--)
327
		{
328
			putc(p[0], fp);
329
			p += 2;
330
		}
331
		break;
332
	case 4:
333
		while (len--)
334
		{
335
			putc(p[0], fp);
336
			putc(p[1], fp);
337
			putc(p[2], fp);
338
			p += 4;
339
		}
340
	}
341
 
342
	fclose(fp);
343
	return fz_okay;
344
}
345
 
346
/*
347
 * Write pixmap to PAM file (with or without alpha channel)
348
 */
349
 
350
fz_error
351
fz_write_pam(fz_pixmap *pixmap, char *filename, int savealpha)
352
{
353
	unsigned char *sp;
354
	int y, w, k;
355
	FILE *fp;
356
 
357
	int sn = pixmap->n;
358
	int dn = pixmap->n;
359
	if (!savealpha && dn > 1)
360
		dn--;
361
 
362
	fp = fopen(filename, "wb");
363
	if (!fp)
364
		return fz_throw("cannot open file '%s': %s", filename, strerror(errno));
365
 
366
	fprintf(fp, "P7\n");
367
	fprintf(fp, "WIDTH %d\n", pixmap->w);
368
	fprintf(fp, "HEIGHT %d\n", pixmap->h);
369
	fprintf(fp, "DEPTH %d\n", dn);
370
	fprintf(fp, "MAXVAL 255\n");
371
	if (pixmap->colorspace)
372
		fprintf(fp, "# COLORSPACE %s\n", pixmap->colorspace->name);
373
	switch (dn)
374
	{
375
	case 1: fprintf(fp, "TUPLTYPE GRAYSCALE\n"); break;
376
	case 2: if (sn == 2) fprintf(fp, "TUPLTYPE GRAYSCALE_ALPHA\n"); break;
377
	case 3: if (sn == 4) fprintf(fp, "TUPLTYPE RGB\n"); break;
378
	case 4: if (sn == 4) fprintf(fp, "TUPLTYPE RGB_ALPHA\n"); break;
379
	}
380
	fprintf(fp, "ENDHDR\n");
381
 
382
	sp = pixmap->samples;
383
	for (y = 0; y < pixmap->h; y++)
384
	{
385
		w = pixmap->w;
386
		while (w--)
387
		{
388
			for (k = 0; k < dn; k++)
389
				putc(sp[k], fp);
390
			sp += sn;
391
		}
392
	}
393
 
394
	fclose(fp);
395
 
396
	return fz_okay;
397
}
398
 
399
/*
400
 * Write pixmap to PNG file (with or without alpha channel)
401
 */
402
 
403
#include 
404
 
405
static inline void big32(unsigned char *buf, unsigned int v)
406
{
407
	buf[0] = (v >> 24) & 0xff;
408
	buf[1] = (v >> 16) & 0xff;
409
	buf[2] = (v >> 8) & 0xff;
410
	buf[3] = (v) & 0xff;
411
}
412
 
413
static inline void put32(unsigned int v, FILE *fp)
414
{
415
	putc(v >> 24, fp);
416
	putc(v >> 16, fp);
417
	putc(v >> 8, fp);
418
	putc(v, fp);
419
}
420
 
421
static void putchunk(char *tag, unsigned char *data, int size, FILE *fp)
422
{
423
	unsigned int sum;
424
	put32(size, fp);
425
	fwrite(tag, 1, 4, fp);
426
	fwrite(data, 1, size, fp);
427
	sum = crc32(0, NULL, 0);
428
	sum = crc32(sum, (unsigned char*)tag, 4);
429
	sum = crc32(sum, data, size);
430
	put32(sum, fp);
431
}
432
 
433
fz_error
434
fz_write_png(fz_pixmap *pixmap, char *filename, int savealpha)
435
{
436
	static const unsigned char pngsig[8] = { 137, 80, 78, 71, 13, 10, 26, 10 };
437
	FILE *fp;
438
	unsigned char head[13];
439
	unsigned char *udata, *cdata, *sp, *dp;
440
	uLong usize, csize;
441
	int y, x, k, sn, dn;
442
	int color;
443
	int err;
444
 
445
	if (pixmap->n != 1 && pixmap->n != 2 && pixmap->n != 4)
446
		return fz_throw("pixmap must be grayscale or rgb to write as png");
447
 
448
	sn = pixmap->n;
449
	dn = pixmap->n;
450
	if (!savealpha && dn > 1)
451
		dn--;
452
 
453
	switch (dn)
454
	{
455
	default:
456
	case 1: color = 0; break;
457
	case 2: color = 4; break;
458
	case 3: color = 2; break;
459
	case 4: color = 6; break;
460
	}
461
 
462
	usize = (pixmap->w * dn + 1) * pixmap->h;
463
	csize = compressBound(usize);
464
	udata = fz_malloc(usize);
465
	cdata = fz_malloc(csize);
466
 
467
	sp = pixmap->samples;
468
	dp = udata;
469
	for (y = 0; y < pixmap->h; y++)
470
	{
471
		*dp++ = 1; /* sub prediction filter */
472
		for (x = 0; x < pixmap->w; x++)
473
		{
474
			for (k = 0; k < dn; k++)
475
			{
476
				if (x == 0)
477
					dp[k] = sp[k];
478
				else
479
					dp[k] = sp[k] - sp[k-sn];
480
			}
481
			sp += sn;
482
			dp += dn;
483
		}
484
	}
485
 
486
	err = compress(cdata, &csize, udata, usize);
487
	if (err != Z_OK)
488
	{
489
		fz_free(udata);
490
		fz_free(cdata);
491
		return fz_throw("cannot compress image data");
492
	}
493
 
494
	fp = fopen(filename, "wb");
495
	if (!fp)
496
	{
497
		fz_free(udata);
498
		fz_free(cdata);
499
		return fz_throw("cannot open file '%s': %s", filename, strerror(errno));
500
	}
501
 
502
	big32(head+0, pixmap->w);
503
	big32(head+4, pixmap->h);
504
	head[8] = 8; /* depth */
505
	head[9] = color;
506
	head[10] = 0; /* compression */
507
	head[11] = 0; /* filter */
508
	head[12] = 0; /* interlace */
509
 
510
	fwrite(pngsig, 1, 8, fp);
511
	putchunk("IHDR", head, 13, fp);
512
	putchunk("IDAT", cdata, csize, fp);
513
	putchunk("IEND", head, 0, fp);
514
	fclose(fp);
515
 
516
	fz_free(udata);
517
	fz_free(cdata);
518
	return fz_okay;
519
}