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