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
/*
2
 * Information tool.
3
 * Print information about the input pdf.
4
 */
5
 
6
#include "fitz.h"
7
#include "mupdf.h"
8
 
9
pdf_xref *xref;
10
int pagecount;
11
 
12
void closexref(void);
13
 
14
void die(fz_error error)
15
{
16
	fz_catch(error, "aborting");
17
	closexref();
18
	exit(1);
19
}
20
 
21
void openxref(char *filename, char *password, int dieonbadpass, int loadpages);
22
 
23
enum
24
{
25
	DIMENSIONS = 0x01,
26
	FONTS = 0x02,
27
	IMAGES = 0x04,
28
	SHADINGS = 0x08,
29
	PATTERNS = 0x10,
30
	XOBJS = 0x20,
31
	ALL = DIMENSIONS | FONTS | IMAGES | SHADINGS | PATTERNS | XOBJS
32
};
33
 
34
struct info
35
{
36
	int page;
37
	fz_obj *pageref;
38
	fz_obj *pageobj;
39
	union {
40
		struct {
41
			fz_obj *obj;
42
		} info;
43
		struct {
44
			fz_obj *obj;
45
		} crypt;
46
		struct {
47
			fz_obj *obj;
48
			fz_rect *bbox;
49
		} dim;
50
		struct {
51
			fz_obj *obj;
52
			fz_obj *subtype;
53
			fz_obj *name;
54
		} font;
55
		struct {
56
			fz_obj *obj;
57
			fz_obj *width;
58
			fz_obj *height;
59
			fz_obj *bpc;
60
			fz_obj *filter;
61
			fz_obj *cs;
62
			fz_obj *altcs;
63
		} image;
64
		struct {
65
			fz_obj *obj;
66
			fz_obj *type;
67
		} shading;
68
		struct {
69
			fz_obj *obj;
70
			fz_obj *type;
71
			fz_obj *paint;
72
			fz_obj *tiling;
73
			fz_obj *shading;
74
		} pattern;
75
		struct {
76
			fz_obj *obj;
77
			fz_obj *groupsubtype;
78
			fz_obj *reference;
79
		} form;
80
	} u;
81
};
82
 
83
static struct info *dim = NULL;
84
static int dims = 0;
85
static struct info *font = NULL;
86
static int fonts = 0;
87
static struct info *image = NULL;
88
static int images = 0;
89
static struct info *shading = NULL;
90
static int shadings = 0;
91
static struct info *pattern = NULL;
92
static int patterns = 0;
93
static struct info *form = NULL;
94
static int forms = 0;
95
static struct info *psobj = NULL;
96
static int psobjs = 0;
97
 
98
void closexref(void)
99
{
100
	int i;
101
	if (xref)
102
	{
103
		pdf_free_xref(xref);
104
		xref = NULL;
105
	}
106
 
107
	if (dim)
108
	{
109
		for (i = 0; i < dims; i++)
110
			fz_free(dim[i].u.dim.bbox);
111
		fz_free(dim);
112
		dim = NULL;
113
		dims = 0;
114
	}
115
 
116
	if (font)
117
	{
118
		fz_free(font);
119
		font = NULL;
120
		fonts = 0;
121
	}
122
 
123
	if (image)
124
	{
125
		fz_free(image);
126
		image = NULL;
127
		images = 0;
128
	}
129
 
130
	if (shading)
131
	{
132
		fz_free(shading);
133
		shading = NULL;
134
		shadings = 0;
135
	}
136
 
137
	if (pattern)
138
	{
139
		fz_free(pattern);
140
		pattern = NULL;
141
		patterns = 0;
142
	}
143
 
144
	if (form)
145
	{
146
		fz_free(form);
147
		form = NULL;
148
		forms = 0;
149
	}
150
 
151
	if (psobj)
152
	{
153
		fz_free(psobj);
154
		psobj = NULL;
155
		psobjs = 0;
156
	}
157
 
158
	if (xref && xref->store)
159
	{
160
		pdf_free_store(xref->store);
161
		xref->store = NULL;
162
	}
163
}
164
 
165
static void
166
infousage(void)
167
{
168
	fprintf(stderr,
169
		"usage: pdfinfo [options] [file.pdf ... ]\n"
170
		"\t-d -\tpassword for decryption\n"
171
		"\t-f\tlist fonts\n"
172
		"\t-i\tlist images\n"
173
		"\t-m\tlist dimensions\n"
174
		"\t-p\tlist patterns\n"
175
		"\t-s\tlist shadings\n"
176
		"\t-x\tlist form and postscript xobjects\n");
177
	exit(1);
178
}
179
 
