diff options
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/image/writejp2.w')
-rw-r--r-- | Build/source/texk/web2c/luatexdir/image/writejp2.w | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/luatexdir/image/writejp2.w b/Build/source/texk/web2c/luatexdir/image/writejp2.w new file mode 100644 index 00000000000..1d27f733c56 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/image/writejp2.w @@ -0,0 +1,282 @@ +% writejp2.w + +% Copyright 2011 Taco Hoekwater <taco@@luatex.org> +% Copyright 2011 Hartmut Henkel <hartmut@@luatex.org> + +% This file is part of LuaTeX. + +% LuaTeX is free software; you can redistribute it and/or modify it under +% the terms of the GNU General Public License as published by the Free +% Software Foundation; either version 2 of the License, or (at your +% option) any later version. + +% LuaTeX is distributed in the hope that it will be useful, but WITHOUT +% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +% FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +% License for more details. + +% You should have received a copy of the GNU General Public License along +% with LuaTeX; if not, see <http://www.gnu.org/licenses/>. + +@ @c +static const char _svn_version[] = + "$Id: writejp2.w 4133 2011-04-11 16:54:11Z oneiros $ " + "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.66.0/source/texk/web2c/luatexdir/image/writejp2.w $"; + +@ Basic JPEG~2000 image support. Section and Table references below: +Information technology --- JPEG~2000 image coding system: Core coding system. +ISO/IEC 15444-1, Second edition, 2004-09-15, file |15444-1annexi.pdf|. + +@c +#include <math.h> +#include <assert.h> +#include "ptexlib.h" +#include "image/image.h" +#include "image/writejp2.h" +#include "image/writejbig2.h" /* read2bytes(), read4bytes() */ + +/* Table 1.2 -- Defined boxes */ +#define BOX_JP 0x6A502020 +#define BOX_FTYP 0x66747970 +#define BOX_JP2H 0x6a703268 +#define BOX_IHDR 0x69686472 +#define BOX_BPCC 0x62706363 +#define BOX_COLR 0x636D6170 +#define BOX_CDEF 0x63646566 +#define BOX_RES 0x72657320 +#define BOX_RESC 0x72657363 +#define BOX_RESD 0x72657364 +#define BOX_JP2C 0x6A703263 + +/* 1.4 Box definition */ +typedef struct { + unsigned long long lbox; + unsigned int tbox; +} hdr_struct; + +static unsigned long long read8bytes(FILE * f) +{ + unsigned long long l = read4bytes(f); + l = (l << 32) + read4bytes(f); + return l; +} + +static hdr_struct read_boxhdr(image_dict * idict) +{ + hdr_struct hdr; + hdr.lbox = read4bytes(img_file(idict)); + hdr.tbox = read4bytes(img_file(idict)); + if (hdr.lbox == 1) + hdr.lbox = read8bytes(img_file(idict)); + if (hdr.lbox == 0 && hdr.tbox != BOX_JP2C) + pdftex_fail("reading JP2 image failed (LBox == 0)"); + return hdr; +} + +/* 1.5.3.1 Image Header box */ +static void scan_ihdr(image_dict * idict) +{ + unsigned int height, width, nc; + unsigned char bpc, c, unkc, ipr; + height = read4bytes(img_file(idict)); + width = read4bytes(img_file(idict)); + img_ysize(idict) = (int) height; + img_xsize(idict) = (int) width; + nc = read2bytes(img_file(idict)); + bpc = (unsigned char) xgetc(img_file(idict)); + img_colordepth(idict) = bpc + 1; + c = (unsigned char) xgetc(img_file(idict)); + unkc = (unsigned char) xgetc(img_file(idict)); + ipr = (unsigned char) xgetc(img_file(idict)); +} + +/* 1.5.3.7.1 Capture Resolution box */ +/* 1.5.3.7.2 Default Display Resolution box */ +static void scan_resc_resd(image_dict * idict) +{ + unsigned int vr_n, vr_d, hr_n, hr_d; + unsigned char vr_e, hr_e; + double hr_, vr_; + vr_n = read2bytes(img_file(idict)); + vr_d = read2bytes(img_file(idict)); + hr_n = read2bytes(img_file(idict)); + hr_d = read2bytes(img_file(idict)); + vr_e = (unsigned char) xgetc(img_file(idict)); + hr_e = (unsigned char) xgetc(img_file(idict)); + hr_ = ((double) hr_n / hr_d) * exp(hr_e * log(10.0)) * 0.0254; + vr_ = ((double) vr_n / vr_d) * exp(vr_e * log(10.0)) * 0.0254; + img_xres(idict) = (int) (hr_ + 0.5); + img_yres(idict) = (int) (vr_ + 0.5); +} + +/* 1.5.3.7 Resolution box (superbox) */ +static void scan_res(image_dict * idict, unsigned long long epos_s) +{ + hdr_struct hdr; + unsigned long long spos, epos; + epos = xftell(img_file(idict), img_filepath(idict)); + while (1) { + spos = epos; + hdr = read_boxhdr(idict); + epos = spos + hdr.lbox; + switch (hdr.tbox) { + case (BOX_RESC): + /* arbitrarily: let BOX_RESD have precedence */ + if (img_xres(idict) == 0 && img_yres(idict) == 0) { + scan_resc_resd(idict); + if (xftell(img_file(idict), img_filepath(idict)) != (long)epos) + pdftex_fail + ("reading JP2 image failed (resc box size inconsistent)"); + } + break; + case (BOX_RESD): + scan_resc_resd(idict); + if (xftell(img_file(idict), img_filepath(idict)) != (long)epos) + pdftex_fail + ("reading JP2 image failed (resd box size inconsistent)"); + break; + default:; + } + if (epos > epos_s) + pdftex_fail("reading JP2 image failed (res box size inconsistent)"); + if (epos == epos_s) + break; + xfseek(img_file(idict), (long) epos, SEEK_SET, img_filepath(idict)); + } +} + +/* 1.5.3 JP2 Header box (superbox) */ +static boolean scan_jp2h(image_dict * idict, unsigned long long epos_s) +{ + boolean ihdr_found = false; + hdr_struct hdr; + unsigned long long spos, epos; + epos = xftell(img_file(idict), img_filepath(idict)); + while (1) { + spos = epos; + hdr = read_boxhdr(idict); + epos = spos + hdr.lbox; + switch (hdr.tbox) { + case (BOX_IHDR): + scan_ihdr(idict); + if (xftell(img_file(idict), img_filepath(idict)) != (long)epos) + pdftex_fail + ("reading JP2 image failed (ihdr box size inconsistent)"); + ihdr_found = true; + break; + case (BOX_RES): + scan_res(idict, epos); + break; + default:; + } + if (epos > epos_s) + pdftex_fail + ("reading JP2 image failed (jp2h box size inconsistent)"); + if (epos == epos_s) + break; + xfseek(img_file(idict), (long) epos, SEEK_SET, img_filepath(idict)); + } + return ihdr_found; +} + +static void close_and_cleanup_jp2(image_dict * idict) +{ + assert(idict != NULL); + assert(img_file(idict) != NULL); + assert(img_filepath(idict) != NULL); + xfclose(img_file(idict), img_filepath(idict)); + img_file(idict) = NULL; + assert(img_jp2_ptr(idict) != NULL); + xfree(img_jp2_ptr(idict)); +} + +void read_jp2_info(image_dict * idict, img_readtype_e readtype) +{ + boolean ihdr_found = false; + hdr_struct hdr; + unsigned long long spos, epos; + assert(img_type(idict) == IMG_TYPE_JP2); + img_totalpages(idict) = 1; + img_pagenum(idict) = 1; + img_xres(idict) = img_yres(idict) = 0; + assert(img_file(idict) == NULL); + img_file(idict) = xfopen(img_filepath(idict), FOPEN_RBIN_MODE); + assert(img_jp2_ptr(idict) == NULL); + img_jp2_ptr(idict) = xtalloc(1, jp2_img_struct); + xfseek(img_file(idict), 0, SEEK_END, img_filepath(idict)); + img_jp2_ptr(idict)->length = + (int) xftell(img_file(idict), img_filepath(idict)); + xfseek(img_file(idict), 0, SEEK_SET, img_filepath(idict)); + + assert(sizeof(unsigned long long) >= 8); + spos = epos = 0; + + /* 1.5.1 JPEG 2000 Signature box */ + hdr = read_boxhdr(idict); + assert(hdr.tbox == BOX_JP); /* has already been checked */ + epos = spos + hdr.lbox; + xfseek(img_file(idict), (long) epos, SEEK_SET, img_filepath(idict)); + + /* 1.5.2 File Type box */ + spos = epos; + hdr = read_boxhdr(idict); + if (hdr.tbox != BOX_FTYP) + pdftex_fail("reading JP2 image failed (missing ftyp box)"); + epos = spos + hdr.lbox; + xfseek(img_file(idict), (long) epos, SEEK_SET, img_filepath(idict)); + + while (!ihdr_found) { + spos = epos; + hdr = read_boxhdr(idict); + epos = spos + hdr.lbox; + switch (hdr.tbox) { + case BOX_JP2H: + ihdr_found = scan_jp2h(idict, epos); + break; + case BOX_JP2C: + if (!ihdr_found) + pdftex_fail("reading JP2 image failed (no ihdr box found)"); + break; + default:; + } + xfseek(img_file(idict), (long) epos, SEEK_SET, img_filepath(idict)); + } + if (readtype == IMG_CLOSEINBETWEEN) + close_and_cleanup_jp2(idict); +} + +static void reopen_jp2(image_dict * idict) +{ + int width, height, xres, yres; + width = img_xsize(idict); + height = img_ysize(idict); + xres = img_xres(idict); + yres = img_yres(idict); + read_jp2_info(idict, IMG_KEEPOPEN); + if (width != img_xsize(idict) || height != img_ysize(idict) + || xres != img_xres(idict) || yres != img_yres(idict)) + pdftex_fail("writejp2: image dimensions have changed"); +} + +void write_jp2(PDF pdf, image_dict * idict) +{ + long unsigned l; + FILE *f; + assert(idict != NULL); + if (img_file(idict) == NULL) + reopen_jp2(idict); + xfseek(img_file(idict), 0, SEEK_SET, img_filepath(idict)); + assert(img_jp2_ptr(idict) != NULL); + pdf_puts(pdf, "/Type /XObject\n/Subtype /Image\n"); + if (img_attr(idict) != NULL && strlen(img_attr(idict)) > 0) + pdf_printf(pdf, "%s\n", img_attr(idict)); + pdf_printf(pdf, "/Width %i\n/Height %i\n/Length %i\n", + (int) img_xsize(idict), + (int) img_ysize(idict), (int) img_jp2_ptr(idict)->length); + pdf_puts(pdf, "/Filter /JPXDecode\n>>\nstream\n"); + for (l = (long unsigned int) img_jp2_ptr(idict)->length, f = + img_file(idict); l > 0; l--) + pdf_out(pdf, xgetc(f)); + pdf_end_stream(pdf); + close_and_cleanup_jp2(idict); +} |