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