180
static void
181
showglobalinfo(void)
182
{
183
	fz_obj *obj;
184
 
185
	printf("\nPDF-%d.%d\n", xref->version / 10, xref->version % 10);
186
 
187
	obj = fz_dict_gets(xref->trailer, "Info");
188
	if (obj)
189
	{
190
		printf("Info object (%d %d R):\n", fz_to_num(obj), fz_to_gen(obj));
191
		fz_debug_obj(fz_resolve_indirect(obj));
192
	}
193
 
194
	obj = fz_dict_gets(xref->trailer, "Encrypt");
195
	if (obj)
196
	{
197
		printf("\nEncryption object (%d %d R):\n", fz_to_num(obj), fz_to_gen(obj));
198
		fz_debug_obj(fz_resolve_indirect(obj));
199
	}
200
 
201
	printf("\nPages: %d\n\n", pagecount);
202
}
203
 
204
static void
205
gatherdimensions(int page, fz_obj *pageref, fz_obj *pageobj)
206
{
207
	fz_rect bbox;
208
	fz_obj *obj;
209
	int j;
210
 
211
	obj = fz_dict_gets(pageobj, "MediaBox");
212
	if (!fz_is_array(obj))
213
		return;
214
 
215
	bbox = pdf_to_rect(obj);
216
 
217
	for (j = 0; j < dims; j++)
218
		if (!memcmp(dim[j].u.dim.bbox, &bbox, sizeof (fz_rect)))
219
			break;
220
 
221
	if (j < dims)
222
		return;
223
 
224
	dims++;
225
 
226
	dim = fz_realloc(dim, dims, sizeof(struct info));
227
	dim[dims - 1].page = page;
228
	dim[dims - 1].pageref = pageref;
229
	dim[dims - 1].pageobj = pageobj;
230
	dim[dims - 1].u.dim.bbox = fz_malloc(sizeof(fz_rect));
231
	memcpy(dim[dims - 1].u.dim.bbox, &bbox, sizeof (fz_rect));
232
 
233
	return;
234
}
235
 
236
static void
237
gatherfonts(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict)
238
{
239
	int i;
240
 
241
	for (i = 0; i < fz_dict_len(dict); i++)
242
	{
243
		fz_obj *fontdict = NULL;
244
		fz_obj *subtype = NULL;
245
		fz_obj *basefont = NULL;
246
		fz_obj *name = NULL;
247
		int k;
248
 
249
		fontdict = fz_dict_get_val(dict, i);
250
		if (!fz_is_dict(fontdict))
251
		{
252
			fz_warn("not a font dict (%d %d R)", fz_to_num(fontdict), fz_to_gen(fontdict));
253
			continue;
254
		}
255
 
256
		subtype = fz_dict_gets(fontdict, "Subtype");
257
		basefont = fz_dict_gets(fontdict, "BaseFont");
258
		if (!basefont || fz_is_null(basefont))
259
			name = fz_dict_gets(fontdict, "Name");
260
 
261
		for (k = 0; k < fonts; k++)
262
			if (!fz_objcmp(font[k].u.font.obj, fontdict))
263
				break;
264
 
265
		if (k < fonts)
266
			continue;
267
 
268
		fonts++;
269
 
270
		font = fz_realloc(font, fonts, sizeof(struct info));
271
		font[fonts - 1].page = page;
272
		font[fonts - 1].pageref = pageref;
273
		font[fonts - 1].pageobj = pageobj;
274
		font[fonts - 1].u.font.obj = fontdict;
275
		font[fonts - 1].u.font.subtype = subtype;
276
		font[fonts - 1].u.font.name = basefont ? basefont : name;
277
	}
278
}
279
 
