summaryrefslogtreecommitdiff
path: root/Build/source/texk/dvipdf-x/xsrc/xbb.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/dvipdf-x/xsrc/xbb.c')
-rw-r--r--Build/source/texk/dvipdf-x/xsrc/xbb.c511
1 files changed, 511 insertions, 0 deletions
diff --git a/Build/source/texk/dvipdf-x/xsrc/xbb.c b/Build/source/texk/dvipdf-x/xsrc/xbb.c
new file mode 100644
index 00000000000..f447d3a0170
--- /dev/null
+++ b/Build/source/texk/dvipdf-x/xsrc/xbb.c
@@ -0,0 +1,511 @@
+/*
+
+ This is extractbb, a bounding box extraction program.
+
+ Copyright (C) 2008-2012 by Jin-Hwan Cho <chofchof@ktug.or.kr>
+
+ This program 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.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include "system.h"
+#include "mem.h"
+#include "error.h"
+#include "mfileio.h"
+#include "numbers.h"
+#include "pdfobj.h"
+#include "pdfparse.h"
+
+#include "config.h"
+
+#ifdef HAVE_LIBPNG
+#include <png.h>
+#endif
+
+#include "xbb.h"
+
+#define XBB_PROGRAM "extractbb"
+#define XBB_VERSION "Version 0.2"
+
+static int xbb_output_mode = XBB_OUTPUT;
+
+static void usage(void)
+{
+ fprintf (stderr, "%s, version %s, Copyright (C) 2008 by Jin-Hwan Cho\n",
+ XBB_PROGRAM, XBB_VERSION);
+ fprintf (stderr, "A bounding box extraction utility from PDF, PNG, and JPG.\n");
+ fprintf (stdout, "\nThis is free software; you can redistribute it and/or modify\n");
+ fprintf (stdout, "it under the terms of the GNU General Public License as published by\n");
+ fprintf (stdout, "the Free Software Foundation; either version 2 of the License, or\n");
+ fprintf (stdout, "(at your option) any later version.\n");
+ fprintf (stderr, "\nUsage: %s [-v] [-b] [-m|-x] [files]\n", XBB_PROGRAM);
+ fprintf (stderr, "\t-b\tWrite output file in binary mode\n");
+ if(xbb_output_mode == EBB_OUTPUT) {
+ fprintf (stderr, "\t-m\tOutput .bb file used in DVIPDFM (default)\n");
+ fprintf (stderr, "\t-x\tOutput .xbb file used in DVIPDFMx\n");
+ } else {
+ fprintf (stderr, "\t-m\tOutput .bb file used in DVIPDFM\n");
+ fprintf (stderr, "\t-x\tOutput .xbb file used in DVIPDFMx (default)\n");
+ }
+ fprintf (stderr, "\t-v\tVerbose\n");
+ exit(1);
+}
+
+static char verbose = 0;
+
+static void do_time(FILE *file)
+{
+ time_t current_time;
+ struct tm *bd_time;
+
+ time(&current_time);
+ bd_time = localtime(&current_time);
+ fprintf(file, "%%%%CreationDate: %s\n", asctime(bd_time));
+}
+
+const char *extensions[] = {
+ ".jpeg", ".JPEG", ".jpg", ".JPG", ".pdf", ".PDF", ".png", ".PNG"
+};
+
+static char *make_xbb_filename(const char *name)
+{
+ int i;
+ char *result;
+
+ for (i = 0; i < sizeof(extensions) / sizeof(extensions[0]); i++) {
+ if (strlen(extensions[i]) < strlen(name) &&
+ strncmp(name+strlen(name)-strlen(extensions[i]), extensions[i], strlen(extensions[i])) == 0)
+ break;
+ }
+ if (i == sizeof(extensions) / sizeof(extensions[0])) {
+ fprintf(stderr, "Warning: %s: Filename does not end in a recognizeable extension.\n", name);
+ result = NEW(strlen(name)+3, char);
+ strcpy(result, name);
+ } else { /* Remove extension */
+ result = NEW(strlen(name)+3-strlen(extensions[i])+1, char);
+ strncpy(result, name, strlen(name)-strlen(extensions[i]));
+ result[strlen(name)-strlen(extensions[i])] = 0;
+ }
+ strcat(result, (xbb_output_mode == XBB_OUTPUT ? ".xbb" : ".bb"));
+ return result;
+}
+
+static const char *xbb_file_mode = FOPEN_W_MODE;
+
+static void write_xbb(char *fname, int bbllx, int bblly, int bburx, int bbury)
+{
+ char *outname;
+ FILE *fp;
+
+ outname = make_xbb_filename(fname);
+ if ((fp = MFOPEN(outname, xbb_file_mode)) == NULL) {
+ fprintf(stderr, "Unable to open output file: %s\n", outname);
+ RELEASE(outname);
+ return;
+ }
+ if (verbose) {
+ fprintf(stderr, "Writing to %s: ", outname);
+ fprintf(stderr, "Bounding box: %d %d %d %d\n", bbllx, bblly, bburx, bbury);
+ }
+ fprintf(fp,"%%%%Title: %s\n", fname);
+ fprintf(fp,"%%%%Creator: %s %s\n", XBB_PROGRAM, XBB_VERSION);
+ fprintf(fp,"%%%%BoundingBox: %d %d %d %d\n", bbllx, bblly, bburx, bbury);
+ do_time(fp);
+ RELEASE(outname);
+ MFCLOSE(fp);
+}
+
+typedef enum {
+ JM_SOF0 = 0xc0, JM_SOF1 = 0xc1, JM_SOF2 = 0xc2, JM_SOF3 = 0xc3,
+ JM_SOF5 = 0xc5, JM_DHT = 0xc4, JM_SOF6 = 0xc6, JM_SOF7 = 0xc7,
+ JM_SOF9 = 0xc9, JM_SOF10 = 0xca, JM_SOF11 = 0xcb, JM_DAC = 0xcc,
+ JM_SOF13 = 0xcd, JM_SOF14 = 0xce, JM_SOF15 = 0xcf,
+
+ JM_RST0 = 0xd0, JM_RST1 = 0xd1, JM_RST2 = 0xd2, JM_RST3 = 0xd3,
+ JM_RST4 = 0xd4, JM_RST5 = 0xd5, JM_RST6 = 0xd6, JM_RST7 = 0xd7,
+
+ JM_SOI = 0xd8, JM_EOI = 0xd9, JM_SOS = 0xda, JM_DQT = 0xdb,
+ JM_DNL = 0xdc, JM_DRI = 0xdd, JM_DHP = 0xde, JM_EXP = 0xdf,
+
+ JM_APP0 = 0xe0, JM_APP2 = 0xe2, JM_APP14 = 0xee, JM_APP15 = 0xef,
+
+ JM_COM = 0xfe
+} JPEG_marker;
+
+static JPEG_marker JPEG_get_marker (FILE *fp)
+{
+ int c = fgetc(fp);
+ if (c != 255) return -1;
+ for (;;) {
+ c = fgetc(fp);
+ if (c < 0) return -1;
+ else if (c > 0 && c < 255) return c;
+ }
+ return -1;
+}
+
+static int check_for_jpeg (FILE *fp)
+{
+ unsigned char jpeg_sig[2];
+ rewind(fp);
+ if (fread(jpeg_sig, sizeof(unsigned char), 2, fp) != 2) return 0;
+ else if (jpeg_sig[0] != 0xff || jpeg_sig[1] != JM_SOI) return 0;
+ return 1;
+}
+
+static int jpeg_get_info (FILE *fp, int *width, int *height)
+{
+ JPEG_marker marker;
+ unsigned short length;
+ int count;
+ float xdensity = 1.0, ydensity = 1.0;
+ char app_sig[128];
+
+ if (!check_for_jpeg(fp)) {
+ rewind(fp);
+ return -1;
+ }
+ rewind(fp);
+ count = 0;
+ while ((marker = JPEG_get_marker(fp)) >= 0) {
+ if (marker == JM_SOI || (marker >= JM_RST0 && marker <= JM_RST7)) {
+ count++; continue;
+ }
+ length = get_unsigned_pair(fp) - 2;
+ switch (marker) {
+ case JM_SOF0: case JM_SOF1: case JM_SOF2: case JM_SOF3:
+ case JM_SOF5: case JM_SOF6: case JM_SOF7: case JM_SOF9:
+ case JM_SOF10: case JM_SOF11: case JM_SOF13: case JM_SOF14:
+ case JM_SOF15:
+ get_unsigned_byte(fp);
+ if (xbb_output_mode != XBB_OUTPUT) { /* EBB_OUTPUT */
+ xdensity = ydensity = 72.0 / 100.0;
+ }
+ *height = (int)(get_unsigned_pair(fp) * ydensity + 0.5);
+ *width = (int)(get_unsigned_pair(fp) * xdensity + 0.5);
+ return 0;
+ case JM_APP0:
+ if (length > 5) {
+ if (fread(app_sig, sizeof(char), 5, fp) != 5) return -1;
+ length -= 5;
+ if (!memcmp(app_sig, "JFIF\000", 5)) {
+ int units, xden, yden;
+ get_unsigned_pair(fp);
+ units = (int)get_unsigned_byte(fp);
+ xden = (int)get_unsigned_pair(fp);
+ yden = (int)get_unsigned_pair(fp);
+ switch (units) {
+ case 1: /* pixels per inch */
+ xdensity = 72.0 / xden;
+ ydensity = 72.0 / yden;
+ break;
+ case 2: /* pixels per centimeter */
+ xdensity = 72.0 / 2.54 / xden;
+ ydensity = 72.0 / 2.54 / yden;
+ break;
+ default:
+ break;
+ }
+ length -= 7;
+ }
+ }
+ seek_relative(fp, length);
+ break;
+ default:
+ seek_relative(fp, length);
+ break;
+ }
+ count++;
+ }
+ return -1;
+}
+
+static void do_jpeg (FILE *fp, char *filename)
+{
+ int width, height;
+
+ if (jpeg_get_info(fp, &width, &height) < 0) {
+ fprintf (stderr, "%s does not look like a JPEG file...\n", filename);
+ return;
+ }
+ write_xbb(filename, 0, 0, width, height);
+ return;
+}
+
+#ifdef HAVE_LIBPNG
+static int check_for_png (FILE *png_file)
+{
+ unsigned char sigbytes[4];
+ rewind (png_file);
+ if (fread(sigbytes, 1, sizeof(sigbytes), png_file) != sizeof(sigbytes) ||
+ (png_sig_cmp (sigbytes, 0, sizeof(sigbytes)))) return 0;
+ else return 1;
+}
+
+static int png_get_info(FILE *png_file, int *width, int *height)
+{
+ png_structp png_ptr;
+ png_infop png_info_ptr;
+ png_uint_32 xppm, yppm;
+
+ rewind(png_file);
+
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (png_ptr == NULL || (png_info_ptr = png_create_info_struct(png_ptr)) == NULL) {
+ if (png_ptr) png_destroy_read_struct(&png_ptr, NULL, NULL);
+ return -1;
+ }
+ png_init_io(png_ptr, png_file);
+ png_read_info(png_ptr, png_info_ptr);
+
+ *width = (int)png_get_image_width(png_ptr, png_info_ptr);
+ *height = (int)png_get_image_height(png_ptr, png_info_ptr);
+
+ if (xbb_output_mode == XBB_OUTPUT) {
+ xppm = png_get_x_pixels_per_meter(png_ptr, png_info_ptr);
+ yppm = png_get_y_pixels_per_meter(png_ptr, png_info_ptr);
+ if (xppm > 0)
+ *width = (int)(*width * 72.0 / 0.0254 / xppm + 0.5);
+ if (yppm > 0)
+ *height = (int)(*height * 72.0 / 0.0254 / yppm + 0.5);
+ } else { /* EBB_OUTPUT */
+ *width = (int)(*width * 72.0 / 100.0 + 0.5);
+ *height = (int)(*height * 72.0 / 100.0 + 0.5);
+ }
+ return 0;
+}
+
+static void do_png (FILE *fp, char *filename)
+{
+ int width, height;
+
+ if (png_get_info(fp, &width, &height) < 0) {
+ fprintf (stderr, "%s does not look like a PNG file...\n", filename);
+ return;
+ }
+ write_xbb(filename, 0, 0, width, height);
+ return;
+}
+#endif /* HAVE_LIBPNG */
+
+static int rect_equal (pdf_obj *rect1, pdf_obj *rect2)
+{
+ int i;
+ if (!rect1 || !rect2) return 0;
+ for (i = 0; i < 4; i++) {
+ if (pdf_number_value(pdf_get_array(rect1, i)) != pdf_number_value(pdf_get_array(rect2, i))) return 0;
+ }
+ return 1;
+}
+
+static int pdf_get_info (FILE *image_file, char *filename, int *llx, int *lly, int *urx, int *ury)
+{
+ pdf_obj *page_tree;
+ pdf_obj *bbox;
+ pdf_file *pf;
+
+ page_tree = NULL;
+ {
+ pdf_obj *trailer, *catalog;
+
+ pf = pdf_open(filename, image_file);
+ if (!pf)
+ return -1;
+
+ trailer = pdf_file_get_trailer(pf);
+
+ if (pdf_lookup_dict(trailer, "Encrypt")) {
+ WARN("This PDF document is encrypted.");
+ pdf_release_obj(trailer);
+ pdf_close(pf);
+ return -1;
+ }
+ catalog = pdf_deref_obj(pdf_lookup_dict(trailer, "Root"));
+ if (!catalog) {
+ WARN("Catalog isn't where I expect it.");
+ pdf_close(pf);
+ return -1;
+ }
+ pdf_release_obj(trailer);
+ page_tree = pdf_deref_obj(pdf_lookup_dict(catalog, "Pages"));
+ pdf_release_obj(catalog);
+ }
+ if (!page_tree) {
+ WARN("Page tree not found.");
+ pdf_close(pf);
+ return -1;
+ }
+ {
+ pdf_obj *kids_ref, *kids;
+ pdf_obj *crop_box;
+ pdf_obj *tmp;
+
+ tmp = pdf_lookup_dict(page_tree, "MediaBox");
+ bbox = tmp ? pdf_deref_obj(tmp) : NULL;
+ tmp = pdf_lookup_dict(page_tree, "CropBox");
+ crop_box = tmp ? pdf_deref_obj(tmp) : NULL;
+
+ while ((kids_ref = pdf_lookup_dict(page_tree, "Kids")) != NULL) {
+ kids = pdf_deref_obj(kids_ref);
+ pdf_release_obj(page_tree);
+ page_tree = pdf_deref_obj(pdf_get_array(kids, 0));
+ pdf_release_obj(kids);
+
+ if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "MediaBox")))) {
+ if (bbox)
+ pdf_release_obj(bbox);
+ bbox = tmp;
+ }
+ if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "BleedBox")))) {
+ if (!rect_equal(tmp, bbox)) {
+ if (bbox)
+ pdf_release_obj(bbox);
+ bbox = tmp;
+ } else
+ pdf_release_obj(tmp);
+ }
+ if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "TrimBox")))) {
+ if (!rect_equal(tmp, bbox)) {
+ if (bbox)
+ pdf_release_obj(bbox);
+ bbox = tmp;
+ } else
+ pdf_release_obj(tmp);
+ }
+ if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "ArtBox")))) {
+ if (!rect_equal(tmp, bbox)) {
+ if (bbox)
+ pdf_release_obj(bbox);
+ bbox = tmp;
+ } else
+ pdf_release_obj(tmp);
+ }
+ if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "CropBox")))) {
+ if (crop_box)
+ pdf_release_obj(crop_box);
+ crop_box = tmp;
+ }
+ }
+ if (crop_box) {
+ pdf_release_obj(bbox);
+ bbox = crop_box;
+ }
+ }
+ pdf_release_obj(page_tree);
+
+ if (!bbox) {
+ WARN("No BoundingBox information available.");
+ pdf_close(pf);
+ return -1;
+ }
+
+ *llx = (int)pdf_number_value(pdf_get_array(bbox, 0));
+ *lly = (int)pdf_number_value(pdf_get_array(bbox, 1));
+ *urx = (int)pdf_number_value(pdf_get_array(bbox, 2));
+ *ury = (int)pdf_number_value(pdf_get_array(bbox, 3));
+
+ pdf_release_obj(bbox);
+
+ pdf_close(pf);
+ return 0;
+}
+
+static void do_pdf (FILE *fp, char *filename)
+{
+ int llx, lly, urx, ury;
+
+ if (pdf_get_info(fp, filename, &llx, &lly, &urx, &ury) < 0) {
+ fprintf (stderr, "%s does not look like a PDF file...\n", filename);
+ return;
+ }
+ write_xbb(filename, llx, lly, urx, ury);
+ return;
+}
+
+int extractbb (int argc, char *argv[], int mode)
+{
+ xbb_output_mode = mode;
+
+ pdf_files_init();
+
+ pdf_set_version(5);
+
+ kpse_set_program_name(argv[0], NULL);
+
+ argc -= 1; argv += 1;
+ if (argc == 0)
+ usage();
+
+ while (argc > 0 && *argv[0] == '-') {
+ switch (*(argv[0]+1)) {
+ case 'b':
+ xbb_file_mode = FOPEN_WBIN_MODE;
+ argc -= 1; argv += 1;
+ break;
+ case 'm':
+ xbb_output_mode = EBB_OUTPUT;
+ argc -= 1; argv += 1;
+ break;
+ case 'x':
+ xbb_output_mode = XBB_OUTPUT;
+ argc -= 1; argv += 1;
+ break;
+ case 'v':
+ verbose = 1;
+ argc -= 1; argv += 1;
+ break;
+ case 'h':
+ usage();
+ argc -= 1; argv += 1;
+ break;
+ default:
+ usage();
+ }
+ }
+ for (; argc > 0; argc--, argv++) {
+ FILE *infile = NULL;
+ char *kpse_file_name;
+ if (!(kpse_file_name = kpse_find_pict(argv[0])) ||
+ (infile = MFOPEN(kpse_file_name, FOPEN_RBIN_MODE)) == NULL) {
+ fprintf(stderr, "Can't find file (%s)...skipping\n", argv[0]);
+ goto cont;
+ }
+ if (check_for_jpeg(infile)) {
+ do_jpeg(infile, kpse_file_name);
+ goto cont;
+ }
+ if (check_for_pdf(infile)) {
+ do_pdf(infile, kpse_file_name);
+ goto cont;
+ }
+#ifdef HAVE_LIBPNG
+ if (check_for_png(infile)) {
+ do_png(infile, kpse_file_name);
+ goto cont;
+ }
+#endif /* HAVE_LIBPNG */
+ fprintf(stderr, "Can't handle file type for file named %s\n", argv[0]);
+ cont:
+ if (kpse_file_name)
+ RELEASE(kpse_file_name);
+ if (infile)
+ MFCLOSE(infile);
+ }
+
+ pdf_files_close();
+
+ return 0;
+}