summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/luatexdir/image/writejp2.w
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/image/writejp2.w')
-rw-r--r--Build/source/texk/web2c/luatexdir/image/writejp2.w282
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);
+}