280
static void
281
gatherimages(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict)
282
{
283
	int i;
284
 
285
	for (i = 0; i < fz_dict_len(dict); i++)
286
	{
287
		fz_obj *imagedict;
288
		fz_obj *type;
289
		fz_obj *width;
290
		fz_obj *height;
291
		fz_obj *bpc = NULL;
292
		fz_obj *filter = NULL;
293
		fz_obj *cs = NULL;
294
		fz_obj *altcs;
295
		int k;
296
 
297
		imagedict = fz_dict_get_val(dict, i);
298
		if (!fz_is_dict(imagedict))
299
		{
300
			fz_warn("not an image dict (%d %d R)", fz_to_num(imagedict), fz_to_gen(imagedict));
301
			continue;
302
		}
303
 
304
		type = fz_dict_gets(imagedict, "Subtype");
305
		if (strcmp(fz_to_name(type), "Image"))
306
			continue;
307
 
308
		filter = fz_dict_gets(imagedict, "Filter");
309
 
310
		altcs = NULL;
311
		cs = fz_dict_gets(imagedict, "ColorSpace");
312
		if (fz_is_array(cs))
313
		{
314
			fz_obj *cses = cs;
315
 
316
			cs = fz_array_get(cses, 0);
317
			if (fz_is_name(cs) && (!strcmp(fz_to_name(cs), "DeviceN") || !strcmp(fz_to_name(cs), "Separation")))
318
			{
319
				altcs = fz_array_get(cses, 2);
320
				if (fz_is_array(altcs))
321
					altcs = fz_array_get(altcs, 0);
322
			}
323
		}
324
 
325
		width = fz_dict_gets(imagedict, "Width");
326
		height = fz_dict_gets(imagedict, "Height");
327
		bpc = fz_dict_gets(imagedict, "BitsPerComponent");
328
 
329
		for (k = 0; k < images; k++)
330
			if (!fz_objcmp(image[k].u.image.obj, imagedict))
331
				break;
332
 
333
		if (k < images)
334
			continue;
335
 
336
		images++;
337
 
338
		image = fz_realloc(image, images, sizeof(struct info));
339
		image[images - 1].page = page;
340
		image[images - 1].pageref = pageref;
341
		image[images - 1].pageobj = pageobj;
342
		image[images - 1].u.image.obj = imagedict;
343
		image[images - 1].u.image.width = width;
344
		image[images - 1].u.image.height = height;
345
		image[images - 1].u.image.bpc = bpc;
346
		image[images - 1].u.image.filter = filter;
347
		image[images - 1].u.image.cs = cs;
348
		image[images - 1].u.image.altcs = altcs;
349
	}
350
}
351
 
352
static void
353
gatherforms(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict)
354
{
355
	int i;
356
 
357
	for (i = 0; i < fz_dict_len(dict); i++)
358
	{
359
		fz_obj *xobjdict;
360
		fz_obj *type;
361
		fz_obj *subtype;
362
		fz_obj *group;
363
		fz_obj *groupsubtype;
364
		fz_obj *reference;
365
		int k;
366
 
367
		xobjdict = fz_dict_get_val(dict, i);
368
		if (!fz_is_dict(xobjdict))
369
		{
370
			fz_warn("not a xobject dict (%d %d R)", fz_to_num(xobjdict), fz_to_gen(xobjdict));
371
			continue;
372
		}
373
 
374
		type = fz_dict_gets(xobjdict, "Subtype");
375
		if (strcmp(fz_to_name(type), "Form"))
376
			continue;
377
 
378
		subtype = fz_dict_gets(xobjdict, "Subtype2");
379
		if (!strcmp(fz_to_name(subtype), "PS"))
380
			continue;
381
 
382
		group = fz_dict_gets(xobjdict, "Group");
383
		groupsubtype = fz_dict_gets(group, "S");
384
		reference = fz_dict_gets(xobjdict, "Ref");
385
 
386
		for (k = 0; k < forms; k++)
387
			if (!fz_objcmp(form[k].u.form.obj, xobjdict))
388
				break;
389
 
390
		if (k < forms)
391
			continue;
392
 
393
		forms++;
394
 
395
		form = fz_realloc(form, forms, sizeof(struct info));
396
		form[forms - 1].page = page;
397
		form[forms - 1].pageref = pageref;
398
		form[forms - 1].pageobj = pageobj;
399
		form[forms - 1].u.form.obj = xobjdict;
400
		form[forms - 1].u.form.groupsubtype = groupsubtype;
401
		form[forms - 1].u.form.reference = reference;
402
	}
403
}
404
 
