1 /*
2 Copyright 2002-2014 Han The Thanh, <thanh@pdftex.org>
3
4 This file is part of pdfTeX.
5
6 pdfTeX is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2 of the License, or (at your option)
9 any later version.
10
11 pdfTeX is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License along
17 with this program. If not, see <http://www.gnu.org/licenses/>.
18
19 This is experimental JBIG2 image support to pdfTeX. JBIG2 image decoding
20 is part of Adobe PDF-1.4, and requires Acroread 5.0 or later.
21
22 References
23 ==========
24
25 * 14492 FCD: Information technology -- coded representation of picture
26 and audio information -- lossy/lossless coding of bi-level images /
27 JBIG committee, 1999 July 16. This JBIG2 Working Draft is available from
28 http://www.jpeg.org/public/fcd14492.pdf. The references in the C-code
29 correspond to the sections of this document.
30
31 * PDF Reference, 5th edition, version 1.6, 1985--2005 Adobe Systems
32 Incorporated. Available online:
33
34 http://partners.adobe.com/public/developer/en/pdf/PDFReference16.pdf
35
36 News
37 ====
38
39 31 May 2006: no need to wait for endoffileflag in sequential access
40 organization.
41
42 10 May 2006: ygetc() for some catching of broken JBIG2 files; modify to
43 accept Example 3.4 from PDFRef 5th ed. with short end-of-file segment.
44
45 09 May 2006: pages_maketree() and segments_maketree() by AVL tree,
46 some cleaning up.
47
48 06 May 2006: File list replaced by AVL tree; new_fileinfo(),
49 new_pageinfo().
50
51 04 May 2006: Updated for pdftex-1.40-beta-20060213.
52
53 08 Jan. 2003: Added flushjbig2page0objects() function. Now at the end
54 of the pdfTeX run all pending page0 objects are written out.
55
56 08 Jan. 2003: Release on private webpage.
57
58 04 Jan. 2003: Completely rewritten. Now with some data structures.
59 Rudimentary local file and image bookkeeping. Multiple image inclusion
60 from one JBIG2 file. Only required page0 segments are marked for
61 inclusion.
62
63 13 Nov. 2002: pdfcrypting removed.
64
65 08 Dec. 2002: bug in page 0 stream writing repaired.
66 Strategy for multiple page inclusion from same JBIG2 file: When writing
67 1st image, create fresh PDF object for page 0, and include any page
68 0 segments from complete file (even if these segments are not needed
69 for image). When writing next image, check by filename comparison if
70 PDF object for page 0 of this JBIG2 file has already been written. This
71 can only remember the file name for the direct predecessor JBIG2 image
72 (but images of other types might come inbetween). If such page 0 PDF
73 object exists, reference it. Else create fresh one.
74
75 09 Dec. 2002: JBIG2 seg. page numbers > 0 are now set to 1, see PDF Ref.
76
77 ***********************************************************************/
78
79 #include "ptexlib.h"
80 #include <stdlib.h>
81 #include <stdio.h>
82 #include <assert.h>
83 #include "ptexmac.h"
84 #include "image.h"
85
86 /* 7.3 Segment types */
87 #define M_SymbolDictionary 0
88 #define M_IntermediateTextRegion 4
89 #define M_ImmediateTextRegion 6
90 #define M_ImmediateLosslessTextRegion 7
91 #define M_PatternDictionary 16
92 #define M_IntermediateHalftoneRegion 20
93 #define M_ImmediateHalftoneRegion 22
94 #define M_ImmediateLosslessHalftoneRegion 23
95 #define M_IntermediateGenericRegion 36
96 #define M_ImmediateGenericRegion 38
97 #define M_ImmediateLosslessGenericRegion 39
98 #define M_IntermediateGenericRefinementRegion 40
99 #define M_ImmediateGenericRefinementRegion 42
100 #define M_ImmediateLosslessGenericRefinementRegion 43
101 #define M_PageInformation 48
102 #define M_EndOfPage 49
103 #define M_EndOfStripe 50
104 #define M_EndOfFile 51
105 #define M_Profiles 52
106 #define M_Tables 53
107 #define M_Extension 62
108
109 /**********************************************************************/
110
111 typedef enum { INITIAL, HAVEINFO, WRITEPDF } PHASE;
112
113 typedef struct _LITEM {
114 struct _LITEM *prev;
115 struct _LITEM *next;
116 void *d; /* data */
117 } LITEM;
118
119 typedef struct _LIST {
120 LITEM *first;
121 LITEM *last;
122 struct avl_table *tree;
123 } LIST;
124
125 typedef struct _SEGINFO {
126 unsigned long segnum;
127 boolean isrefered;
128 boolean refers;
129 unsigned int seghdrflags; /* set by readseghdr() */
130 boolean pageassocsizeflag; /* set by readseghdr() */
131 unsigned int reftosegcount; /* set by readseghdr() */
132 unsigned int countofrefered; /* set by readseghdr() */
133 unsigned int fieldlen; /* set by readseghdr() */
134 unsigned int segnumwidth; /* set by readseghdr() */
135 long segpage; /* set by readseghdr() */
136 unsigned long segdatalen; /* set by readseghdr() */
137 off_t hdrstart; /* set by readseghdr() */
138 off_t hdrend; /* set by readseghdr() */
139 off_t datastart;
140 off_t dataend;
141 boolean endofstripeflag; /* set by checkseghdrflags() */
142 boolean endofpageflag; /* set by checkseghdrflags() */
143 boolean pageinfoflag; /* set by checkseghdrflags() */
144 boolean endoffileflag; /* set by checkseghdrflags() */
145 } SEGINFO;
146
147 typedef struct _PAGEINFO {
148 LIST segments; /* segments associated with page */
149 unsigned long pagenum;
150 unsigned int width;
151 unsigned int height;
152 unsigned int xres;
153 unsigned int yres;
154 unsigned int pagesegmentflags;
155 unsigned int stripinginfo;
156 unsigned int stripedheight;
157 } PAGEINFO;
158
159 typedef struct _FILEINFO {
160 FILE *file;
161 char *filename;
162 off_t filesize;
163 LIST pages; /* not including page0 */
164 LIST page0;
165 unsigned int filehdrflags; /* set by readfilehdr() */
166 boolean sequentialaccess; /* set by readfilehdr() */
167 unsigned long numofpages; /* set by readfilehdr() */
168 off_t streamstart; /* set by get_jbig2_info() */
169 unsigned long pdfpage0objnum;
170 PHASE phase;
171 } FILEINFO;
172
173 /**********************************************************************/
174
175 static void initlinkedlist(LIST * lp);
176 static void checkseghdrflags(SEGINFO * sip);
177 static void markpage0seg(FILEINFO * fip, unsigned long referedseg);
178
179 /**********************************************************************/
180
181 struct avl_table *file_tree = NULL;
182
comp_file_entry(const void * pa,const void * pb,void * p)183 static int comp_file_entry(const void *pa, const void *pb, void *p)
184 {
185 return strcmp(((const FILEINFO *) pa)->filename,
186 ((const FILEINFO *) pb)->filename);
187 }
188
comp_page_entry(const void * pa,const void * pb,void * p)189 static int comp_page_entry(const void *pa, const void *pb, void *p)
190 {
191 return ((const PAGEINFO *) pa)->pagenum - ((const PAGEINFO *) pb)->pagenum;
192 }
193
comp_segment_entry(const void * pa,const void * pb,void * p)194 static int comp_segment_entry(const void *pa, const void *pb, void *p)
195 {
196 return ((const SEGINFO *) pa)->segnum - ((const SEGINFO *) pb)->segnum;
197 }
198
199 /**********************************************************************/
200
ygetc(FILE * stream)201 static int ygetc(FILE * stream)
202 {
203 int c = getc(stream);
204 if (c < 0) {
205 if (c == EOF)
206 pdftex_fail("getc() failed; premature end of JBIG2 image file");
207 else
208 pdftex_fail("getc() failed (can't happen)");
209 }
210 return c;
211 }
212
213 /**********************************************************************/
214
new_fileinfo(void)215 static FILEINFO *new_fileinfo(void)
216 {
217 FILEINFO *fip;
218 fip = xtalloc(1, FILEINFO);
219 fip->file = NULL;
220 fip->filename = NULL;
221 fip->filesize = 0;
222 initlinkedlist(&(fip->pages));
223 initlinkedlist(&(fip->page0));
224 fip->filehdrflags = 0;
225 fip->sequentialaccess = false;
226 fip->numofpages = 0;
227 fip->streamstart = 0;
228 fip->pdfpage0objnum = 0;
229 fip->phase = INITIAL;
230 return fip;
231 }
232
new_pageinfo(void)233 static PAGEINFO *new_pageinfo(void)
234 {
235 PAGEINFO *pip;
236 pip = xtalloc(1, PAGEINFO);
237 initlinkedlist(&(pip->segments));
238 pip->pagenum = 0;
239 pip->width = 0;
240 pip->height = 0;
241 pip->xres = 0;
242 pip->yres = 0;
243 pip->pagesegmentflags = 0;
244 pip->stripinginfo = 0;
245 pip->stripedheight = 0;
246 return pip;
247 }
248
init_seginfo(SEGINFO * sip)249 static void init_seginfo(SEGINFO * sip)
250 {
251 sip->segnum = 0;
252 sip->isrefered = false;
253 sip->refers = false;
254 sip->seghdrflags = 0;
255 sip->pageassocsizeflag = false;
256 sip->reftosegcount = 0;
257 sip->countofrefered = 0;
258 sip->fieldlen = 0;
259 sip->segnumwidth = 0;
260 sip->segpage = 0;
261 sip->segdatalen = 0;
262 sip->hdrstart = 0;
263 sip->hdrend = 0;
264 sip->datastart = 0;
265 sip->dataend = 0;
266 sip->endofstripeflag = false;
267 sip->endofpageflag = false;
268 sip->pageinfoflag = false;
269 sip->endoffileflag = false;
270 }
271
272 /**********************************************************************/
273
initlinkedlist(LIST * lp)274 static void initlinkedlist(LIST * lp)
275 {
276 lp->first = NULL;
277 lp->last = NULL;
278 lp->tree = NULL;
279 }
280
litem_append(LIST * lp)281 static LIST *litem_append(LIST * lp)
282 {
283 LITEM *ip;
284 ip = xtalloc(1, LITEM);
285 if (lp->first == NULL) {
286 lp->first = ip;
287 ip->prev = NULL;
288 } else {
289 lp->last->next = ip;
290 ip->prev = lp->last;
291 }
292 lp->last = ip;
293 ip->next = NULL;
294 ip->d = NULL;
295 return lp;
296 }
297
298 /**********************************************************************/
299
pages_maketree(LIST * plp)300 static void pages_maketree(LIST * plp)
301 {
302 LITEM *ip;
303 void **aa;
304 assert(plp->tree == NULL);
305 plp->tree = avl_create(comp_page_entry, NULL, &avl_xallocator);
306 assert(plp->tree != NULL);
307 for (ip = plp->first; ip != NULL; ip = ip->next) {
308 aa = avl_probe(plp->tree, (PAGEINFO *) ip->d);
309 assert(aa != NULL);
310 }
311 }
312
segments_maketree(LIST * slp)313 static void segments_maketree(LIST * slp)
314 {
315 LITEM *ip;
316 void **aa;
317 assert(slp->tree == NULL);
318 slp->tree = avl_create(comp_segment_entry, NULL, &avl_xallocator);
319 assert(slp->tree != NULL);
320 for (ip = slp->first; ip != NULL; ip = ip->next) {
321 aa = avl_probe(slp->tree, (SEGINFO *) ip->d);
322 assert(aa != NULL);
323 }
324 }
325
326 /**********************************************************************/
327
find_pageinfo(LIST * plp,unsigned long pagenum)328 static PAGEINFO *find_pageinfo(LIST * plp, unsigned long pagenum)
329 {
330 PAGEINFO tmp;
331 tmp.pagenum = pagenum;
332 assert(plp->tree != NULL);
333 return (PAGEINFO *) avl_find(plp->tree, &tmp);
334 }
335
find_seginfo(LIST * slp,unsigned long segnum)336 static SEGINFO *find_seginfo(LIST * slp, unsigned long segnum)
337 {
338 SEGINFO tmp;
339 tmp.segnum = segnum;
340 assert(slp->tree != NULL);
341 return (SEGINFO *) avl_find(slp->tree, &tmp);
342 }
343
344 /**********************************************************************/
345
read2bytes(FILE * f)346 static unsigned int read2bytes(FILE * f)
347 {
348 unsigned int c = ygetc(f);
349 return (c << 8) + ygetc(f);
350 }
351
read4bytes(FILE * f)352 static unsigned long read4bytes(FILE * f)
353 {
354 unsigned int l = read2bytes(f);
355 return (l << 16) + read2bytes(f);
356 }
357
358 /**********************************************************************/
359
getstreamlen(LITEM * slip,boolean refer)360 static off_t getstreamlen(LITEM * slip, boolean refer)
361 {
362 SEGINFO *sip;
363 off_t len = 0;
364 for (; slip != NULL; slip = slip->next) {
365 sip = slip->d;
366 if (refer || sip->isrefered)
367 len += (sip->hdrend - sip->hdrstart) + (sip->dataend - sip->datastart);
368 }
369 return len;
370 }
371
372 /**********************************************************************/
373
readfilehdr(FILEINFO * fip)374 static void readfilehdr(FILEINFO * fip)
375 {
376 unsigned int i;
377 /* Annex D.4 File header syntax */
378 /* Annex D.4.1 ID string */
379 unsigned char jbig2_id[] = { 0x97, 'J', 'B', '2', 0x0d, 0x0a, 0x1a, 0x0a };
380 xfseeko(fip->file, (off_t)0, SEEK_SET, fip->filename);
381 for (i = 0; i < 8; i++)
382 if (ygetc(fip->file) != jbig2_id[i])
383 pdftex_fail
384 ("readfilehdr(): reading JBIG2 image file failed: ID string missing");
385 /* Annex D.4.2 File header flags */
386 fip->filehdrflags = ygetc(fip->file);
387 fip->sequentialaccess = (fip->filehdrflags & 0x01) ? true : false;
388 if (fip->sequentialaccess) { /* Annex D.1 vs. Annex D.2 */
389 xfseeko(fip->file, (off_t)0, SEEK_END, fip->filename);
390 fip->filesize = xftello(fip->file, fip->filename);
391 xfseeko(fip->file, (off_t)9, SEEK_SET, fip->filename);
392 }
393 /* Annex D.4.3 Number of pages */
394 if (!(fip->filehdrflags >> 1) & 0x01) /* known number of pages */
395 fip->numofpages = read4bytes(fip->file);
396 /* --- at end of file header --- */
397 }
398
399 /**********************************************************************/
400 /* for first reading of file; return value tells if header been read */
401
readseghdr(FILEINFO * fip,SEGINFO * sip)402 static boolean readseghdr(FILEINFO * fip, SEGINFO * sip)
403 {
404 unsigned int i;
405 sip->hdrstart = xftello(fip->file, fip->filename);
406 if (fip->sequentialaccess && sip->hdrstart == fip->filesize)
407 return false; /* no endoffileflag is ok for sequentialaccess */
408 /* 7.2.2 Segment number */
409 sip->segnum = read4bytes(fip->file);
410 /* 7.2.3 Segment header flags */
411 sip->seghdrflags = ygetc(fip->file);
412 checkseghdrflags(sip);
413 if (fip->sequentialaccess && sip->endoffileflag) /* accept shorter segment, */
414 return true; /* makes it compliant with Example 3.4 of PDFRef. 5th ed. */
415 sip->pageassocsizeflag = ((sip->seghdrflags >> 6) & 0x01) ? true : false;
416 /* 7.2.4 Referred-to segment count and retention flags */
417 sip->reftosegcount = (unsigned int) ygetc(fip->file);
418 sip->countofrefered = sip->reftosegcount >> 5;
419 if (sip->countofrefered < 5)
420 sip->fieldlen = 1;
421 else {
422 sip->fieldlen = 5 + sip->countofrefered / 8;
423 xfseeko(fip->file, (off_t) sip->fieldlen - 1, SEEK_CUR, fip->filename);
424 }
425 /* 7.2.5 Referred-to segment numbers */
426 if (sip->segnum <= 256)
427 sip->segnumwidth = 1;
428 else if (sip->segnum <= 65536)
429 sip->segnumwidth = 2;
430 else
431 sip->segnumwidth = 4;
432 for (i = 0; i < sip->countofrefered; i++) {
433 switch (sip->segnumwidth) {
434 case 1:
435 (void) ygetc(fip->file);
436 break;
437 case 2:
438 (void) read2bytes(fip->file);
439 break;
440 case 4:
441 (void) read4bytes(fip->file);
442 break;
443 }
444 }
445 /* 7.2.6 Segment page association */
446 if (sip->pageassocsizeflag)
447 sip->segpage = read4bytes(fip->file);
448 else
449 sip->segpage = ygetc(fip->file);
450 /* 7.2.7 Segment data length */
451 sip->segdatalen = read4bytes(fip->file);
452 sip->hdrend = xftello(fip->file, fip->filename);
453 /* ---- at end of segment header ---- */
454 return true;
455 }
456
457 /**********************************************************************/
458 /* for writing, marks refered page0 segments, sets segpage > 0 to 1 */
459
writeseghdr(FILEINFO * fip,SEGINFO * sip)460 static void writeseghdr(FILEINFO * fip, SEGINFO * sip)
461 {
462 unsigned int i;
463 unsigned long referedseg = 0;
464 /* 7.2.2 Segment number */
465 /* 7.2.3 Segment header flags */
466 /* 7.2.4 Referred-to segment count and retention flags */
467 for (i = 0; i < 5 + sip->fieldlen; i++)
468 pdfout(ygetc(fip->file));
469 /* 7.2.5 Referred-to segment numbers */
470 for (i = 0; i < sip->countofrefered; i++) {
471 switch (sip->segnumwidth) {
472 case 1:
473 referedseg = ygetc(fip->file);
474 pdfout(referedseg);
475 break;
476 case 2:
477 referedseg = read2bytes(fip->file);
478 pdfout((referedseg >> 8) & 0xff);
479 pdfout(referedseg & 0xff);
480 break;
481 case 4:
482 referedseg = read4bytes(fip->file);
483 pdfout((referedseg >> 24) & 0xff);
484 pdfout((referedseg >> 16) & 0xff);
485 pdfout((referedseg >> 8) & 0xff);
486 pdfout(referedseg & 0xff);
487 break;
488 }
489 if (fip->page0.last != NULL && !sip->refers)
490 markpage0seg(fip, referedseg);
491 }
492 if (sip->countofrefered > 0)
493 sip->refers = true;
494 /* 7.2.6 Segment page association */
495 if (sip->pageassocsizeflag)
496 for (i = 0; i < 3; i++) {
497 (void) ygetc(fip->file);
498 pdfout(0);
499 }
500 (void) ygetc(fip->file);
501 pdfout((sip->segpage > 0) ? 1 : 0);
502 /* 7.2.7 Segment data length */
503 for (i = 0; i < 4; i++)
504 pdfout(ygetc(fip->file));
505 /* ---- at end of segment header ---- */
506 }
507
508 /**********************************************************************/
509 /* for recursive marking of refered page0 segments */
510
checkseghdr(FILEINFO * fip,SEGINFO * sip)511 static void checkseghdr(FILEINFO * fip, SEGINFO * sip)
512 {
513 unsigned int i;
514 unsigned long referedseg = 0;
515 /* 7.2.2 Segment number */
516 /* 7.2.3 Segment header flags */
517 /* 7.2.4 Referred-to segment count and retention flags */
518 xfseeko(fip->file, (off_t) sip->fieldlen + 5, SEEK_CUR, fip->filename);
519 /* 7.2.5 Referred-to segment numbers */
520 for (i = 0; i < sip->countofrefered; i++) {
521 switch (sip->segnumwidth) {
522 case 1:
523 referedseg = ygetc(fip->file);
524 break;
525 case 2:
526 referedseg = read2bytes(fip->file);
527 break;
528 case 4:
529 referedseg = read4bytes(fip->file);
530 break;
531 }
532 if (!sip->refers)
533 markpage0seg(fip, referedseg);
534 }
535 if (sip->countofrefered > 0)
536 sip->refers = true;
537 /* 7.2.6 Segment page association */
538 /* 7.2.7 Segment data length */
539 if (sip->pageassocsizeflag)
540 xfseeko(fip->file, 8, SEEK_CUR, fip->filename);
541 else
542 xfseeko(fip->file, 5, SEEK_CUR, fip->filename);
543 /* ---- at end of segment header ---- */
544 }
545
546 /**********************************************************************/
547
checkseghdrflags(SEGINFO * sip)548 static void checkseghdrflags(SEGINFO * sip)
549 {
550 sip->endofstripeflag = false;
551 sip->endofpageflag = false;
552 sip->pageinfoflag = false;
553 sip->endoffileflag = false;
554 /* 7.3 Segment types */
555 switch (sip->seghdrflags & 0x3f) {
556 case M_SymbolDictionary:
557 case M_IntermediateTextRegion:
558 case M_ImmediateTextRegion:
559 case M_ImmediateLosslessTextRegion:
560 case M_PatternDictionary:
561 case M_IntermediateHalftoneRegion:
562 case M_ImmediateHalftoneRegion:
563 case M_ImmediateLosslessHalftoneRegion:
564 case M_IntermediateGenericRegion:
565 case M_ImmediateGenericRegion:
566 case M_ImmediateLosslessGenericRegion:
567 case M_IntermediateGenericRefinementRegion:
568 case M_ImmediateGenericRefinementRegion:
569 case M_ImmediateLosslessGenericRefinementRegion:
570 break;
571 case M_PageInformation:
572 sip->pageinfoflag = true;
573 break;
574 case M_EndOfPage:
575 sip->endofpageflag = true;
576 break;
577 case M_EndOfStripe:
578 sip->endofstripeflag = true;
579 break;
580 case M_EndOfFile:
581 sip->endoffileflag = true;
582 break;
583 case M_Profiles:
584 case M_Tables:
585 case M_Extension:
586 break;
587 default:
588 pdftex_fail
589 ("checkseghdrflags(): unknown segment type in JBIG2 image file");
590 break;
591 }
592 }
593
594 /**********************************************************************/
595
markpage0seg(FILEINFO * fip,unsigned long referedseg)596 static void markpage0seg(FILEINFO * fip, unsigned long referedseg)
597 {
598 PAGEINFO *pip;
599 SEGINFO *sip;
600 pip = fip->page0.first->d;
601 sip = find_seginfo(&(pip->segments), referedseg);
602 if (sip != NULL) {
603 if (!sip->refers && sip->countofrefered > 0)
604 checkseghdr(fip, sip);
605 sip->isrefered = true;
606 }
607 }
608
609 /**********************************************************************/
610
findstreamstart(FILEINFO * fip)611 static off_t findstreamstart(FILEINFO * fip)
612 {
613 SEGINFO tmp;
614 assert(!fip->sequentialaccess); /* D.2 Random-access organisation */
615 do /* find random-access stream start */
616 (void) readseghdr(fip, &tmp);
617 while (!tmp.endoffileflag);
618 fip->streamstart = tmp.hdrend;
619 readfilehdr(fip);
620 return fip->streamstart;
621 }
622
623 /**********************************************************************/
624
rd_jbig2_info(FILEINFO * fip)625 static void rd_jbig2_info(FILEINFO * fip)
626 {
627 off_t seekdist = 0; /* for sequential-access only */
628 off_t streampos = 0; /* for random-access only */
629 unsigned long currentpage = 0;
630 boolean sipavail = false;
631 PAGEINFO *pip;
632 SEGINFO *sip = NULL;
633 LIST *plp, *slp;
634 fip->file = xfopen(fip->filename, FOPEN_RBIN_MODE);
635 readfilehdr(fip);
636 if (!fip->sequentialaccess) /* D.2 Random-access organisation */
637 streampos = findstreamstart(fip);
638 while (true) { /* loop over segments */
639 if (!sipavail) {
640 sip = xtalloc(1, SEGINFO);
641 sipavail = true;
642 }
643 init_seginfo(sip);
644 if (!readseghdr(fip, sip) || sip->endoffileflag)
645 break;
646 if (sip->segpage > 0) {
647 if (sip->segpage > currentpage) {
648 plp = litem_append(&(fip->pages));
649 plp->last->d = new_pageinfo();
650 currentpage = sip->segpage;
651 }
652 pip = fip->pages.last->d;
653 } else {
654 if (fip->page0.last == NULL) {
655 plp = litem_append(&(fip->page0));
656 plp->last->d = new_pageinfo();
657 }
658 pip = fip->page0.last->d;
659 }
660 if (!sip->endofpageflag) {
661 slp = litem_append(&(pip->segments));
662 slp->last->d = sip;
663 sipavail = false;
664 }
665 if (!fip->sequentialaccess)
666 sip->datastart = streampos;
667 else
668 sip->datastart = sip->hdrend;
669 sip->dataend = sip->datastart + sip->segdatalen;
670 if (!fip->sequentialaccess
671 && (sip->pageinfoflag || sip->endofstripeflag))
672 xfseeko(fip->file, sip->datastart, SEEK_SET, fip->filename);
673 seekdist = (off_t) sip->segdatalen;
674 /* 7.4.8 Page information segment syntax */
675 if (sip->pageinfoflag) {
676 pip->pagenum = sip->segpage;
677 pip->width = read4bytes(fip->file);
678 pip->height = read4bytes(fip->file);
679 pip->xres = read4bytes(fip->file);
680 pip->yres = read4bytes(fip->file);
681 pip->pagesegmentflags = ygetc(fip->file);
682 /* 7.4.8.6 Page striping information */
683 pip->stripinginfo = read2bytes(fip->file);
684 seekdist -= 19;
685 }
686 if (sip->endofstripeflag) {
687 pip->stripedheight = read4bytes(fip->file);
688 seekdist -= 4;
689 }
690 if (!fip->sequentialaccess
691 && (sip->pageinfoflag || sip->endofstripeflag))
692 xfseeko(fip->file, sip->hdrend, SEEK_SET, fip->filename);
693 if (!fip->sequentialaccess)
694 streampos += sip->segdatalen;
695 if (fip->sequentialaccess)
696 xfseeko(fip->file, seekdist, SEEK_CUR, fip->filename);
697 if (sip->endofpageflag && currentpage && (pip->stripinginfo >> 15))
698 pip->height = pip->stripedheight;
699 }
700 fip->phase = HAVEINFO;
701 if (sipavail)
702 xfree(sip);
703 xfclose(fip->file, fip->filename);
704 }
705
706 /**********************************************************************/
707
wr_jbig2(FILEINFO * fip,unsigned long page)708 static void wr_jbig2(FILEINFO * fip, unsigned long page)
709 {
710 LITEM *slip;
711 PAGEINFO *pip;
712 SEGINFO *sip;
713 off_t i;
714 if (page > 0) {
715 pip = find_pageinfo(&(fip->pages), page);
716 assert(pip != NULL);
717 pdf_puts("/Type /XObject\n");
718 pdf_puts("/Subtype /Image\n");
719 pdf_printf("/Width %i\n", pip->width);
720 pdf_printf("/Height %i\n", pip->height);
721 pdf_puts("/ColorSpace /DeviceGray\n");
722 pdf_puts("/BitsPerComponent 1\n");
723 pdf_printf("/Length %" LONGINTEGER_PRI "d\n",
724 (LONGINTEGER_TYPE) getstreamlen(pip->segments.first, true));
725 pdf_puts("/Filter [/JBIG2Decode]\n");
726 if (fip->page0.last != NULL) {
727 if (fip->pdfpage0objnum == 0) {
728 pdfcreateobj(0, 0);
729 fip->pdfpage0objnum = objptr;
730 }
731 pdf_printf("/DecodeParms [<< /JBIG2Globals %lu 0 R >>]\n",
732 fip->pdfpage0objnum);
733 }
734 } else {
735 pip = find_pageinfo(&(fip->page0), page);
736 assert(pip != NULL);
737 pdfbegindict(fip->pdfpage0objnum, 0);
738 pdf_printf("/Length %" LONGINTEGER_PRI "d\n",
739 (LONGINTEGER_TYPE) getstreamlen(pip->segments.first, false));
740 }
741 pdf_puts(">>\n");
742 pdf_puts("stream\n");
743 fip->file = xfopen(fip->filename, FOPEN_RBIN_MODE);
744 for (slip = pip->segments.first; slip != NULL; slip = slip->next) { /* loop over page segments */
745 sip = slip->d;
746 if (sip->isrefered || page > 0) {
747 xfseeko(fip->file, sip->hdrstart, SEEK_SET, fip->filename);
748 /* mark refered-to page 0 segments, change segpages > 1 to 1 */
749 writeseghdr(fip, sip);
750 xfseeko(fip->file, sip->datastart, SEEK_SET, fip->filename);
751 for (i = sip->datastart; i < sip->dataend; i++)
752 pdfout(ygetc(fip->file));
753 }
754 }
755 pdfendstream();
756 xfclose(fip->file, fip->filename);
757 }
758
759 /**********************************************************************/
760
read_jbig2_info(integer img)761 void read_jbig2_info(integer img)
762 {
763 FILEINFO *fip, tmp;
764 PAGEINFO *pip;
765 void **aa;
766 if (jbig2_ptr(img)->selected_page < 1)
767 pdftex_fail
768 ("read_jbig2_info(): page %d not in JBIG2 image file; page must be > 0",
769 (int) jbig2_ptr(img)->selected_page);
770 if (file_tree == NULL) {
771 file_tree = avl_create(comp_file_entry, NULL, &avl_xallocator);
772 assert(file_tree != NULL);
773 }
774 tmp.filename = img_name(img);
775 fip = (FILEINFO *) avl_find(file_tree, &tmp);
776 if (fip == NULL) {
777 fip = new_fileinfo();
778 fip->filename = xstrdup(img_name(img));
779 aa = avl_probe(file_tree, fip);
780 assert(aa != NULL);
781 }
782 if (fip->phase == INITIAL) {
783 rd_jbig2_info(fip);
784 pages_maketree(&(fip->pages));
785 if (fip->page0.last != NULL) {
786 pages_maketree(&(fip->page0));
787 pip = fip->page0.first->d;
788 segments_maketree(&(pip->segments));
789 }
790 }
791 pip = find_pageinfo(&(fip->pages), jbig2_ptr(img)->selected_page);
792 if (pip == NULL)
793 pdftex_fail("read_jbig2_info(): page %d not found in JBIG2 image file",
794 (int) jbig2_ptr(img)->selected_page);
795 img_pages(img) = fip->numofpages;
796 img_width(img) = pip->width;
797 img_height(img) = pip->height;
798 img_xres(img) = (int) (pip->xres * 0.0254 + 0.5);
799 img_yres(img) = (int) (pip->yres * 0.0254 + 0.5);
800 }
801
802 /**********************************************************************/
803
write_jbig2(integer img)804 void write_jbig2(integer img)
805 {
806 FILEINFO *fip, tmp;
807 PAGEINFO *pip;
808 assert(file_tree != NULL);
809 tmp.filename = img_name(img);
810 fip = (FILEINFO *) avl_find(file_tree, &tmp);
811 assert(fip != NULL);
812 assert(fip->phase == HAVEINFO); /* don't write before rd_jbig2_info() call */
813 pip = find_pageinfo(&(fip->pages), jbig2_ptr(img)->selected_page);
814 assert(pip != NULL);
815 wr_jbig2(fip, pip->pagenum);
816 }
817
818 /**********************************************************************/
819
flushjbig2page0objects(void)820 void flushjbig2page0objects(void)
821 {
822 FILEINFO *fip;
823 struct avl_traverser t;
824 if (file_tree != NULL) {
825 avl_t_init(&t, file_tree);
826 for (fip = avl_t_first(&t, file_tree); fip != NULL;
827 fip = avl_t_next(&t)) {
828 if (fip->page0.last != NULL)
829 wr_jbig2(fip, 0);
830 }
831 }
832 }
833
834 /**********************************************************************/
835