405
static void
406
gatherpsobjs(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict)
407
{
408
	int i;
409
 
410
	for (i = 0; i < fz_dict_len(dict); i++)
411
	{
412
		fz_obj *xobjdict;
413
		fz_obj *type;
414
		fz_obj *subtype;
415
		int k;
416
 
417
		xobjdict = fz_dict_get_val(dict, i);
418
		if (!fz_is_dict(xobjdict))
419
		{
420
			fz_warn("not a xobject dict (%d %d R)", fz_to_num(xobjdict), fz_to_gen(xobjdict));
421
			continue;
422
		}
423
 
424
		type = fz_dict_gets(xobjdict, "Subtype");
425
		subtype = fz_dict_gets(xobjdict, "Subtype2");
426
		if (strcmp(fz_to_name(type), "PS") &&
427
			(strcmp(fz_to_name(type), "Form") || strcmp(fz_to_name(subtype), "PS")))
428
			continue;
429
 
430
		for (k = 0; k < psobjs; k++)
431
			if (!fz_objcmp(psobj[k].u.form.obj, xobjdict))
432
				break;
433
 
434
		if (k < psobjs)
435
			continue;
436
 
437
		psobjs++;
438
 
439
		psobj = fz_realloc(psobj, psobjs, sizeof(struct info));
440
		psobj[psobjs - 1].page = page;
441
		psobj[psobjs - 1].pageref = pageref;
442
		psobj[psobjs - 1].pageobj = pageobj;
443
		psobj[psobjs - 1].u.form.obj = xobjdict;
444
	}
445
}
446
 
447
static void
448
gathershadings(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict)
449
{
450
	int i;
451
 
452
	for (i = 0; i < fz_dict_len(dict); i++)
453
	{
454
		fz_obj *shade;
455
		fz_obj *type;
456
		int k;
457
 
458
		shade = fz_dict_get_val(dict, i);
459
		if (!fz_is_dict(shade))
460
		{
461
			fz_warn("not a shading dict (%d %d R)", fz_to_num(shade), fz_to_gen(shade));
462
			continue;
463
		}
464
 
465
		type = fz_dict_gets(shade, "ShadingType");
466
		if (!fz_is_int(type) || fz_to_int(type) < 1 || fz_to_int(type) > 7)
467
		{
468
			fz_warn("not a shading type (%d %d R)", fz_to_num(shade), fz_to_gen(shade));
469
			type = NULL;
470
		}
471
 
472
		for (k = 0; k < shadings; k++)
473
			if (!fz_objcmp(shading[k].u.shading.obj, shade))
474
				break;
475
 
476
		if (k < shadings)
477
			continue;
478
 
479
		shadings++;
480
 
481
		shading = fz_realloc(shading, shadings, sizeof(struct info));
482
		shading[shadings - 1].page = page;
483
		shading[shadings - 1].pageref = pageref;
484
		shading[shadings - 1].pageobj = pageobj;
485
		shading[shadings - 1].u.shading.obj = shade;
486
		shading[shadings - 1].u.shading.type = type;
487
	}
488
}
489
 
490
static void
491
gatherpatterns(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict)
492
{
493
	int i;
494
 
495
	for (i = 0; i < fz_dict_len(dict); i++)
496
	{
497
		fz_obj *patterndict;
498
		fz_obj *type;
499
		fz_obj *paint = NULL;
500
		fz_obj *tiling = NULL;
501
		fz_obj *shading = NULL;
502
		int k;
503
 
504
		patterndict = fz_dict_get_val(dict, i);
505
		if (!fz_is_dict(patterndict))
506
		{
507
			fz_warn("not a pattern dict (%d %d R)", fz_to_num(patterndict), fz_to_gen(patterndict));
508
			continue;
509
		}
510
 
511
		type = fz_dict_gets(patterndict, "PatternType");
512
		if (!fz_is_int(type) || fz_to_int(type) < 1 || fz_to_int(type) > 2)
513
		{
514
			fz_warn("not a pattern type (%d %d R)", fz_to_num(patterndict), fz_to_gen(patterndict));
515
			type = NULL;
516
		}
517
 
518
		if (fz_to_int(type) == 1)
519
		{
520
			paint = fz_dict_gets(patterndict, "PaintType");
521
			if (!fz_is_int(paint) || fz_to_int(paint) < 1 || fz_to_int(paint) > 2)
522
			{
523
				fz_warn("not a pattern paint type (%d %d R)", fz_to_num(patterndict), fz_to_gen(patterndict));
524
				paint = NULL;
525
			}
526
 
527
			tiling = fz_dict_gets(patterndict, "TilingType");
528
			if (!fz_is_int(tiling) || fz_to_int(tiling) < 1 || fz_to_int(tiling) > 3)
529
			{
530
				fz_warn("not a pattern tiling type (%d %d R)", fz_to_num(patterndict), fz_to_gen(patterndict));
531
				tiling = NULL;
532
			}
533
		}
534
		else
535
		{
536
			shading = fz_dict_gets(patterndict, "Shading");
537
		}
538
 
539
		for (k = 0; k < patterns; k++)
540
			if (!fz_objcmp(pattern[k].u.pattern.obj, patterndict))
541
				break;
542
 
543
		if (k < patterns)
544
			continue;
545
 
546
		patterns++;
547
 
548
		pattern = fz_realloc(pattern, patterns, sizeof(struct info));
549
		pattern[patterns - 1].page = page;
550
		pattern[patterns - 1].pageref = pageref;
551
		pattern[patterns - 1].pageobj = pageobj;
552
		pattern[patterns - 1].u.pattern.obj = patterndict;
553
		pattern[patterns - 1].u.pattern.type = type;
554
		pattern[patterns - 1].u.pattern.paint = paint;
555
		pattern[patterns - 1].u.pattern.tiling = tiling;
556
		pattern[patterns - 1].u.pattern.shading = shading;
557
	}
558
}
559
 
560
static void
561
gatherresourceinfo(int page, fz_obj *rsrc)
562
{
563
	fz_obj *pageobj;
564
	fz_obj *pageref;
565
	fz_obj *font;
566
	fz_obj *xobj;
567
	fz_obj *shade;
568
	fz_obj *pattern;
569
	fz_obj *subrsrc;
570
	int i;
571
 
572
	pageobj = xref->page_objs[page-1];
573
	pageref = xref->page_refs[page-1];
574
 
575
	if (!pageobj)
576
		die(fz_throw("cannot retrieve info from page %d", page));
577
 
578
	font = fz_dict_gets(rsrc, "Font");
579
	if (font)
580
	{
581
		gatherfonts(page, pageref, pageobj, font);
582
 
583
		for (i = 0; i < fz_dict_len(font); i++)
584
		{
585
			fz_obj *obj = fz_dict_get_val(font, i);
586
 
587
			subrsrc = fz_dict_gets(obj, "Resources");
588
			if (subrsrc && fz_objcmp(rsrc, subrsrc))
589
				gatherresourceinfo(page, subrsrc);
590
		}
591
	}
592
 
593
	xobj = fz_dict_gets(rsrc, "XObject");
594
	if (xobj)
595
	{
596
		gatherimages(page, pageref, pageobj, xobj);
597
		gatherforms(page, pageref, pageobj, xobj);
598
		gatherpsobjs(page, pageref, pageobj, xobj);
599
 
600
		for (i = 0; i < fz_dict_len(xobj); i++)
601
		{
602
			fz_obj *obj = fz_dict_get_val(xobj, i);
603
			subrsrc = fz_dict_gets(obj, "Resources");
604
			if (subrsrc && fz_objcmp(rsrc, subrsrc))
605
				gatherresourceinfo(page, subrsrc);
606
		}
607
	}
608
 
609
	shade = fz_dict_gets(rsrc, "Shading");
610
	if (shade)
611
		gathershadings(page, pageref, pageobj, shade);
612
 
613
	pattern = fz_dict_gets(rsrc, "Pattern");
614
	if (pattern)
615
	{
616
		gatherpatterns(page, pageref, pageobj, pattern);
617
 
618
		for (i = 0; i < fz_dict_len(pattern); i++)
619
		{
620
			fz_obj *obj = fz_dict_get_val(pattern, i);
621
			subrsrc = fz_dict_gets(obj, "Resources");
622
			if (subrsrc && fz_objcmp(rsrc, subrsrc))
623
				gatherresourceinfo(page, subrsrc);
624
		}
625
	}
626
}
627
 
628
static void
629
gatherpageinfo(int page)
630
{
631
	fz_obj *pageobj;
632
	fz_obj *pageref;
633
	fz_obj *rsrc;
634
 
635
	pageobj = xref->page_objs[page-1];
636
	pageref = xref->page_refs[page-1];
637
 
638
	if (!pageobj)
639
		die(fz_throw("cannot retrieve info from page %d", page));
640
 
641
	gatherdimensions(page, pageref, pageobj);
642
 
643
	rsrc = fz_dict_gets(pageobj, "Resources");
644
	gatherresourceinfo(page, rsrc);
645
}
646
 
647
static void
648
printinfo(char *filename, int show, int page)
649
{
650
	int i;
651
	int j;
652
 
653
#define PAGE_FMT "\t% 5d (% 7d %1d R): "
654
 
655
	if (show & DIMENSIONS && dims > 0)
656
	{
657
		printf("Mediaboxes (%d):\n", dims);
658
		for (i = 0; i < dims; i++)
659
		{
660
			printf(PAGE_FMT "[ %g %g %g %g ]\n",
661
				dim[i].page,
662
				fz_to_num(dim[i].pageref), fz_to_gen(dim[i].pageref),
663
				dim[i].u.dim.bbox->x0,
664
				dim[i].u.dim.bbox->y0,
665
				dim[i].u.dim.bbox->x1,
666
				dim[i].u.dim.bbox->y1);
667
		}
668
		printf("\n");
669
	}
670
 
671
	if (show & FONTS && fonts > 0)
672
	{
673
		printf("Fonts (%d):\n", fonts);
674
		for (i = 0; i < fonts; i++)
675
		{
676
			printf(PAGE_FMT "%s '%s' (%d %d R)\n",
677
				font[i].page,
678
				fz_to_num(font[i].pageref), fz_to_gen(font[i].pageref),
679
				fz_to_name(font[i].u.font.subtype),
680
				fz_to_name(font[i].u.font.name),
681
				fz_to_num(font[i].u.font.obj), fz_to_gen(font[i].u.font.obj));
682
		}
683
		printf("\n");
684
	}
685
 
686
	if (show & IMAGES && images > 0)
687
	{
688
		printf("Images (%d):\n", images);
689
		for (i = 0; i < images; i++)
690
		{
691
			char *cs = NULL;
692
			char *altcs = NULL;
693
 
694
			printf(PAGE_FMT "[ ",
695
				image[i].page,
696
				fz_to_num(image[i].pageref), fz_to_gen(image[i].pageref));
697
 
698
			if (fz_is_array(image[i].u.image.filter))
699
				for (j = 0; j < fz_array_len(image[i].u.image.filter); j++)
700
				{
701
					fz_obj *obj = fz_array_get(image[i].u.image.filter, j);
702
					char *filter = fz_strdup(fz_to_name(obj));
703
 
704
					if (strstr(filter, "Decode"))
705
						*(strstr(filter, "Decode")) = '\0';
706
 
707
					printf("%s%s",
708
							filter,
709
							j == fz_array_len(image[i].u.image.filter) - 1 ? "" : " ");
710
					fz_free(filter);
711
				}
712
			else if (image[i].u.image.filter)
713
			{
714
				fz_obj *obj = image[i].u.image.filter;
715
				char *filter = fz_strdup(fz_to_name(obj));
716
 
717
				if (strstr(filter, "Decode"))
718
					*(strstr(filter, "Decode")) = '\0';
719
 
720
				printf("%s", filter);
721
				fz_free(filter);
722
			}
723
			else
724
				printf("Raw");
725
 
726
			if (image[i].u.image.cs)
727
			{
728
				cs = fz_strdup(fz_to_name(image[i].u.image.cs));
729
 
730
				if (!strncmp(cs, "Device", 6))
731
				{
732
					int len = strlen(cs + 6);
733
					memmove(cs + 3, cs + 6, len + 1);
734
					cs[3 + len + 1] = '\0';
735
				}
736
				if (strstr(cs, "ICC"))
737
					fz_strlcpy(cs, "ICC", 4);
738
				if (strstr(cs, "Indexed"))
739
					fz_strlcpy(cs, "Idx", 4);
740
				if (strstr(cs, "Pattern"))
741
					fz_strlcpy(cs, "Pat", 4);
742
				if (strstr(cs, "Separation"))
743
					fz_strlcpy(cs, "Sep", 4);
744
			}
745
			if (image[i].u.image.altcs)
746
			{
747
				altcs = fz_strdup(fz_to_name(image[i].u.image.altcs));
748
 
749
				if (!strncmp(altcs, "Device", 6))
750
				{
751
					int len = strlen(altcs + 6);
752
					memmove(altcs + 3, altcs + 6, len + 1);
753
					altcs[3 + len + 1] = '\0';
754
				}
755
				if (strstr(altcs, "ICC"))
756
					fz_strlcpy(altcs, "ICC", 4);
757
				if (strstr(altcs, "Indexed"))
758
					fz_strlcpy(altcs, "Idx", 4);
759
				if (strstr(altcs, "Pattern"))
760
					fz_strlcpy(altcs, "Pat", 4);
761
				if (strstr(altcs, "Separation"))
762
					fz_strlcpy(altcs, "Sep", 4);
763
			}
764
 
765
			printf(" ] %dx%d %dbpc %s%s%s (%d %d R)\n",
766
				fz_to_int(image[i].u.image.width),
767
				fz_to_int(image[i].u.image.height),
768
				image[i].u.image.bpc ? fz_to_int(image[i].u.image.bpc) : 1,
769
				image[i].u.image.cs ? cs : "ImageMask",
770
				image[i].u.image.altcs ? " " : "",
771
				image[i].u.image.altcs ? altcs : "",
772
				fz_to_num(image[i].u.image.obj), fz_to_gen(image[i].u.image.obj));
773
 
774
			fz_free(cs);
775
			fz_free(altcs);
776
		}
777
		printf("\n");
778
	}
779
 
780
	if (show & SHADINGS && shadings > 0)
781
	{
782
		printf("Shading patterns (%d):\n", shadings);
783
		for (i = 0; i < shadings; i++)
784
		{
785
			char *shadingtype[] =
786
			{
787
				"",
788
				"Function",
789
				"Axial",
790
				"Radial",
791
				"Triangle mesh",
792
				"Lattice",
793
				"Coons patch",
794
				"Tensor patch",
795
			};
796
 
797
			printf(PAGE_FMT "%s (%d %d R)\n",
798
				shading[i].page,
799
				fz_to_num(shading[i].pageref), fz_to_gen(shading[i].pageref),
800
				shadingtype[fz_to_int(shading[i].u.shading.type)],
801
				fz_to_num(shading[i].u.shading.obj), fz_to_gen(shading[i].u.shading.obj));
802
		}
803
		printf("\n");
804
	}
805
 
806
	if (show & PATTERNS && patterns > 0)
807
	{
808
		printf("Patterns (%d):\n", patterns);
809
		for (i = 0; i < patterns; i++)
810
		{
811
			if (fz_to_int(pattern[i].u.pattern.type) == 1)
812
			{
813
				char *painttype[] =
814
				{
815
					"",
816
					"Colored",
817
					"Uncolored",
818
				};
819
				char *tilingtype[] =
820
				{
821
					"",
822
					"Constant",
823
					"No distortion",
824
					"Constant/fast tiling",
825
				};
826
 
827
				printf(PAGE_FMT "Tiling %s %s (%d %d R)\n",
828
						pattern[i].page,
829
						fz_to_num(pattern[i].pageref), fz_to_gen(pattern[i].pageref),
830
						painttype[fz_to_int(pattern[i].u.pattern.paint)],
831
						tilingtype[fz_to_int(pattern[i].u.pattern.tiling)],
832
						fz_to_num(pattern[i].u.pattern.obj), fz_to_gen(pattern[i].u.pattern.obj));
833
			}
834
			else
835
			{
836
				printf(PAGE_FMT "Shading %d %d R (%d %d R)\n",
837
						pattern[i].page,
838
						fz_to_num(pattern[i].pageref), fz_to_gen(pattern[i].pageref),
839
						fz_to_num(pattern[i].u.pattern.shading), fz_to_gen(pattern[i].u.pattern.shading),
840
						fz_to_num(pattern[i].u.pattern.obj), fz_to_gen(pattern[i].u.pattern.obj));
841
			}
842
		}
843
		printf("\n");
844
	}
845
 
846
	if (show & XOBJS && forms > 0)
847
	{
848
		printf("Form xobjects (%d):\n", forms);
849
		for (i = 0; i < forms; i++)
850
		{
851
			printf(PAGE_FMT "Form%s%s%s%s (%d %d R)\n",
852
				form[i].page,
853
				fz_to_num(form[i].pageref), fz_to_gen(form[i].pageref),
854
				form[i].u.form.groupsubtype ? " " : "",
855
				form[i].u.form.groupsubtype ? fz_to_name(form[i].u.form.groupsubtype) : "",
856
				form[i].u.form.groupsubtype ? " Group" : "",
857
				form[i].u.form.reference ? " Reference" : "",
858
				fz_to_num(form[i].u.form.obj), fz_to_gen(form[i].u.form.obj));
859
		}
860
		printf("\n");
861
	}
862
 
863
	if (show & XOBJS && psobjs > 0)
864
	{
865
		printf("Postscript xobjects (%d):\n", psobjs);
866
		for (i = 0; i < psobjs; i++)
867
		{
868
			printf(PAGE_FMT "(%d %d R)\n",
869
				psobj[i].page,
870
				fz_to_num(psobj[i].pageref), fz_to_gen(psobj[i].pageref),
871
				fz_to_num(psobj[i].u.form.obj), fz_to_gen(psobj[i].u.form.obj));
872
		}
873
		printf("\n");
874
	}
875
}
876
 
877
static void
878
showinfo(char *filename, int show, char *pagelist)
879
{
880
	int page, spage, epage;
881
	char *spec, *dash;
882
	int allpages;
883
 
884
	if (!xref)
885
		infousage();
886
 
887
	allpages = !strcmp(pagelist, "1-");
888
 
889
	spec = fz_strsep(&pagelist, ",");
890
	while (spec)
891
	{
892
		dash = strchr(spec, '-');
893
 
894
		if (dash == spec)
895
			spage = epage = pagecount;
896
		else
897
			spage = epage = atoi(spec);
898
 
899
		if (dash)
900
		{
901
			if (strlen(dash) > 1)
902
				epage = atoi(dash + 1);
903
			else
904
				epage = pagecount;
905
		}
906
 
907
		if (spage > epage)
908
			page = spage, spage = epage, epage = page;
909
 
910
		if (spage < 1)
911
			spage = 1;
912
		if (epage > pagecount)
913
			epage = pagecount;
914
		if (spage > pagecount)
915
			spage = pagecount;
916
 
917
		if (allpages)
918
			printf("Retrieving info from pages %d-%d...\n", spage, epage);
919
		if (spage >= 1)
920
		{
921
			for (page = spage; page <= epage; page++)
922
			{
923
				gatherpageinfo(page);
924
				if (!allpages)
925
				{
926
					printf("Page %d:\n", page);
927
					printinfo(filename, show, page);
928
					printf("\n");
929
				}
930
			}
931
		}
932
 
933
		spec = fz_strsep(&pagelist, ",");
934
	}
935
 
936
	if (allpages)
937
		printinfo(filename, show, -1);
938
}
939
 
940
int main(int argc, char **argv)
941
{
942
	enum { NO_FILE_OPENED, NO_INFO_GATHERED, INFO_SHOWN } state;
943
	fz_error error;
944
	char *filename = "";
945
	char *password = "";
946
	int show = ALL;
947
	int c;
948
 
949
	while ((c = fz_getopt(argc, argv, "mfispxd:")) != -1)
950
	{
951
		switch (c)
952
		{
953
		case 'm': if (show == ALL) show = DIMENSIONS; else show |= DIMENSIONS; break;
954
		case 'f': if (show == ALL) show = FONTS; else show |= FONTS; break;
955
		case 'i': if (show == ALL) show = IMAGES; else show |= IMAGES; break;
956
		case 's': if (show == ALL) show = SHADINGS; else show |= SHADINGS; break;
957
		case 'p': if (show == ALL) show = PATTERNS; else show |= PATTERNS; break;
958
		case 'x': if (show == ALL) show = XOBJS; else show |= XOBJS; break;
959
		case 'd': password = fz_optarg; break;
960
		default:
961
			infousage();
962
			break;
963
		}
964
	}
965
 
966
	if (fz_optind == argc)
967
		infousage();
968
 
969
	state = NO_FILE_OPENED;
970
	while (fz_optind < argc)
971
	{
972
		if (strstr(argv[fz_optind], ".pdf") || strstr(argv[fz_optind], ".PDF"))
973
		{
974
			if (state == NO_INFO_GATHERED)
975
			{
976
				showinfo(filename, show, "1-");
977
				closexref();
978
			}
979
 
980
			closexref();
981
 
982
			filename = argv[fz_optind];
983
			printf("%s:\n", filename);
984
			error = pdf_open_xref(&xref, filename, password);
985
			if (error)
986
				die(fz_rethrow(error, "cannot open input file '%s'", filename));
987
 
988
			error = pdf_load_page_tree(xref);
989
			if (error)
990
				die(fz_rethrow(error, "cannot load page tree: %s", filename));
991
			pagecount = pdf_count_pages(xref);
992
 
993
			showglobalinfo();
994
			state = NO_INFO_GATHERED;
995
		}
996
		else
997
		{
998
			showinfo(filename, show, argv[fz_optind]);
999
			state = INFO_SHOWN;
1000
		}
1001
 
1002
		fz_optind++;
1003
	}
1004
 
1005
	if (state == NO_INFO_GATHERED)
1006
		showinfo(filename, show, "1-");
1007
 
1008
	closexref();
1009
 
1010
	return 0;
1011
}