diff --git a/.gitmodules b/.gitmodules index 45ae3eaf5..f652a7490 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,3 +13,6 @@ [submodule "luajit-2.0"] path = luajit-2.0 url = http://luajit.org/git/luajit-2.0.git +[submodule "libk2pdfopt"] + path = libk2pdfopt + url = git://github.com/chrox/libk2pdfopt.git diff --git a/Makefile b/Makefile index 40904367a..6ef84fe1d 100644 --- a/Makefile +++ b/Makefile @@ -13,6 +13,7 @@ JPEGDIR=$(MUPDFDIR)/thirdparty/jpeg-9 LFSDIR=luafilesystem POPENNSDIR=popen-noshell +K2PDFOPTLIBDIR=libk2pdfopt # must point to directory with *.ttf fonts for crengine TTF_FONTS_DIR=$(MUPDFDIR)/fonts @@ -113,17 +114,18 @@ LUALIB := $(LUADIR)/src/libluajit.a POPENNSLIB := $(POPENNSDIR)/libpopen_noshell.a +K2PDFOPTLIB := $(K2PDFOPTLIBDIR)/libk2pdfopt.a + all: kpdfview extr VERSION?=$(shell git describe HEAD) -kpdfview: kpdfview.o einkfb.o pdf.o k2pdfopt.o blitbuffer.o drawcontext.o koptcontext.o input.o $(POPENNSLIB) util.o ft.o lfs.o mupdfimg.o $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) djvu.o $(DJVULIBS) cre.o $(CRENGINELIBS) pic.o pic_jpeg.o +kpdfview: kpdfview.o einkfb.o pdf.o blitbuffer.o drawcontext.o koptcontext.o input.o $(POPENNSLIB) util.o ft.o lfs.o mupdfimg.o $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) djvu.o $(DJVULIBS) cre.o $(CRENGINELIBS) pic.o pic_jpeg.o echo $(VERSION) > git-rev $(CC) \ $(CFLAGS) \ kpdfview.o \ einkfb.o \ pdf.o \ - k2pdfopt.o \ blitbuffer.o \ drawcontext.o \ koptcontext.o \ @@ -133,6 +135,7 @@ kpdfview: kpdfview.o einkfb.o pdf.o k2pdfopt.o blitbuffer.o drawcontext.o koptco ft.o \ lfs.o \ mupdfimg.o \ + $(K2PDFOPTLIB) \ $(MUPDFLIBS) \ $(THIRDPARTYLIBS) \ $(LUALIB) \ @@ -166,9 +169,6 @@ ft.o: %.o: %.c $(THIRDPARTYLIBS) kpdfview.o pdf.o blitbuffer.o util.o drawcontext.o koptcontext.o einkfb.o input.o mupdfimg.o: %.o: %.c $(CC) -c $(KPDFREADER_CFLAGS) $(EMU_CFLAGS) -I$(LFSDIR)/src $< -o $@ -k2pdfopt.o: %.o: %.c - $(CC) -c -I$(MUPDFDIR)/ -I$(DJVUDIR)/ $(CFLAGS) $< -o $@ - djvu.o: %.o: %.c $(CC) -c $(KPDFREADER_CFLAGS) -I$(DJVUDIR)/ $< -o $@ @@ -232,6 +232,7 @@ cleanthirdparty: rm -f $(MUPDFDIR)/fontdump.host rm -f $(MUPDFDIR)/cmapdump.host $(MAKE) -C $(POPENNSDIR) clean + $(MAKE) -C $(K2PDFOPTLIBDIR) clean $(MUPDFDIR)/fontdump.host: CFLAGS="$(HOSTCFLAGS)" $(MAKE) -C mupdf build="release" CC="$(HOSTCC)" $(MUPDFTARGET)/fontdump @@ -274,7 +275,10 @@ endif $(POPENNSLIB): $(MAKE) -C $(POPENNSDIR) CC="$(CC)" AR="$(AR)" -thirdparty: $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) $(DJVULIBS) $(CRENGINELIBS) $(POPENNSLIB) +$(K2PDFOPTLIB): + $(MAKE) -C $(K2PDFOPTLIBDIR) BUILDMODE=static CC="$(CC)" CFLAGS="$(CFLAGS) -I../$(DJVUDIR)/ -I../$(MUPDFDIR)/" AR="$(AR)" + +thirdparty: $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) $(DJVULIBS) $(CRENGINELIBS) $(POPENNSLIB) $(K2PDFOPTLIB) INSTALL_DIR=kindlepdfviewer diff --git a/k2pdfopt.c b/k2pdfopt.c deleted file mode 100644 index 56503f3f4..000000000 --- a/k2pdfopt.c +++ /dev/null @@ -1,7353 +0,0 @@ -/* - ** k2pdfopt.c K2pdfopt optimizes PDF/DJVU files for mobile e-readers - ** (e.g. the Kindle) and smartphones. It works well on - ** multi-column PDF/DJVU files. K2pdfopt is freeware. - ** - ** Copyright (C) 2012 http://willus.com - ** - ** This program is free software: you can redistribute it and/or modify - ** it under the terms of the GNU Affero General Public License as - ** published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. - ** - ** You should have received a copy of the GNU Affero General Public License - ** along with this program. If not, see . - ** - /* - ** WILLUSDEBUGX flags: - ** 1 = Generic - ** 2 = breakinfo row analysis - ** 4 = word wrapping - ** 8 = word wrapping II - ** 16 = hyphens - ** 32 = OCR - ** - */ -// #define WILLUSDEBUGX 32 -// #define WILLUSDEBUG -#include -#include -#include -#include -#include -#include -#include "k2pdfopt.h" - -#define HAVE_MUPDF - -#define VERSION "v1.60" -#define GRAYLEVEL(r,g,b) ((int)(((r)*0.3+(g)*0.59+(b)*0.11)*1.002)) -#if (defined(WIN32) || defined(WIN64)) -#define TTEXT_BOLD ANSI_WHITE -#define TTEXT_NORMAL ANSI_NORMAL -#define TTEXT_BOLD2 ANSI_YELLOW -#define TTEXT_INPUT ANSI_GREEN -#define TTEXT_WARN ANSI_RED -#define TTEXT_HEADER ANSI_CYAN -#define TTEXT_MAGENTA ANSI_MAGENTA -#else -#define TTEXT_BOLD "\x1b[0m\x1b[34m" -#define TTEXT_NORMAL "\x1b[0m" -#define TTEXT_BOLD2 "\x1b[0m\x1b[33m" -#define TTEXT_INPUT "\x1b[0m\x1b[32m" -#define TTEXT_WARN "\x1b[0m\x1b[31m" -#define TTEXT_HEADER "\x1b[0m\x1b[36m" -#define TTEXT_MAGENTA "\x1b[0m\x1b[35m" -#endif - -#ifndef __ANSI_H__ -#define ANSI_RED "\x1b[1m\x1b[31m" -#define ANSI_GREEN "\x1b[1m\x1b[32m" -#define ANSI_YELLOW "\x1b[1m\x1b[33m" -#define ANSI_BROWN "\x1b[0m\x1b[33m" -#define ANSI_BLUE "\x1b[1m\x1b[34m" -#define ANSI_MAGENTA "\x1b[1m\x1b[35m" -#define ANSI_CYAN "\x1b[1m\x1b[36m" -#define ANSI_WHITE "\x1b[1m\x1b[37m" -#define ANSI_NORMAL "\x1b[0m\x1b[37m" -#define ANSI_SAVE_CURSOR "\x1b[s" -#define ANSI_RESTORE_CURSOR "\x1b[u" -#define ANSI_CLEAR_TO_END "\x1b[K" -#define ANSI_BEGIN_LINE "\x1b[80D" -#define ANSI_UP_ONE_LINE "\x1b[1A" -#define ANSI_HOME "\x1b[2J\x1b[0;0;H" -#define __ANSI_H__ -#endif - -/* bmp.c */ -#define WILLUSBITMAP_TYPE_NATIVE 0 -#define WILLUSBITMAP_TYPE_WIN32 1 -#define BOUND(x,xmin,xmax) if ((x)<(xmin)) (x)=(xmin); else { if ((x)>(xmax)) (x)=(xmax); } - -#ifdef PI -#undef PI -#endif -/* - ** Constants from the front of the CRC standard math tables - ** (Accuracy = 50 digits) - */ -#define PI 3.14159265358979323846264338327950288419716939937511 -#define SQRT2 1.41421356237309504880168872420969807856967187537695 -#define SQRT3 1.73205080756887729352744634150587236694280525381039 -#define LOG10E 0.43429448190325182765112891891660508229439700580367 -#define DBPERNEP (20.*LOG10E) - -#define SRC_TYPE_PDF 1 -#define SRC_TYPE_DJVU 2 -#define SRC_TYPE_OTHER 3 - -/* DATA STRUCTURES */ - -typedef struct { - int page; /* Source page */ - double rot_deg; /* Source rotation (happens first) */ - double x0, y0; /* x0,y0, in points, of lower left point on rectangle */ - double w, h; /* width and height of rectangle in points */ - double scale; /* Scale rectangle by this factor on destination page */ - double x1, y1; /* (x,y) position of lower left point on destination page, in points */ -} PDFBOX; - -typedef struct { - PDFBOX *box; - int n; - int na; -} PDFBOXES; - -typedef struct { - int pageno; /* Source page number */ - double page_rot_deg; /* Source page rotation */ - PDFBOXES boxes; -} PAGEINFO; - -typedef struct { - int pageno; - double finerot_deg; - double rot_deg; - double page_width_pts; - double page_height_pts; - double x0_pts; - double y0_pts; - double crop_width_pts; - double crop_height_pts; -} WPDFSRCBOX; - -typedef struct { - int dstpage; /* Dest page */ - double x0, y0; /* x0,y0, in points, of lower left point on transformed source page */ - double w, h; /* width and height of transformed source rectangle in points */ - double x1, y1; /* (x,y) position of lower left source point on destination page, in points */ - double scale; /* Scale rectangle by this factor on destination page */ - double srcrot_deg; /* Rotation of source selection rectangle about x0,y0 */ - double dstrot_deg; /* Rotation of destination rectangle about x1,y1 */ - double userx, usery; /* For user use */ - double src_width_pts, src_height_pts; /* Width/height of transformed source page in points */ - double dst_width_pts, dst_height_pts; /* Width/height of device page in points */ - WPDFSRCBOX srcbox; -} WPDFBOX; - -typedef struct { - WPDFBOX *box; - int n; - int na; -} WPDFBOXES; - -typedef struct { - char producer[128]; /* Producer */ - double width_pts; /* Destination page width in pts. */ - double height_pts; /* Destination page height in pts. */ - int srcpage; /* Ignored by wmupdf_remake_pdf */ - double srcpage_rot_deg; /* Ignored by wmupdf_remake_pdf */ - double srcpage_fine_rot_deg; /* Ignored by wmupdf_remake_pdf */ - WPDFBOXES boxes; -} WPDFPAGEINFO; - -typedef struct { - int ch; /* Hyphen starting point -- < 0 for no hyphen */ - int c2; /* End of end region if hyphen is erased */ - int r1; /* Top of hyphen */ - int r2; /* Bottom of hyphen */ -} HYPHENINFO; - -typedef struct { - int c1, c2; /* Left and right columns */ - int r1, r2; /* Top and bottom of region in pixels */ - int rowbase; /* Baseline of row */ - int gap; /* Gap to next region in pixels */ - int rowheight; /* text + gap */ - int capheight; - int h5050; - int lcheight; - HYPHENINFO hyphen; -} TEXTROW; - -typedef struct { - TEXTROW *textrow; - int rhmean_pixels; /* Mean row height (text) */ - int centered; /* Is this set of rows centered? */ - int n, na; -} BREAKINFO; - -typedef struct { - int red[256]; - int green[256]; - int blue[256]; - unsigned char *data; /* Top to bottom in native type, bottom to */ - /* top in Win32 type. */ - int width; /* Width of image in pixels */ - int height; /* Height of image in pixels */ - int bpp; /* Bits per pixel (only 8 or 24 allowed) */ - int size_allocated; - int type; /* See defines above for WILLUSBITMAP_TYPE_... */ -} WILLUSBITMAP; - -typedef struct { - int r1, r2; /* row position from top of bmp, inclusive */ - int c1, c2; /* column positions, inclusive */ - int rowbase; /* Baseline of text row */ - int capheight; /* capital letter height */ - int h5050; - int lcheight; /* lower-case letter height */ - int bgcolor; /* 0 - 255 */ - HYPHENINFO hyphen; - WILLUSBITMAP *bmp; - WILLUSBITMAP *bmp8; - WILLUSBITMAP *marked; -} BMPREGION; - -typedef struct { - WILLUSBITMAP bmp; - int rows; - int published_pages; - int bgcolor; - int fit_to_page; - int wordcount; - char debugfolder[256]; -} MASTERINFO; - -static int verbose = 0; -static int debug = 0; - -#define DEFAULT_WIDTH 600 -#define DEFAULT_HEIGHT 800 -#define MIN_REGION_WIDTH_INCHES 1.0 -#define SRCROT_AUTO -999. -#define SRCROT_AUTOEP -998. - -/* - ** Blank Area Threshold Widths--average black pixel width, in inches, that - ** prevents a region from being determined as "blank" or clear. - */ -static int src_rot = 0; -static double gtc_in = .005; // detecting gap between columns -static double gtr_in = .006; // detecting gap between rows -static double gtw_in = .0015; // detecting gap between words -// static double gtm_in=.005; // detecting margins for trimming -static int src_left_to_right = 1; -static int src_whitethresh = -1; -static int dst_dpi = 167; -static int fit_columns = 1; -static int src_dpi = 300; -static int dst_width = DEFAULT_WIDTH; /* Full device width in pixels */ -static int dst_height = DEFAULT_HEIGHT; -static int dst_userwidth = DEFAULT_WIDTH; -static int dst_userheight = DEFAULT_HEIGHT; -static int dst_justify = -1; // 0 = left, 1 = center -static int dst_figure_justify = -1; // -1 = same as dst_justify. 0=left 1=center 2=right -static double dst_min_figure_height_in = 0.75; -static int dst_fulljustify = -1; // 0 = no, 1 = yes -static int dst_color = 0; -static int dst_landscape = 0; -static int src_autostraighten = 0; -static double dst_mar = 0.06; -static double dst_martop = -1.0; -static double dst_marbot = -1.0; -static double dst_marleft = -1.0; -static double dst_marright = -1.0; -static double min_column_gap_inches = 0.1; -static double max_column_gap_inches = 1.5; // max gap between columns -static double min_column_height_inches = 1.5; -static double mar_top = -1.0; -static double mar_bot = -1.0; -static double mar_left = -1.0; -static double mar_right = -1.0; -static double max_region_width_inches = 3.6; /* Max viewable width (device width minus margins) */ -static int max_columns = 2; -static double column_gap_range = 0.33; -static double column_offset_max = 0.2; -static double column_row_gap_height_in = 1. / 72.; -static int text_wrap = 1; -static double word_spacing = 0.375; -static double display_width_inches = 3.6; /* Device width = dst_width / dst_dpi */ -static int column_fitted = 0; -static double lm_org, bm_org, tm_org, rm_org, dpi_org; -static double contrast_max = 2.0; -static int show_marked_source = 0; -static int use_crop_boxes = 1; -static int preserve_indentation = 1; -static double defect_size_pts = 1.0; -static double max_vertical_gap_inches = 0.25; -static double vertical_multiplier = 1.0; -static double vertical_line_spacing = -1.2; -static double vertical_break_threshold = 1.75; -static int src_trim = 1; -static int erase_vertical_lines = 0; -static int k2_hyphen_detect = 1; -static int dst_fit_to_page = 0; -static int src_grid_rows = -1; -static int src_grid_cols = -1; -static int src_grid_overlap_percentage = 2; -static int src_grid_order = 0; /* 0=down then across, 1=across then down */ -/* - ** Undocumented cmd-line args - */ -static double no_wrap_ar_limit = 0.2; /* -arlim */ -static double no_wrap_height_limit_inches = 0.55; /* -whmax */ -static double little_piece_threshold_inches = 0.5; /* -rwmin */ -/* - ** Keeping track of vertical gaps - */ -static double last_scale_factor_internal = -1.0; -/* indicates desired vert. gap before next region is added. */ -static int last_rowbase_internal; /* Pixels between last text row baseline and current end */ -/* of destination bitmap. */ -static int beginning_gap_internal = -1; -static int last_h5050_internal = -1; -static int just_flushed_internal = 0; -static int gap_override_internal; /* If > 0, apply this gap in wrapbmp_flush() and then reset. */ - -void adjust_params_init(void); -void set_region_widths(void); -static void mark_source_page(BMPREGION *region, int caller_id, int mark_flags); -static void fit_column_to_screen(double column_width_inches); -static void restore_output_dpi(void); -void adjust_contrast(WILLUSBITMAP *src, WILLUSBITMAP *srcgrey, int *white); -static int bmpregion_row_black_count(BMPREGION *region, int r0); -static void bmpregion_row_histogram(BMPREGION *region); -static int bmpregion_find_multicolumn_divider(BMPREGION *region, - int *row_black_count, BMPREGION *pageregion, int *npr, int *colcount, - int *rowcount); -static int bmpregion_column_height_and_gap_test(BMPREGION *column, - BMPREGION *region, int r1, int r2, int cmid, int *colcount, - int *rowcount); -static int bmpregion_is_clear(BMPREGION *region, int *row_is_clear, - double gt_in); -static void bmpregion_source_page_add(BMPREGION *region, MASTERINFO *masterinfo, - int level, WPDFPAGEINFO *pageinfo, int colgap0_pixels); -static void bmpregion_vertically_break(BMPREGION *region, - MASTERINFO *masterinfo, int allow_text_wrapping, double force_scale, - int *colcount, int *rowcount, WPDFPAGEINFO *pageinfo, int colgap_pixels, - int ncols); -static void bmpregion_add(BMPREGION *region, BREAKINFO *breakinfo, - MASTERINFO *masterinfo, int allow_text_wrapping, int trim_flags, - int allow_vertical_breaks, double force_scale, int justify_flags, - int caller_id, int *colcount, int *rowcount, WPDFPAGEINFO *pageinfo, - int mark_flags, int rowbase_delta); -static void dst_add_gap_src_pixels(char *caller, MASTERINFO *masterinfo, - int pixels); -static void dst_add_gap(MASTERINFO *masterinfo, double inches); -static void bmp_src_to_dst(MASTERINFO *masterinfo, WILLUSBITMAP *src, - WPDFPAGEINFO *pageinfo, int justification_flags, int whitethresh, - int nocr, int dpi); -static void bmp_fully_justify(WILLUSBITMAP *jbmp, WILLUSBITMAP *src, int nocr, - int whitethresh, int just); -#ifdef HAVE_OCR -static void ocrwords_fill_in(OCRWORDS *words,WILLUSBITMAP *src,int whitethresh,int dpi); -#endif -static void bmpregion_trim_margins(BMPREGION *region, int *colcount0, - int *rowcount0, int flags); -static void bmpregion_hyphen_detect(BMPREGION *region); -#if (WILLUSDEBUGX & 6) -static void breakinfo_echo(BREAKINFO *bi); -#endif -#if (defined(WILLUSDEBUGX) || defined(WILLUSDEBUG)) -static void bmpregion_write(BMPREGION *region,char *filename); -#endif -static int height2_calc(int *rc, int n); -static void trim_to(int *count, int *i1, int i2, double gaplen); -static void bmpregion_analyze_justification_and_line_spacing(BMPREGION *region, - BREAKINFO *breakinfo, MASTERINFO *masterinfo, int *colcount, - int *rowcount, WPDFPAGEINFO *pageinfo, int allow_text_wrapping, - double force_scale); -static int bmpregion_is_centered(BMPREGION *region, BREAKINFO *breakinfo, - int i1, int i2, int *textheight); -static double median_val(double *x, int n); -static void bmpregion_find_vertical_breaks(BMPREGION *region, - BREAKINFO *breakinfo, int *colcount, int *rowcount, double apsize_in); -static void textrow_assign_bmpregion(TEXTROW *textrow, BMPREGION *region); -static void breakinfo_compute_row_gaps(BREAKINFO *breakinfo, int r2); -static void breakinfo_compute_col_gaps(BREAKINFO *breakinfo, int c2); -static void breakinfo_remove_small_col_gaps(BREAKINFO *breakinfo, int lcheight, - double mingap); -static void breakinfo_remove_small_rows(BREAKINFO *breakinfo, double fracrh, - double fracgap, BMPREGION *region, int *colcount, int *rowcount); -static void breakinfo_alloc(int index, BREAKINFO *breakinfo, int nrows); -static void breakinfo_free(int index, BREAKINFO *breakinfo); -static void breakinfo_sort_by_gap(BREAKINFO *breakinfo); -static void breakinfo_sort_by_row_position(BREAKINFO *breakinfo); -static void bmpregion_one_row_find_breaks(BMPREGION *region, - BREAKINFO *breakinfo, int *colcount, int *rowcount, int add_to_dbase); -void wrapbmp_init(void); -static int wrapbmp_ends_in_hyphen(void); -static void wrapbmp_set_color(int is_color); -static void wrapbmp_free(void); -static void wrapbmp_set_maxgap(int value); -static int wrapbmp_width(void); -static int wrapbmp_remaining(void); -static void wrapbmp_add(BMPREGION *region, int gap, int line_spacing, int rbase, - int gio, int justification_flags); -static void wrapbmp_flush(MASTERINFO *masterinfo, int allow_full_justify, - WPDFPAGEINFO *pageinfo, int use_bgi); -static void wrapbmp_hyphen_erase(void); -static void bmpregion_one_row_wrap_and_add(BMPREGION *region, - BREAKINFO *breakinfo, int index, int i0, int i1, MASTERINFO *masterinfo, - int justflags, int *colcount, int *rowcount, WPDFPAGEINFO *pageinfo, - int rheight, int mean_row_gap, int rowbase, int marking_flags, int pi); -static void white_margins(WILLUSBITMAP *src, WILLUSBITMAP *srcgrey); -static void get_white_margins(BMPREGION *region); -/* Bitmap orientation detection functions */ -static double bitmap_orientation(WILLUSBITMAP *bmp); -static double bmp_inflections_vertical(WILLUSBITMAP *srcgrey, int ndivisions, - int delta, int *wthresh); -static double bmp_inflections_horizontal(WILLUSBITMAP *srcgrey, int ndivisions, - int delta, int *wthresh); -static int inflection_count(double *x, int n, int delta, int *wthresh); -static void pdfboxes_init(PDFBOXES *boxes); -static void pdfboxes_free(PDFBOXES *boxes); -/* - static void pdfboxes_add_box(PDFBOXES *boxes,PDFBOX *box); - static void pdfboxes_delete(PDFBOXES *boxes,int n); - */ -static void word_gaps_add(BREAKINFO *breakinfo, int lcheight, - double *median_gap); -static void bmp_detect_vertical_lines(WILLUSBITMAP *bmp, WILLUSBITMAP *cbmp, - double dpi, double minwidth_in, double maxwidth_in, double minheight_in, - double anglemax_deg, int white_thresh); -static int vert_line_erase(WILLUSBITMAP *bmp, WILLUSBITMAP *cbmp, - WILLUSBITMAP *tmp, int row0, int col0, double tanthx, - double minheight_in, double minwidth_in, double maxwidth_in, - int white_thresh); -static void willus_dmem_alloc_warn(int index, void **ptr, int size, - char *funcname, int exitcode); -static void willus_dmem_free(int index, double **ptr, char *funcname); -static int willus_mem_alloc_warn(void **ptr, int size, char *name, int exitcode); -static void willus_mem_free(double **ptr, char *name); -static void sortd(double *x, int n); -static void sorti(int *x, int n); -static void bmp_init(WILLUSBITMAP *bmap); -static int bmp_alloc(WILLUSBITMAP *bmap); -static void bmp_free(WILLUSBITMAP *bmap); -static int bmp_copy(WILLUSBITMAP *dest, WILLUSBITMAP *src); -static void bmp_fill(WILLUSBITMAP *bmp,int r,int g,int b); -static int bmp_bytewidth(WILLUSBITMAP *bmp); -static unsigned char *bmp_rowptr_from_top(WILLUSBITMAP *bmp, int row); -static void bmp_more_rows(WILLUSBITMAP *bmp, double ratio, int pixval); -static int bmp_is_grayscale(WILLUSBITMAP *bmp); -static int bmp_resample(WILLUSBITMAP *dest, WILLUSBITMAP *src, double x1, - double y1, double x2, double y2, int newwidth, int newheight); -static void bmp_contrast_adjust(WILLUSBITMAP *dest,WILLUSBITMAP *src,double contrast); -static void bmp_convert_to_greyscale_ex(WILLUSBITMAP *dst, WILLUSBITMAP *src); -static double bmp_autostraighten(WILLUSBITMAP *src, WILLUSBITMAP *srcgrey, int white, - double maxdegrees, double mindegrees, int debug); -static int bmp_rotate_right_angle(WILLUSBITMAP *bmp, int degrees); -static int bmpmupdf_pixmap_to_bmp(WILLUSBITMAP *bmp, fz_context *ctx, - fz_pixmap *pixmap); -static void handle(int wait, ddjvu_context_t *ctx); -static void wpdfboxes_init(WPDFBOXES *boxes); -static void wpdfboxes_free(WPDFBOXES *boxes); -static void wpdfboxes_add_box(WPDFBOXES *boxes, WPDFBOX *box); - -static MASTERINFO _masterinfo, *masterinfo; -static int master_bmp_inited = 0; -static int max_page_width_pix = 3000; -static int max_page_height_pix = 4000; -static double shrink_factor = 0.9; - -static void k2pdfopt_reflow_bmp(MASTERINFO *masterinfo, WILLUSBITMAP *src) { - WPDFPAGEINFO _pageinfo, *pageinfo; - WILLUSBITMAP _srcgrey, *srcgrey; - int i, white, dpi; - double area_ratio; - - if (use_crop_boxes) { - pageinfo = &_pageinfo; - wpdfboxes_init(&pageinfo->boxes); - } else - pageinfo = NULL; - - masterinfo->debugfolder[0] = '\0'; - white = src_whitethresh; /* Will be set by adjust_contrast() or set to src_whitethresh */ - dpi = src_dpi; - adjust_params_init(); - set_region_widths(); - - srcgrey = &_srcgrey; - if (master_bmp_inited == 0) { - bmp_init(&masterinfo->bmp); - master_bmp_inited = 1; - } - - bmp_free(&masterinfo->bmp); - bmp_init(&masterinfo->bmp); - bmp_init(srcgrey); - - wrapbmp_init(); - - int ii; - masterinfo->bmp.bpp = 8; - for (ii = 0; ii < 256; ii++) - masterinfo->bmp.red[ii] = masterinfo->bmp.blue[ii] = - masterinfo->bmp.green[ii] = ii; - masterinfo->rows = 0; - masterinfo->bmp.width = dst_width; - area_ratio = 8.5 * 11.0 * dst_dpi * dst_dpi / (dst_width * dst_height); - masterinfo->bmp.height = dst_height * area_ratio * 1.5; - bmp_alloc(&masterinfo->bmp); - bmp_fill(&masterinfo->bmp, 255, 255, 255); - - if (src_rot != 0) { - bmp_rotate_right_angle(src, src_rot); - } - - BMPREGION region; - bmp_copy(srcgrey, src); - adjust_contrast(src, srcgrey, &white); - white_margins(src, srcgrey); - - if (erase_vertical_lines > 0) - bmp_detect_vertical_lines(srcgrey, src, (double) src_dpi, 0.005, 0.25, - min_column_height_inches, src_autostraighten, white); - if (src_autostraighten > 0.) { - double rot; - rot = bmp_autostraighten(src, srcgrey, white, src_autostraighten, 0.1, debug); - if (pageinfo != NULL) - pageinfo->srcpage_fine_rot_deg = rot; - } - - region.r1 = 0; - region.r2 = srcgrey->height - 1; - region.c1 = 0; - region.c2 = srcgrey->width - 1; - region.bgcolor = white; - region.bmp = src; - region.bmp8 = srcgrey; - - masterinfo->bgcolor = white; - masterinfo->fit_to_page = dst_fit_to_page; - /* Check to see if master bitmap might need more room */ - bmpregion_source_page_add(®ion, masterinfo, 1, pageinfo, (int) (0.25 * src_dpi + .5)); - - bmp_free(srcgrey); - if (pageinfo != NULL) - wpdfboxes_free(&pageinfo->boxes); -} - -static void k2pdfopt_init(KOPTContext *kctx) { - dst_userwidth = kctx->dev_width; // dst_width is adjusted in adjust_params_init - dst_userheight = kctx->dev_height; - vertical_line_spacing = kctx->line_spacing; - word_spacing = kctx->word_spacing; - text_wrap = kctx->wrap; - src_autostraighten = kctx->straighten; - preserve_indentation = kctx->indent; - max_columns = kctx->columns; - src_rot = kctx->rotate; - src_dpi = (int)300*kctx->quality; - defect_size_pts = kctx->defect_size; - - if (kctx->trim == 0) { - mar_left = 0; - mar_top = 0; - mar_right = 0; - mar_bot = 0; - } else { - mar_left = -1; - mar_top = -1; - mar_right = -1; - mar_bot = -1; - } - - // margin - dst_mar = kctx->margin; - dst_martop = -1.0; - dst_marbot = -1.0; - dst_marleft = -1.0; - dst_marright = -1.0; - - // justification - if (kctx->justification < 0) { - dst_justify = -1; - dst_fulljustify = -1; - } - else if (kctx->justification <= 2) { - dst_justify = kctx->justification; - dst_fulljustify = 0; - } - else { - dst_justify = -1; - dst_fulljustify = 1; - } -} - -void k2pdfopt_mupdf_reflow(KOPTContext *kctx, fz_document *doc, fz_page *page, fz_context *ctx) { - fz_device *dev; - fz_pixmap *pix; - fz_rect bounds,bounds2; - fz_matrix ctm; - fz_bbox bbox; - WILLUSBITMAP _src, *src; - - k2pdfopt_init(kctx); - - double dpp,zoom; - zoom = kctx->zoom; - double dpi = 250*zoom*src_dpi/300; - do { - dpp = dpi / 72.; - pix = NULL; - fz_var(pix); - bounds = fz_bound_page(doc, page); - ctm = fz_scale(dpp, dpp); - // ctm=fz_concat(ctm,fz_rotate(rotation)); - bounds2 = fz_transform_rect(ctm, bounds); - bbox = fz_round_rect(bounds2); - printf("reading page:%d,%d,%d,%d zoom:%.2f dpi:%.0f\n",bbox.x0,bbox.y0,bbox.x1,bbox.y1,zoom,dpi); - kctx->zoom = zoom; - zoom *= shrink_factor; - dpi *= shrink_factor; - } while (bbox.x1 > max_page_width_pix | bbox.y1 > max_page_height_pix); - // ctm=fz_translate(0,-page->mediabox.y1); - // ctm=fz_concat(ctm,fz_scale(dpp,-dpp)); - // ctm=fz_concat(ctm,fz_rotate(page->rotate)); - // ctm=fz_concat(ctm,fz_rotate(0)); - // bbox=fz_round_rect(fz_transform_rect(ctm,page->mediabox)); - // pix=fz_new_pixmap_with_rect(colorspace,bbox); - pix = fz_new_pixmap_with_bbox(ctx, fz_device_gray, bbox); - fz_clear_pixmap_with_value(ctx, pix, 0xff); - dev = fz_new_draw_device(ctx, pix); -#ifdef MUPDF_TRACE - fz_device *tdev; - fz_try(ctx) { - tdev = fz_new_trace_device(ctx); - fz_run_page(doc, page, tdev, ctm, NULL); - } - fz_always(ctx) { - fz_free_device(tdev); - } -#endif - fz_run_page(doc, page, dev, ctm, NULL); - fz_free_device(dev); - - if(kctx->contrast >= 0.0) { - fz_gamma_pixmap(ctx, pix, kctx->contrast); - } - - src = &_src; - masterinfo = &_masterinfo; - bmp_init(src); - int status = bmpmupdf_pixmap_to_bmp(src, ctx, pix); - k2pdfopt_reflow_bmp(masterinfo, src); - bmp_free(src); - - fz_drop_pixmap(ctx, pix); - - kctx->page_width = masterinfo->bmp.width; - kctx->page_height = masterinfo->rows; - kctx->data = masterinfo->bmp.data; -} - -void k2pdfopt_djvu_reflow(KOPTContext *kctx, ddjvu_page_t *page, ddjvu_context_t *ctx, \ - ddjvu_render_mode_t mode, ddjvu_format_t *fmt) { - WILLUSBITMAP _src, *src; - ddjvu_rect_t prect; - ddjvu_rect_t rrect; - - k2pdfopt_init(kctx); - - int i, iw, ih, idpi, status; - double zoom = kctx->zoom; - double dpi = 250*zoom; - - while (!ddjvu_page_decoding_done(page)) - handle(1, ctx); - - iw = ddjvu_page_get_width(page); - ih = ddjvu_page_get_height(page); - idpi = ddjvu_page_get_resolution(page); - prect.x = prect.y = 0; - do { - prect.w = iw * dpi / idpi; - prect.h = ih * dpi / idpi; - printf("reading page:%d,%d,%d,%d dpi:%.0f\n",prect.x,prect.y,prect.w,prect.h,dpi); - kctx->zoom = zoom; - zoom *= shrink_factor; - dpi *= shrink_factor; - } while (prect.w > max_page_width_pix | prect.h > max_page_height_pix); - rrect = prect; - - src = &_src; - masterinfo = &_masterinfo; - bmp_init(src); - - src->width = prect.w = iw * dpi / idpi; - src->height = prect.h = ih * dpi / idpi; - src->bpp = 8; - rrect = prect; - bmp_alloc(src); - if (src->bpp == 8) { - int ii; - for (ii = 0; ii < 256; ii++) - src->red[ii] = src->blue[ii] = src->green[ii] = ii; - } - - ddjvu_format_set_row_order(fmt, 1); - - status = ddjvu_page_render(page, mode, &prect, &rrect, fmt, - bmp_bytewidth(src), (char *) src->data); - - k2pdfopt_reflow_bmp(masterinfo, src); - bmp_free(src); - - kctx->page_width = masterinfo->bmp.width; - kctx->page_height = masterinfo->rows; - kctx->data = masterinfo->bmp.data; -} - -/* ansi.c */ -#define MAXSIZE 8000 - -static int ansi_on=1; -static char ansi_buffer[MAXSIZE]; - -int avprintf(FILE *f, char *fmt, va_list args) - -{ - int status; - { - if (!ansi_on) { - status = vsprintf(ansi_buffer, fmt, args); - ansi_parse(f, ansi_buffer); - } else - status = vfprintf(f, fmt, args); - } - return (status); -} - -int aprintf(char *fmt, ...) - -{ - va_list args; - int status; - - va_start(args, fmt); - status = avprintf(stdout, fmt, args); - va_end(args); - return (status); -} - -/* - ** Ensure that max_region_width_inches will be > MIN_REGION_WIDTH_INCHES - ** - ** Should only be called once, after all params are set. - ** - */ -void adjust_params_init(void) - -{ - if (dst_landscape) { - dst_width = dst_userheight; - dst_height = dst_userwidth; - } else { - dst_width = dst_userwidth; - dst_height = dst_userheight; - } - if (dst_mar < 0.) - dst_mar = 0.02; - if (dst_martop < 0.) - dst_martop = dst_mar; - if (dst_marbot < 0.) - dst_marbot = dst_mar; - if (dst_marleft < 0.) - dst_marleft = dst_mar; - if (dst_marright < 0.) - dst_marright = dst_mar; - if ((double) dst_width / dst_dpi - dst_marleft - - dst_marright< MIN_REGION_WIDTH_INCHES) { - int olddpi; - olddpi = dst_dpi; - dst_dpi = (int) ((double) dst_width - / (MIN_REGION_WIDTH_INCHES + dst_marleft + dst_marright)); - aprintf( - TTEXT_BOLD2 "Output DPI of %d is too large. Reduced to %d." TTEXT_NORMAL "\n\n", - olddpi, dst_dpi); - } -} - -void set_region_widths(void) - -{ - max_region_width_inches = display_width_inches = (double) dst_width - / dst_dpi; - max_region_width_inches -= (dst_marleft + dst_marright); - /* This is ensured by adjust_dst_dpi() as of v1.17 */ - /* - if (max_region_width_inches < MIN_REGION_WIDTH_INCHES) - max_region_width_inches = MIN_REGION_WIDTH_INCHES; - */ -} - -/* - ** Process full source page bitmap into rectangular regions and add - ** to the destination bitmap. Start by looking for columns. - ** - ** level = recursion level. First call = 1, then 2, ... - ** - */ -static void bmpregion_source_page_add(BMPREGION *region, MASTERINFO *masterinfo, - int level, WPDFPAGEINFO *pageinfo, int colgap0_pixels) - -{ - static char *funcname = "bmpregion_source_page_add"; - int *row_black_count; - int r2, rh, r0, cgr, maxlevel; - BMPREGION *srcregion, _srcregion; - BMPREGION *newregion, _newregion; - BMPREGION *pageregion; - double minh; - int ipr, npr, na; - int *colcount, *rowcount; - - willus_dmem_alloc_warn(1, (void **) &colcount, - sizeof(int) * (region->c2 + 1), funcname, 10); - willus_dmem_alloc_warn(2, (void **) &rowcount, - sizeof(int) * (region->r2 + 1), funcname, 10); - maxlevel = max_columns / 2; - if (debug) - printf("@bmpregion_source_page_add (%d,%d) - (%d,%d) lev=%d\n", - region->c1, region->r1, region->c2, region->r2, level); - newregion = &_newregion; - (*newregion) = (*region); - /* Establish colcount, rowcount arrays */ - bmpregion_trim_margins(newregion, colcount, rowcount, src_trim ? 0xf : 0); - (*newregion) = (*region); - srcregion = &_srcregion; - (*srcregion) = (*region); - /* Blind Grid Output (no attempt to find breaks between rows or columns) */ - if (src_grid_cols > 0 && src_grid_rows > 0) { - int i, nr; - nr = src_grid_cols * src_grid_rows; - for (i = 0; i < nr; i++) { - int r, c, gw, gh, gwo, gho; - - gwo = (src_grid_overlap_percentage * region->bmp8->width - + region->bmp8->width / 2) / 100; - gho = (src_grid_overlap_percentage * region->bmp8->height - + region->bmp8->height / 2) / 100; - gw = region->bmp8->width / src_grid_cols + gwo; - gh = region->bmp8->height / src_grid_rows + gho; - if (src_grid_order == 0) { - r = i % src_grid_rows; - c = i / src_grid_rows; - } else { - r = i / src_grid_cols; - c = i % src_grid_cols; - } - srcregion->c1 = c * region->bmp8->width / src_grid_cols - gwo / 2; - if (srcregion->c1 < 0) - srcregion->c1 = 0; - srcregion->c2 = srcregion->c1 + gw - 1; - if (srcregion->c2 > region->bmp8->width - 1) { - srcregion->c2 = region->bmp8->width - 1; - srcregion->c1 = srcregion->c2 - gw + 1; - if (srcregion->c1 < 0) - srcregion->c1 = 0; - } - srcregion->r1 = r * region->bmp8->height / src_grid_rows - gho / 2; - if (srcregion->r1 < 0) - srcregion->r1 = 0; - srcregion->r2 = srcregion->r1 + gh - 1; - if (srcregion->r2 > region->bmp8->height - 1) { - srcregion->r2 = region->bmp8->height - 1; - srcregion->r1 = srcregion->r2 - gh + 1; - if (srcregion->r1 < 0) - srcregion->r1 = 0; - } - bmpregion_vertically_break(srcregion, masterinfo, text_wrap, - fit_columns ? -2.0 : -1.0, colcount, rowcount, pageinfo, 0, - 2 * level); - if (masterinfo->fit_to_page == -2) - publish_master(masterinfo, pageinfo, 1); - } - willus_dmem_free(2, (double **) &rowcount, funcname); - willus_dmem_free(1, (double **) &colcount, funcname); - return; - } - /* How many page regions do we need? */ - minh = min_column_height_inches; - if (minh < .01) - minh = .1; - na = (srcregion->r2 - srcregion->r1 + 1) / src_dpi / minh; - if (na < 1) - na = 1; - na += 16; - /* Allocate page regions */ - willus_dmem_alloc_warn(3, (void **) &pageregion, sizeof(BMPREGION) * na, - funcname, 10); -#ifdef COMMENT - mindr=src_dpi*.045; /* src->height/250; */ - if (mindr<1) - mindr=1; -#endif -// white=250; -// for (i=0;iwidth;i++) -// colcount[i]=0; - if (debug) - bmpregion_row_histogram(region); - - /* - ** Store information about which rows are mostly clear for future - ** processing (saves processing time). - */ - willus_dmem_alloc_warn(4, (void **) &row_black_count, - region->bmp8->height * sizeof(int), funcname, 10); - for (cgr = 0, r0 = 0; r0 < region->bmp8->height; r0++) { - row_black_count[r0] = bmpregion_row_black_count(region, r0); - if (row_black_count[r0] == 0) - cgr++; - /* - int dr; - dr=mindr; - if (r0+dr>region->bmp8->height) - dr=region->bmp8->height-r0; - if ((row_is_clear[r0]=bmpregion_row_mostly_white(region,r0,dr))!=0) - cgr++; - */ -// printf("row_is_clear[%d]=%d\n",r0,row_is_clear[r0]); - } - if (verbose) - printf("%d clear rows.\n", cgr); - - if (max_columns == 1) { - pageregion[0] = (*srcregion); - /* Set c1 negative to indicate full span */ - pageregion[0].c1 = -1 - pageregion[0].c1; - npr = 1; - } else - /* Find all column dividers in source region and store sequentially in pageregion[] array */ - for (npr = 0, rh = 0; srcregion->r1 <= srcregion->r2; srcregion->r1 += - rh) { - static char *ierr = - TTEXT_WARN "\n\aInternal error--not enough allocated regions.\n" - "Please inform the developer at willus.com.\n\n" TTEXT_NORMAL; - if (npr >= na - 3) { - aprintf("%s", ierr); - break; - } - /* - if (maxlevel==1) - */ - rh = bmpregion_find_multicolumn_divider(srcregion, row_black_count, - pageregion, &npr, colcount, rowcount); - /* - else - { - BMPREGIONS *subregion,_subregion; - - subregion=&_subregion; - } - */ - if (verbose) - printf("rh=%d/%d\n", rh, region->r2 - region->r1 + 1); - } - - /* Process page regions by column */ - if (debug) - printf("Page regions: %d\n", npr); - r2 = -1; - for (ipr = 0; ipr < npr;) { - int r20, jpr, colnum, colgap_pixels; - - for (colnum = 1; colnum <= 2; colnum++) { - if (debug) { - printf("ipr = %d of %d...\n", ipr, npr); - printf("COLUMN %d...\n", colnum); - } - r20 = r2; - for (jpr = ipr; jpr < npr; jpr += 2) { - /* If we get to a page region that spans the entire source, stop */ - if (pageregion[jpr].c1 < 0) - break; - /* See if we should suspend this column and start displaying the next one */ - if (jpr > ipr) { - double cpdiff, cdiv1, cdiv2, rowgap1_in, rowgap2_in; - - if (column_offset_max < 0.) - break; - /* Did column divider move too much? */ - cdiv1 = (pageregion[jpr].c2 + pageregion[jpr + 1].c1) / 2.; - cdiv2 = (pageregion[jpr - 2].c2 + pageregion[jpr - 1].c1) - / 2.; - cpdiff = fabs( - (double) (cdiv1 - cdiv2) - / (srcregion->c2 - srcregion->c1 + 1)); - if (cpdiff > column_offset_max) - break; - /* Is gap between this column region and next column region too big? */ - rowgap1_in = (double) (pageregion[jpr].r1 - - pageregion[jpr - 2].r2) / src_dpi; - rowgap2_in = (double) (pageregion[jpr + 1].r1 - - pageregion[jpr - 1].r2) / src_dpi; - if (rowgap1_in > 0.28 && rowgap2_in > 0.28) - break; - } - (*newregion) = pageregion[ - src_left_to_right ? - jpr + colnum - 1 : jpr + (2 - colnum)]; - /* Preserve vertical gap between this region and last region */ - if (r20 >= 0 && newregion->r1 - r20 >= 0) - colgap_pixels = newregion->r1 - r20; - else - colgap_pixels = colgap0_pixels; - if (level < maxlevel) - bmpregion_source_page_add(newregion, masterinfo, level + 1, - pageinfo, colgap_pixels); - else { - bmpregion_vertically_break(newregion, masterinfo, text_wrap, - fit_columns ? -2.0 : -1.0, colcount, rowcount, - pageinfo, colgap_pixels, 2 * level); - } - r20 = newregion->r2; - } - if (r20 > r2) - r2 = r20; - if (jpr == ipr) - break; - } - if (jpr < npr && pageregion[jpr].c1 < 0) { - if (debug) - printf("SINGLE COLUMN REGION...\n"); - (*newregion) = pageregion[jpr]; - newregion->c1 = -1 - newregion->c1; - /* dst_add_gap_src_pixels("Col level",masterinfo,newregion->r1-r2); */ - colgap_pixels = newregion->r1 - r2; - bmpregion_vertically_break(newregion, masterinfo, text_wrap, - (fit_columns && (level > 1)) ? -2.0 : -1.0, colcount, - rowcount, pageinfo, colgap_pixels, level); - r2 = newregion->r2; - jpr++; - } - ipr = jpr; - } - willus_dmem_free(4, (double **) &row_black_count, funcname); - willus_dmem_free(3, (double **) &pageregion, funcname); - willus_dmem_free(2, (double **) &rowcount, funcname); - willus_dmem_free(1, (double **) &colcount, funcname); -} - -static void fit_column_to_screen(double column_width_inches) - -{ - double text_width_pixels, lm_pixels, rm_pixels, tm_pixels, bm_pixels; - - if (!column_fitted) { - dpi_org = dst_dpi; - lm_org = dst_marleft; - rm_org = dst_marright; - tm_org = dst_martop; - bm_org = dst_marbot; - } - text_width_pixels = max_region_width_inches * dst_dpi; - lm_pixels = dst_marleft * dst_dpi; - rm_pixels = dst_marright * dst_dpi; - tm_pixels = dst_martop * dst_dpi; - bm_pixels = dst_marbot * dst_dpi; - dst_dpi = text_width_pixels / column_width_inches; - dst_marleft = lm_pixels / dst_dpi; - dst_marright = rm_pixels / dst_dpi; - dst_martop = tm_pixels / dst_dpi; - dst_marbot = bm_pixels / dst_dpi; - set_region_widths(); - column_fitted = 1; -} - -static void restore_output_dpi(void) - -{ - if (column_fitted) { - dst_dpi = dpi_org; - dst_marleft = lm_org; - dst_marright = rm_org; - dst_martop = tm_org; - dst_marbot = bm_org; - set_region_widths(); - } - column_fitted = 0; -} - -void adjust_contrast(WILLUSBITMAP *src, WILLUSBITMAP *srcgrey, int *white) - -{ - int i, j, tries, wc, tc, hist[256]; - double contrast, rat0; - WILLUSBITMAP *dst, _dst; - - if (debug && verbose) - printf("\nAt adjust_contrast.\n"); - if ((*white) <= 0) - (*white) = 192; - /* If contrast_max negative, use it as fixed contrast adjustment. */ - if (contrast_max < 0.) { - bmp_contrast_adjust(srcgrey, srcgrey, -contrast_max); - if (dst_color && fabs(contrast_max + 1.0) > 1e-4) - bmp_contrast_adjust(src, src, -contrast_max); - return; - } - dst = &_dst; - bmp_init(dst); - wc = 0; /* Avoid compiler warning */ - tc = srcgrey->width * srcgrey->height; - rat0 = 0.5; /* Avoid compiler warning */ - for (contrast = 1.0, tries = 0; contrast < contrast_max + .01; tries++) { - if (fabs(contrast - 1.0) > 1e-4) - bmp_contrast_adjust(dst, srcgrey, contrast); - else - bmp_copy(dst, srcgrey); - /*Get bitmap histogram */ - for (i = 0; i < 256; i++) - hist[i] = 0; - for (j = 0; j < dst->height; j++) { - unsigned char *p; - p = bmp_rowptr_from_top(dst, j); - for (i = 0; i < dst->width; i++, p++) - hist[p[0]]++; - } - if (tries == 0) { - int h1; - for (h1 = 0, j = (*white); j < 256; j++) - h1 += hist[j]; - rat0 = (double) h1 / tc; - if (debug && verbose) - printf(" rat0 = rat[%d-255]=%.4f\n", (*white), rat0); - } - - /* Find white ratio */ - /* - for (wc=hist[254],j=253;j>=252;j--) - if (hist[j]>wc1) - wc1=hist[j]; - */ - for (wc = 0, j = 252; j <= 255; j++) - wc += hist[j]; - /* - if ((double)wc/tc >= rat0*0.7 && (double)hist[255]/wc > 0.995) - break; - */ - if (debug && verbose) - printf(" %2d. Contrast=%7.2f, rat[252-255]/rat0=%.4f\n", - tries + 1, contrast, (double) wc / tc / rat0); - if ((double) wc / tc >= rat0 * 0.94) - break; - contrast *= 1.05; - } - if (debug) - printf("Contrast=%7.2f, rat[252-255]/rat0=%.4f\n", contrast, - (double) wc / tc / rat0); - /* - bmp_write(dst,"outc.png",stdout,100); - wfile_written_info("outc.png",stdout); - exit(10); - */ - bmp_copy(srcgrey, dst); - /* Maybe don't adjust the contrast for the color bitmap? */ - if (dst_color && fabs(contrast - 1.0) > 1e-4) - bmp_contrast_adjust(src, src, contrast); - bmp_free(dst); -} - -static int bmpregion_row_black_count(BMPREGION *region, int r0) - -{ - unsigned char *p; - int i, nc, c; - - p = bmp_rowptr_from_top(region->bmp8, r0) + region->c1; - nc = region->c2 - region->c1 + 1; - for (c = i = 0; i < nc; i++, p++) - if (p[0] < region->bgcolor) - c++; - return (c); -} - -/* - ** Returns height of region found and divider position in (*divider_column). - ** (*divider_column) is absolute position on source bitmap. - ** - */ -static int bmpregion_find_multicolumn_divider(BMPREGION *region, - int *row_black_count, BMPREGION *pageregion, int *npr, int *colcount, - int *rowcount) - -{ - int itop, i, dm, middle, divider_column, min_height_pixels, mhp2, - min_col_gap_pixels; - BMPREGION _newregion, *newregion, column[2]; - BREAKINFO *breakinfo, _breakinfo; - int *rowmin, *rowmax; - static char *funcname = "bmpregion_find_multicolumn_divider"; - - if (debug) - printf("@bmpregion_find_multicolumn_divider(%d,%d)-(%d,%d)\n", - region->c1, region->r1, region->c2, region->r2); - breakinfo = &_breakinfo; - breakinfo->textrow = NULL; - breakinfo_alloc(101, breakinfo, region->r2 - region->r1 + 1); - bmpregion_find_vertical_breaks(region, breakinfo, colcount, rowcount, - column_row_gap_height_in); - if (debug) { - printf("region (%d,%d)-(%d,%d) has %d breaks:\n", region->c1, - region->r1, region->c2, region->r2, breakinfo->n); - for (i = 0; i < breakinfo->n; i++) - printf(" Rows %d - %d\n", breakinfo->textrow[i].r1, - breakinfo->textrow[i].r2); - } - newregion = &_newregion; - (*newregion) = (*region); - min_height_pixels = min_column_height_inches * src_dpi; /* src->height/15; */ - mhp2 = min_height_pixels - 1; - if (mhp2 < 0) - mhp2 = 0; - dm = 1 + (region->c2 - region->c1 + 1) * column_gap_range / 2.; - middle = (region->c2 - region->c1 + 1) / 2; - min_col_gap_pixels = (int) (min_column_gap_inches * src_dpi + .5); - if (verbose) { - printf("(dm=%d, width=%d, min_gap=%d)\n", dm, - region->c2 - region->c1 + 1, min_col_gap_pixels); - printf("Checking regions (r1=%d, r2=%d, minrh=%d)..", region->r1, - region->r2, min_height_pixels); - fflush(stdout); - } - breakinfo_sort_by_row_position(breakinfo); - willus_dmem_alloc_warn(5, (void **) &rowmin, - (region->c2 + 10) * 2 * sizeof(int), funcname, 10); - rowmax = &rowmin[region->c2 + 10]; - for (i = 0; i < region->c2 + 2; i++) { - rowmin[i] = region->r2 + 2; - rowmax[i] = -1; - } - /* Un-trim top/bottom rows if requested */ - if (!src_trim && breakinfo->n > 0) { - breakinfo->textrow[0].r1 = region->r1; - breakinfo->textrow[breakinfo->n - 1].r2 = region->r2; - } - - /* Start with top-most and bottom-most regions, look for column dividers */ - for (itop = 0; - itop < breakinfo->n - && breakinfo->textrow[itop].r1 - < region->r2 + 1 - min_height_pixels; itop++) { - int ibottom; - - for (ibottom = breakinfo->n - 1; - ibottom >= itop - && breakinfo->textrow[ibottom].r2 - - breakinfo->textrow[itop].r1 - >= min_height_pixels; ibottom--) { - /* - ** Look for vertical shaft of clear space that clearly demarcates - ** two columns - */ - for (i = 0; i < dm; i++) { - int foundgap, ii, c1, c2, iiopt, status; - - newregion->c1 = region->c1 + middle - i; - /* If we've effectively already checked this shaft, move on */ - if (itop >= rowmin[newregion->c1] - && ibottom <= rowmax[newregion->c1]) - continue; - newregion->c2 = newregion->c1 + min_col_gap_pixels - 1; - newregion->r1 = breakinfo->textrow[itop].r1; - newregion->r2 = breakinfo->textrow[ibottom].r2; - foundgap = bmpregion_is_clear(newregion, row_black_count, - gtc_in); - if (!foundgap && i > 0) { - newregion->c1 = region->c1 + middle + i; - newregion->c2 = newregion->c1 + min_col_gap_pixels - 1; - foundgap = bmpregion_is_clear(newregion, row_black_count, - gtc_in); - } - if (!foundgap) - continue; - /* Found a gap, but look for a better gap nearby */ - c1 = newregion->c1; - c2 = newregion->c2; - for (iiopt = 0, ii = -min_col_gap_pixels; - ii <= min_col_gap_pixels; ii++) { - int newgap; - newregion->c1 = c1 + ii; - newregion->c2 = c2 + ii; - newgap = bmpregion_is_clear(newregion, row_black_count, - gtc_in); - if (newgap > 0 && newgap < foundgap) { - iiopt = ii; - foundgap = newgap; - if (newgap == 1) - break; - } - } - newregion->c1 = c1 + iiopt; - /* If we've effectively already checked this shaft, move on */ - if (itop >= rowmin[newregion->c1] - && ibottom <= rowmax[newregion->c1]) - continue; - newregion->c2 = c2 + iiopt; - divider_column = newregion->c1 + min_col_gap_pixels / 2; - status = bmpregion_column_height_and_gap_test(column, region, - breakinfo->textrow[itop].r1, - breakinfo->textrow[ibottom].r2, divider_column, - colcount, rowcount); - /* If fails column height or gap test, mark as bad */ - if (status) { - if (itop < rowmin[newregion->c1]) - rowmin[newregion->c1] = itop; - if (ibottom > rowmax[newregion->c1]) - rowmax[newregion->c1] = ibottom; - } - /* If right column too short, stop looking */ - if (status & 2) - break; - if (!status) { - int colheight; - - /* printf(" GOT COLUMN DIVIDER AT x=%d.\n",(*divider_column)); */ - if (verbose) { - printf("\n GOOD REGION: col gap=(%d,%d) - (%d,%d)\n" - " r1=%d, r2=%d\n", - newregion->c1, newregion->r1, newregion->c2, - newregion->r2, breakinfo->textrow[itop].r1, - breakinfo->textrow[ibottom].r2); - } - if (itop > 0) { - /* add 1-column region */ - pageregion[(*npr)] = (*region); - pageregion[(*npr)].r2 = breakinfo->textrow[itop - 1].r2; - if (pageregion[(*npr)].r2 - > pageregion[(*npr)].bmp8->height - 1) - pageregion[(*npr)].r2 = - pageregion[(*npr)].bmp8->height - 1; - bmpregion_trim_margins(&pageregion[(*npr)], colcount, - rowcount, src_trim ? 0xf : 0); - /* Special flag to indicate full-width region */ - pageregion[(*npr)].c1 = -1 - pageregion[(*npr)].c1; - (*npr) = (*npr) + 1; - } - /* Un-trim columns if requested */ - if (!src_trim) { - column[0].c1 = region->c1; - column[1].c2 = region->c2; - } - pageregion[(*npr)] = column[0]; - (*npr) = (*npr) + 1; - pageregion[(*npr)] = column[1]; - (*npr) = (*npr) + 1; - colheight = breakinfo->textrow[ibottom].r2 - region->r1 + 1; - breakinfo_free(101, breakinfo); - /* - printf("Returning %d divider column = %d - %d\n",region->r2-region->r1+1,newregion->c1,newregion->c2); - */ - return (colheight); - } - } - } - } - if (verbose) - printf("NO GOOD REGION FOUND.\n"); - pageregion[(*npr)] = (*region); - bmpregion_trim_margins(&pageregion[(*npr)], colcount, rowcount, - src_trim ? 0xf : 0); - /* Special flag to indicate full-width region */ - pageregion[(*npr)].c1 = -1 - pageregion[(*npr)].c1; - (*npr) = (*npr) + 1; - /* (*divider_column)=region->c2+1; */ - willus_dmem_free(5, (double **) &rowmin, funcname); - breakinfo_free(101, breakinfo); - /* - printf("Returning %d\n",region->r2-region->r1+1); - */ - return (region->r2 - region->r1 + 1); -} - -/* - ** 1 = column 1 too short - ** 2 = column 2 too short - ** 3 = both too short - ** 0 = both okay - ** Both columns must pass height requirement. - ** - ** Also, if gap between columns > max_column_gap_inches, fails test. (8-31-12) - ** - */ -static int bmpregion_column_height_and_gap_test(BMPREGION *column, - BMPREGION *region, int r1, int r2, int cmid, int *colcount, - int *rowcount) - -{ - int min_height_pixels, status; - - status = 0; - min_height_pixels = min_column_height_inches * src_dpi; - column[0] = (*region); - column[0].r1 = r1; - column[0].r2 = r2; - column[0].c2 = cmid - 1; - bmpregion_trim_margins(&column[0], colcount, rowcount, 0xf); - /* - printf(" COL1: pix=%d (%d - %d)\n",newregion->r2-newregion->r1+1,newregion->r1,newregion->r2); - */ - if (column[0].r2 - column[0].r1 + 1 < min_height_pixels) - status |= 1; - column[1] = (*region); - column[1].r1 = r1; - column[1].r2 = r2; - column[1].c1 = cmid; - column[1].c2 = region->c2; - bmpregion_trim_margins(&column[1], colcount, rowcount, 0xf); - /* - printf(" COL2: pix=%d (%d - %d)\n",newregion->r2-newregion->r1+1,newregion->r1,newregion->r2); - */ - if (column[1].r2 - column[1].r1 + 1 < min_height_pixels) - status |= 2; - /* Make sure gap between columns is not too large */ - if (max_column_gap_inches >= 0. - && column[1].c1 - column[0].c2 - 1 - > max_column_gap_inches * src_dpi) - status |= 4; - return (status); -} - -/* - ** Return 0 if there are dark pixels in the region. NZ otherwise. - */ -static int bmpregion_is_clear(BMPREGION *region, int *row_black_count, - double gt_in) - -{ - int r, c, nc, pt; - - /* - ** row_black_count[] doesn't necessarily match up to this particular region's columns. - ** So if row_black_count[] == 0, the row is clear, otherwise it has to be counted. - ** because the columns are a subset. - */ - /* nr=region->r2-region->r1+1; */ - nc = region->c2 - region->c1 + 1; - pt = (int) (gt_in * src_dpi * nc + .5); - if (pt < 0) - pt = 0; - for (c = 0, r = region->r1; r <= region->r2; r++) { - if (r < 0 || r >= region->bmp8->height) - continue; - if (row_black_count[r] == 0) - continue; - c += bmpregion_row_black_count(region, r); - if (c > pt) - return (0); - } - /* - printf("(%d,%d)-(%d,%d): c=%d, pt=%d (gt_in=%g)\n", - region->c1,region->r1,region->c2,region->r2,c,pt,gt_in); - */ - return (pt <= 0 ? 1 : 1 + (int) 10 * c / pt); -} - -static void bmpregion_row_histogram(BMPREGION *region) - -{ - static char *funcname = "bmpregion_row_histogram"; - WILLUSBITMAP *src; - FILE *out; - static int *rowcount; - static int *hist; - int i, j, nn; - - willus_dmem_alloc_warn(6, (void **) &rowcount, - (region->r2 - region->r1 + 1) * sizeof(int), funcname, 10); - willus_dmem_alloc_warn(7, (void **) &hist, - (region->c2 - region->c1 + 1) * sizeof(int), funcname, 10); - src = region->bmp8; - for (j = region->r1; j <= region->r2; j++) { - unsigned char *p; - p = bmp_rowptr_from_top(src, j) + region->c1; - rowcount[j - region->r1] = 0; - for (i = region->c1; i <= region->c2; i++, p++) - if (p[0] < region->bgcolor) - rowcount[j - region->r1]++; - } - for (i = region->c1; i <= region->c2; i++) - hist[i - region->c1] = 0; - for (i = region->r1; i <= region->r2; i++) - hist[rowcount[i - region->r1]]++; - for (i = region->c2 - region->c1 + 1; i >= 0; i--) - if (hist[i] > 0) - break; - nn = i; - out = fopen("hist.ep", "w"); - for (i = 0; i <= nn; i++) - fprintf(out, "%5d %5d\n", i, hist[i]); - fclose(out); - out = fopen("rowcount.ep", "w"); - for (i = 0; i < region->r2 - region->r1 + 1; i++) - fprintf(out, "%5d %5d\n", i, rowcount[i]); - fclose(out); - willus_dmem_free(7, (double **) &hist, funcname); - willus_dmem_free(6, (double **) &rowcount, funcname); -} - -/* - ** Mark the region - ** mark_flags & 1 : Mark top - ** mark_flags & 2 : Mark bottom - ** mark_flags & 4 : Mark left - ** mark_flags & 8 : Mark right - ** - */ -static void mark_source_page(BMPREGION *region0, int caller_id, int mark_flags) - -{ - static int display_order = 0; - int i, n, nn, fontsize, r, g, b, shownum; - char num[16]; - BMPREGION *region, _region; - BMPREGION *clip, _clip; - - if (!show_marked_source) - return; - - if (region0 == NULL) { - display_order = 0; - return; - } - - region = &_region; - (*region) = (*region0); - - /* Clip the region w/ignored margins */ - clip = &_clip; - clip->bmp = region0->bmp; - get_white_margins(clip); - if (region->c1 < clip->c1) - region->c1 = clip->c1; - if (region->c2 > clip->c2) - region->c2 = clip->c2; - if (region->r1 < clip->r1) - region->r1 = clip->r1; - if (region->r2 > clip->r2) - region->r2 = clip->r2; - if (region->r2 <= region->r1 || region->c2 <= region->c1) - return; - - /* printf("@mark_source_page(display_order=%d)\n",display_order); */ - if (caller_id == 1) { - display_order++; - shownum = 1; - n = (int) (src_dpi / 60. + 0.5); - if (n < 5) - n = 5; - r = 255; - g = b = 0; - } else if (caller_id == 2) { - shownum = 0; - n = 2; - r = 0; - g = 0; - b = 255; - } else if (caller_id == 3) { - shownum = 0; - n = (int) (src_dpi / 80. + 0.5); - if (n < 4) - n = 4; - r = 0; - g = 255; - b = 0; - } else if (caller_id == 4) { - shownum = 0; - n = 2; - r = 255; - g = 0; - b = 255; - } else { - shownum = 0; - n = 2; - r = 140; - g = 140; - b = 140; - } - if (n < 2) - n = 2; - nn = (region->c2 + 1 - region->c1) / 2; - if (n > nn) - n = nn; - nn = (region->r2 + 1 - region->r1) / 2; - if (n > nn) - n = nn; - if (n < 1) - n = 1; - for (i = 0; i < n; i++) { - int j; - unsigned char *p; - if (mark_flags & 1) { - p = bmp_rowptr_from_top(region->marked, region->r1 + i) - + region->c1 * 3; - for (j = region->c1; j <= region->c2; j++, p += 3) { - p[0] = r; - p[1] = g; - p[2] = b; - } - } - if (mark_flags & 2) { - p = bmp_rowptr_from_top(region->marked, region->r2 - i) - + region->c1 * 3; - for (j = region->c1; j <= region->c2; j++, p += 3) { - p[0] = r; - p[1] = g; - p[2] = b; - } - } - if (mark_flags & 16) /* rowbase */ - { - p = bmp_rowptr_from_top(region->marked, region->rowbase - i) - + region->c1 * 3; - for (j = region->c1; j <= region->c2; j++, p += 3) { - p[0] = r; - p[1] = g; - p[2] = b; - } - } - if (mark_flags & 4) - for (j = region->r1; j <= region->r2; j++) { - p = bmp_rowptr_from_top(region->marked, j) - + (region->c1 + i) * 3; - p[0] = r; - p[1] = g; - p[2] = b; - } - if (mark_flags & 8) - for (j = region->r1; j <= region->r2; j++) { - p = bmp_rowptr_from_top(region->marked, j) - + (region->c2 - i) * 3; - p[0] = r; - p[1] = g; - p[2] = b; - } - } - if (!shownum) - return; - fontsize = region->c2 - region->c1 + 1; - if (fontsize > region->r2 - region->r1 + 1) - fontsize = region->r2 - region->r1 + 1; - fontsize /= 2; - if (fontsize > src_dpi) - fontsize = src_dpi; - if (fontsize < 5) - return; - fontrender_set_typeface("helvetica-bold"); - fontrender_set_fgcolor(r, g, b); - fontrender_set_bgcolor(255, 255, 255); - fontrender_set_pixel_size(fontsize); - fontrender_set_justification(4); - fontrender_set_or(1); - sprintf(num, "%d", display_order); - fontrender_render(region->marked, (double) (region->c1 + region->c2) / 2., - (double) (region->marked->height - ((region->r1 + region->r2) / 2.)), - num, 0, NULL); - /* printf(" done mark_source_page.\n"); */ -} - -/* - ** Input: A generic rectangular region from the source file. It will not - ** be checked for multiple columns, but the text may be wrapped - ** (controlled by allow_text_wrapping input). - ** - ** force_scale == -2 : Use same scale for entire column--fit to device - ** - ** This function looks for vertical gaps in the region and breaks it at - ** the widest ones (if there are significantly wider ones). - ** - */ -static void bmpregion_vertically_break(BMPREGION *region, - MASTERINFO *masterinfo, int allow_text_wrapping, double force_scale, - int *colcount, int *rowcount, WPDFPAGEINFO *pageinfo, int colgap_pixels, - int ncols) - -{ - static int ncols_last = -1; - int regcount, i, i1, biggap, revert, trim_flags, allow_vertical_breaks; - int justification_flags, caller_id, marking_flags, rbdelta; - // int trim_left_and_right; - BMPREGION *bregion, _bregion; - BREAKINFO *breakinfo, _breakinfo; - double region_width_inches, region_height_inches; - -#if (WILLUSDEBUGX & 1) - printf("\n\n@bmpregion_vertically_break. colgap_pixels=%d\n\n",colgap_pixels); - printf(" region = (%d,%d) - (%d,%d)\n",region->c1,region->r1,region->c2,region->r2); - printf(" vertical_break_threshold=%g\n",vertical_break_threshold); -#endif - allow_vertical_breaks = (vertical_break_threshold > -1.5); - justification_flags = 0x8f; /* Don't know region justification status yet. Use user settings. */ - rbdelta = -1; - breakinfo = &_breakinfo; - breakinfo->textrow = NULL; - breakinfo_alloc(102, breakinfo, region->r2 - region->r1 + 1); - bmpregion_find_vertical_breaks(region, breakinfo, colcount, rowcount, -1.0); - /* Should there be a check for breakinfo->n==0 here? */ - /* Don't think it breaks anything to let it go. -- 6-11-12 */ -#if (WILLUSDEBUGX & 2) - breakinfo_echo(breakinfo); -#endif - breakinfo_remove_small_rows(breakinfo, 0.25, 0.5, region, colcount, - rowcount); -#if (WILLUSDEBUGX & 2) - breakinfo_echo(breakinfo); -#endif - breakinfo->centered = bmpregion_is_centered(region, breakinfo, 0, - breakinfo->n - 1, NULL); -#if (WILLUSDEBUGX & 2) - breakinfo_echo(breakinfo); -#endif - - /* Red, numbered region */ - mark_source_page(region, 1, 0xf); - bregion = &_bregion; - if (debug) { - if (!allow_text_wrapping) - printf( - "@bmpregion_vertically_break (no break) (%d,%d) - (%d,%d) (scale=%g)\n", - region->c1, region->r1, region->c2, region->r2, - force_scale); - else - printf( - "@bmpregion_vertically_break (allow break) (%d,%d) - (%d,%d) (scale=%g)\n", - region->c1, region->r1, region->c2, region->r2, - force_scale); - } - /* - ** Tag blank rows and columns - */ - if (vertical_break_threshold < 0. || breakinfo->n < 6) - biggap = -1.; - else { - int gap_median; - /* - int rowheight_median; - - breakinfo_sort_by_rowheight(breakinfo); - rowheight_median = breakinfo->textrow[breakinfo->n/2].rowheight; - */ -#ifdef WILLUSDEBUG - for (i=0;in;i++) - printf(" gap[%d]=%d\n",i,breakinfo->textrow[i].gap); -#endif - breakinfo_sort_by_gap(breakinfo); - gap_median = breakinfo->textrow[breakinfo->n / 2].gap; -#ifdef WILLUSDEBUG - printf(" median=%d\n",gap_median); -#endif - biggap = gap_median * vertical_break_threshold; - breakinfo_sort_by_row_position(breakinfo); - } -#ifdef WILLUSDEBUG - printf(" biggap=%d\n",biggap); -#endif - region_width_inches = (double) (region->c2 - region->c1 + 1) / src_dpi; - region_height_inches = (double) (region->r2 - region->r1 + 1) / src_dpi; - /* - trim_left_and_right = 1; - if (region_width_inches <= max_region_width_inches) - trim_left_and_right = 0; - */ - /* - printf("force_scale=%g, rwi = %g, rwi/mrwi = %g, rhi = %g\n", - force_scale, - region_width_inches, - region_width_inches / max_region_width_inches, - region_height_inches); - */ - if (force_scale < -1.5 && region_width_inches > MIN_REGION_WIDTH_INCHES - && region_width_inches / max_region_width_inches < 1.25 - && region_height_inches > 0.5) { - revert = 1; - force_scale = -1.0; - fit_column_to_screen(region_width_inches); - // trim_left_and_right = 0; - allow_text_wrapping = 0; - } else - revert = 0; -#if (WILLUSDEBUGX & 1) - printf("Entering vert region loop, %d regions.\n",breakinfo->n); - printf(" region 1: r1=%d, r2=%d\n",breakinfo->textrow[0].r1,breakinfo->textrow[0].r2); - printf(" region %d: r1=%d, r2=%d\n",breakinfo->n,breakinfo->textrow[breakinfo->n-1].r1,breakinfo->textrow[breakinfo->n-1].r2); -#endif - /* Un-trim top and bottom region if necessary */ - if (!src_trim && breakinfo->n > 0) { - breakinfo->textrow[0].r1 = region->r1; - breakinfo->textrow[breakinfo->n - 1].r2 = region->r2; - } - - /* Add the regions (broken vertically) */ - caller_id = 1; - trim_flags = src_trim ? 0xf : 0x80; - for (regcount = i1 = i = 0; i1 < breakinfo->n; i++) { - int i2; - - i2 = i < breakinfo->n ? i : breakinfo->n - 1; - if (i >= breakinfo->n - || (biggap > 0. && breakinfo->textrow[i2].gap >= biggap)) { - int j, c1, c2, nc, nowrap; - double regwidth, ar1, rh1; - -// printf("CALLER 1: i1=%d, i2=%d (breakinfo->n=%d)\n",i1,i2,breakinfo->n); - (*bregion) = (*region); - bregion->r1 = breakinfo->textrow[i1].r1; - bregion->r2 = breakinfo->textrow[i2].r2; - c1 = breakinfo->textrow[i1].c1; - c2 = breakinfo->textrow[i1].c2; - nc = c2 - c1 + 1; - if (nc <= 0) - nc = 1; - rh1 = (double) (breakinfo->textrow[i1].r2 - - breakinfo->textrow[i1].r1 + 1) / src_dpi; - ar1 = (double) (breakinfo->textrow[i1].r2 - - breakinfo->textrow[i1].r1 + 1) / nc; - for (j = i1 + 1; j <= i2; j++) { - if (c1 > breakinfo->textrow[j].c1) - c1 = breakinfo->textrow[j].c1; - if (c2 < breakinfo->textrow[j].c2) - c2 = breakinfo->textrow[j].c2; - } - regwidth = (double) (c2 - c1 + 1) / src_dpi; - marking_flags = (i1 == 0 ? 0 : 1) - | (i2 == breakinfo->n - 1 ? 0 : 2); - /* Green */ - mark_source_page(bregion, 3, marking_flags); - nowrap = ((regwidth <= max_region_width_inches - && allow_text_wrapping < 2) - || (ar1 > no_wrap_ar_limit - && rh1 > no_wrap_height_limit_inches)); - /* - ** If between regions, or if the next region isn't going to be - ** wrapped, or if the next region starts a different number of - ** columns than before, then "flush and gap." - */ - if (regcount > 0 || just_flushed_internal || nowrap - || (ncols_last > 0 && ncols_last != ncols)) { - int gap; -#ifdef WILLUSDEBUG - printf("wrapflush1\n"); -#endif - if (!just_flushed_internal) - wrapbmp_flush(masterinfo, 0, pageinfo, 0); - gap = regcount == 0 ? - colgap_pixels : breakinfo->textrow[i1 - 1].gap; - if (regcount == 0 && beginning_gap_internal > 0) { - if (last_h5050_internal > 0) { - if (fabs( - 1. - - (double) breakinfo->textrow[i1].h5050 - / last_h5050_internal) > .1) - dst_add_gap_src_pixels("Col/Page break", masterinfo, - colgap_pixels); - last_h5050_internal = -1; - } - gap = beginning_gap_internal; - beginning_gap_internal = -1; - } - dst_add_gap_src_pixels("Vert break", masterinfo, gap); - } else { - if (regcount == 0 && beginning_gap_internal < 0) - beginning_gap_internal = colgap_pixels; - } - bmpregion_add(bregion, breakinfo, masterinfo, allow_text_wrapping, - trim_flags, allow_vertical_breaks, force_scale, - justification_flags, caller_id, colcount, rowcount, - pageinfo, marking_flags, rbdelta); - regcount++; - i1 = i2 + 1; - } - } - ncols_last = ncols; - if (revert) - restore_output_dpi(); - breakinfo_free(102, breakinfo); -} - -/* - ** - ** MAIN BITMAP REGION ADDING FUNCTION - ** - ** NOTE: This function calls itself recursively! - ** - ** Input: A generic rectangular region from the source file. It will not - ** be checked for multiple columns, but the text may be wrapped - ** (controlled by allow_text_wrapping input). - ** - ** First, excess margins are trimmed off of the region. - ** - ** Then, if the resulting trimmed region is wider than the max desirable width - ** and allow_text_wrapping is non-zero, then the - ** bmpregion_analyze_justification_and_line_spacing() function is called. - ** Otherwise the region is scaled to fit and added to the master set of pages. - ** - ** justification_flags - ** Bits 6-7: 0 = document is not fully justified - ** 1 = document is fully justified - ** 2 = don't know document justification yet - ** Bits 4-5: 0 = Use user settings - ** 1 = fully justify - ** 2 = do not fully justify - ** Bits 2-3: 0 = document is left justified - ** 1 = document is centered - ** 2 = document is right justified - ** 3 = don't know document justification yet - ** Bits 0-1: 0 = left justify document - ** 1 = center document - ** 2 = right justify document - ** 3 = Use user settings - ** - ** force_scale = -2.0 : Fit column width to display width - ** force_scale = -1.0 : Use output dpi unless the region doesn't fit. - ** In that case, scale it down until it fits. - ** force_scale > 0.0 : Scale region by force_scale. - ** - ** mark_flags & 1 : Mark top - ** mark_flags & 2 : Mark bottom - ** mark_flags & 4 : Mark left - ** mark_flags & 8 : Mark right - ** - ** trim_flags & 0x80 : Do NOT re-trim no matter what. - ** - */ -static void bmpregion_add(BMPREGION *region, BREAKINFO *breakinfo, - MASTERINFO *masterinfo, int allow_text_wrapping, int trim_flags, - int allow_vertical_breaks, double force_scale, int justification_flags, - int caller_id, int *colcount, int *rowcount, WPDFPAGEINFO *pageinfo, - int mark_flags, int rowbase_delta) - -{ - int w, wmax, i, nc, nr, h, bpp, tall_region; - double region_width_inches; - WILLUSBITMAP *bmp, _bmp; - BMPREGION *newregion, _newregion; - - newregion = &_newregion; - (*newregion) = (*region); -#if (WILLUSDEBUGX & 1) - printf("@bmpregion_add (%d,%d) - (%d,%d)\n",region->c1,region->r1,region->c2,region->r2); - printf(" trimflags = %X\n",trim_flags); - printf(" allow_text_wrapping = %d\n",allow_text_wrapping); - printf(" allow_vert_breaks = %d\n",allow_vertical_breaks); -#endif - if (debug) { - if (!allow_text_wrapping) - printf("@bmpregion_add (no break) (%d,%d) - (%d,%d) (scale=%g)\n", - region->c1, region->r1, region->c2, region->r2, - force_scale); - else - printf( - "@bmpregion_add (allow break) (%d,%d) - (%d,%d) (scale=%g)\n", - region->c1, region->r1, region->c2, region->r2, - force_scale); - } - /* - ** Tag blank rows and columns and trim the blank margins off - ** trimflags = 0xf for all margin trim. - ** trimflags = 0xc for just top and bottom margins. - */ - bmpregion_trim_margins(newregion, colcount, rowcount, trim_flags); -#if (WILLUSDEBUGX & 1) - printf(" After trim: (%d,%d) - (%d,%d)\n",newregion->c1,newregion->r1,newregion->c2,newregion->r2); -#endif - nc = newregion->c2 - newregion->c1 + 1; - nr = newregion->r2 - newregion->r1 + 1; -// printf("nc=%d, nr=%d\n",nc,nr); - if (verbose) { - printf(" row range adjusted to %d - %d\n", newregion->r1, - newregion->r2); - printf(" col range adjusted to %d - %d\n", newregion->c1, - newregion->c2); - } - if (nc <= 5 || nr <= 1) - return; - region_width_inches = (double) nc / src_dpi; -// printf("regwidth = %g in\n",region_width_inches); - /* Use untrimmed region left/right if possible */ - if (caller_id == 1 && region_width_inches <= max_region_width_inches) { - int trimleft, trimright; - int maxpix, dpix; - - maxpix = (int) (max_region_width_inches * src_dpi + .5); -#if (WILLUSDEBUGX & 1) - printf(" Trimming. C's = %4d %4d %4d %4d\n",region->c1,newregion->c1,newregion->c2,region->c2); - printf(" maxpix = %d, regwidth = %d\n",maxpix,region->c2-region->c1+1); -#endif - if (maxpix > (region->c2 - region->c1 + 1)) - maxpix = region->c2 - region->c1 + 1; -// printf(" maxpix = %d\n",maxpix); - dpix = (region->c2 - region->c1 + 1 - maxpix) / 2; -// printf(" dpix = %d\n",dpix); - trimright = region->c2 - newregion->c2; - trimleft = newregion->c1 - region->c1; - if (trimleft < trimright) { - if (trimleft > dpix) - newregion->c1 = region->c1 + dpix; - newregion->c2 = newregion->c1 + maxpix - 1; - } else { - if (trimright > dpix) - newregion->c2 = region->c2 - dpix; - newregion->c1 = newregion->c2 - maxpix + 1; - } - if (newregion->c1 < region->c1) - newregion->c1 = region->c1; - if (newregion->c2 > region->c2) - newregion->c2 = region->c2; - nc = newregion->c2 - newregion->c1 + 1; -#if (WILLUSDEBUGX & 1) - printf(" Post Trim. C's = %4d %4d %4d %4d\n",region->c1,newregion->c1,newregion->c2,region->c2); -#endif - region_width_inches = (double) nc / src_dpi; - } - - /* - ** Try breaking the region into smaller horizontal pieces (wrap text lines) - */ - /* - printf("allow_text_wrapping=%d, region_width_inches=%g, max_region_width_inches=%g\n", - allow_text_wrapping,region_width_inches,max_region_width_inches); - */ - /* New in v1.50, if allow_text_wrapping==2, unwrap short lines. */ - /* - printf("tw=%d, region_width_inches=%g, max_region_width_inches=%g\n",allow_text_wrapping,region_width_inches,max_region_width_inches); - */ - if (allow_text_wrapping == 2 - || (allow_text_wrapping == 1 - && region_width_inches > max_region_width_inches)) { - bmpregion_analyze_justification_and_line_spacing(newregion, breakinfo, - masterinfo, colcount, rowcount, pageinfo, 1, force_scale); - return; - } - - /* - ** If allowed, re-submit each vertical region individually - */ - if (allow_vertical_breaks) { - bmpregion_analyze_justification_and_line_spacing(newregion, breakinfo, - masterinfo, colcount, rowcount, pageinfo, 0, force_scale); - return; - } - - /* AT THIS POINT, BITMAP IS NOT TO BE BROKEN UP HORIZONTALLY OR VERTICALLY */ - /* (IT CAN STILL BE FULLY JUSTIFIED IF ALLOWED.) */ - - /* - ** Scale region to fit the destination device width and add to the master bitmap. - ** - ** - ** Start by copying source region to new bitmap - ** - */ -// printf("c1=%d\n",newregion->c1); - /* Is it a figure? */ - tall_region = (double) (newregion->r2 - newregion->r1 + 1) / src_dpi - >= dst_min_figure_height_in; - /* Re-trim left and right? */ - if ((trim_flags & 0x80) == 0) { - /* If tall region and figure justification turned on ... */ - if ((tall_region && dst_figure_justify >= 0) - /* ... or if centered region ... */ - || ((trim_flags & 3) != 3 - && ((justification_flags & 3) == 1 - || ((justification_flags & 3) == 3 - && (dst_justify == 1 - || (dst_justify < 0 - && (justification_flags - & 0xc) == 4)))))) { - bmpregion_trim_margins(newregion, colcount, rowcount, 0x3); - nc = newregion->c2 - newregion->c1 + 1; - region_width_inches = (double) nc / src_dpi; - } - } -#if (WILLUSDEBUGX & 1) - aprintf("atomic region: " ANSI_CYAN "%.2f x %.2f in" ANSI_NORMAL " c1=%d, (%d x %d) (rbdel=%d) just=0x%02X\n", - (double)(newregion->c2-newregion->c1+1)/src_dpi, - (double)(newregion->r2-newregion->r1+1)/src_dpi, - newregion->c1, - (newregion->c2-newregion->c1+1), - (newregion->r2-newregion->r1+1), - rowbase_delta,justification_flags); -#endif - /* Copy atomic region into bmp */ - bmp = &_bmp; - bmp_init(bmp); - bmp->width = nc; - bmp->height = nr; - if (dst_color) - bmp->bpp = 24; - else { - bmp->bpp = 8; - for (i = 0; i < 256; i++) - bmp->red[i] = bmp->blue[i] = bmp->green[i] = i; - } - bmp_alloc(bmp); - bpp = dst_color ? 3 : 1; -// printf("r1=%d, r2=%d\n",newregion->r1,newregion->r2); - for (i = newregion->r1; i <= newregion->r2; i++) { - unsigned char *psrc, *pdst; - - pdst = bmp_rowptr_from_top(bmp, i - newregion->r1); - psrc = bmp_rowptr_from_top(dst_color ? newregion->bmp : newregion->bmp8, - i) + bpp * newregion->c1; - memcpy(pdst, psrc, nc * bpp); - } - /* - ** Now scale to appropriate destination size. - ** - ** force_scale is used to maintain uniform scaling so that - ** most of the regions are scaled at the same value. - ** - ** force_scale = -2.0 : Fit column width to display width - ** force_scale = -1.0 : Use output dpi unless the region doesn't fit. - ** In that case, scale it down until it fits. - ** force_scale > 0.0 : Scale region by force_scale. - ** - */ - /* Max viewable pixel width on device screen */ - wmax = (int) (masterinfo->bmp.width - (dst_marleft + dst_marright) * dst_dpi - + 0.5); - if (force_scale > 0.) - w = (int) (force_scale * bmp->width + 0.5); - else { - if (region_width_inches < max_region_width_inches) - w = (int) (region_width_inches * dst_dpi + .5); - else - w = wmax; - } - /* Special processing for tall regions (likely figures) */ - if (tall_region && w < wmax && dst_fit_to_page != 0) { - if (dst_fit_to_page < 0) - w = wmax; - else { - w = (int) (w * (1. + (double) dst_fit_to_page / 100.) + 0.5); - if (w > wmax) - w = wmax; - } - } - h = (int) (((double) w / bmp->width) * bmp->height + .5); - - /* - ** If scaled dimensions are finite, add to master bitmap. - */ - if (w > 0 && h > 0) { - WILLUSBITMAP *tmp, _tmp; - int nocr, have_pagebox; - - have_pagebox = 0; - last_scale_factor_internal = (double) w / bmp->width; -#ifdef HAVE_OCR - if (dst_ocr) { - nocr = (int) ((double) bmp->width / w + 0.5); - if (nocr < 1) - nocr = 1; - if (nocr > 10) - nocr = 10; - w *= nocr; - h *= nocr; - } else -#endif - nocr = 1; - tmp = &_tmp; - bmp_init(tmp); - bmp_resample(tmp, bmp, (double) 0., (double) 0., (double) bmp->width, - (double) bmp->height, w, h); - bmp_free(bmp); - /* - { - static int nn=0; - char filename[256]; - sprintf(filename,"xxx%02d.png",nn++); - bmp_write(tmp,filename,stdout,100); - } - */ - /* - ** Add scaled bitmap to destination. - */ - /* Allocate more rows if necessary */ - while (masterinfo->rows + tmp->height / nocr > masterinfo->bmp.height) - bmp_more_rows(&masterinfo->bmp, 1.4, 255); - /* Check special justification for tall regions */ - if (tall_region && dst_figure_justify >= 0) - justification_flags = dst_figure_justify; -#ifdef HAVE_MUPDF - /* Add source region corresponding to "tmp" bitmap to pageinfo structure */ - if (pageinfo != NULL) { - WPDFBOX _wpdfbox, *wpdfbox; - WPDFSRCBOX *srcbox; - - wpdfbox = &_wpdfbox; - srcbox = &wpdfbox->srcbox; - wpdfbox->dstpage = -1; /* -1 while still on master bitmap */ - wpdfbox->dst_width_pts = pageinfo->width_pts; - wpdfbox->dst_height_pts = pageinfo->height_pts; - srcbox->pageno = pageinfo->srcpage; - srcbox->finerot_deg = pageinfo->srcpage_fine_rot_deg; - srcbox->rot_deg = pageinfo->srcpage_rot_deg; - srcbox->page_width_pts = 72. * newregion->bmp8->width / src_dpi; - srcbox->page_height_pts = 72. * newregion->bmp8->height / src_dpi; - /* Clip the source crop box with the page crop margins */ - { - BMPREGION *region, _region; - double x0, y0, w, h, mar; - - region = &_region; - region->bmp = newregion->bmp; - get_white_margins(region); - x0 = 72. * newregion->c1 / src_dpi; - y0 = 72. * (newregion->bmp8->height - 1 - newregion->r2) - / src_dpi; - w = 72. * (newregion->c2 - newregion->c1 + 1) / src_dpi; - h = 72. * (newregion->r2 - newregion->r1 + 1) / src_dpi; - mar = region->c1 * srcbox->page_width_pts - / newregion->bmp->width; - if (mar > x0) { - w -= (mar - x0); - x0 = mar; - } - mar = (newregion->bmp->width - 1 - region->c2) - * srcbox->page_width_pts / newregion->bmp->width; - if (w > srcbox->page_width_pts - mar - x0) - w = srcbox->page_width_pts - mar - x0; - mar = (newregion->bmp->height - 1 - region->r2) - * srcbox->page_height_pts / newregion->bmp->height; - if (mar > y0) { - h -= (mar - y0); - y0 = mar; - } - mar = region->r1 * srcbox->page_height_pts - / newregion->bmp->height; - if (h > srcbox->page_height_pts - mar - y0) - h = srcbox->page_height_pts - mar - y0; - srcbox->x0_pts = x0; - srcbox->y0_pts = y0; - srcbox->crop_width_pts = w; - srcbox->crop_height_pts = h; - } - if (srcbox->crop_width_pts > 0. && srcbox->crop_height_pts > 0.) { - wpdfboxes_add_box(&pageinfo->boxes, wpdfbox); - have_pagebox = 1; - } - } -#endif /* HAVE_MUPDF */ - bmp_src_to_dst(masterinfo, tmp, have_pagebox ? pageinfo : NULL, - justification_flags, region->bgcolor, nocr, - (int) ((double) src_dpi * tmp->width / bmp->width + .5)); - bmp_free(tmp); - } - - /* Store delta to base of text row (used by wrapbmp_flush()) */ - last_rowbase_internal = rowbase_delta; - /* .05 was .072 in v1.35 */ - /* dst_add_gap(&masterinfo->bmp,&masterinfo->rows,0.05); */ - /* - if (revert) - restore_output_dpi(); - */ -} - -static void dst_add_gap_src_pixels(char *caller, MASTERINFO *masterinfo, - int pixels) - -{ - double gap_inches; - - /* - aprintf("%s " ANSI_GREEN "dst_add" ANSI_NORMAL " %.3f in (%d pix)\n",caller,(double)pixels/src_dpi,pixels); - */ - if (last_scale_factor_internal < 0.) - gap_inches = (double) pixels / src_dpi; - else - gap_inches = (double) pixels * last_scale_factor_internal / dst_dpi; - gap_inches *= vertical_multiplier; - if (gap_inches > max_vertical_gap_inches) - gap_inches = max_vertical_gap_inches; - dst_add_gap(masterinfo, gap_inches); -} - -static void dst_add_gap(MASTERINFO *masterinfo, double inches) - -{ - int n, bw; - unsigned char *p; - - n = (int) (inches * dst_dpi + .5); - if (n < 1) - n = 1; - while (masterinfo->rows + n > masterinfo->bmp.height) - bmp_more_rows(&masterinfo->bmp, 1.4, 255); - bw = bmp_bytewidth(&masterinfo->bmp) * n; - p = bmp_rowptr_from_top(&masterinfo->bmp, masterinfo->rows); - memset(p, 255, bw); - masterinfo->rows += n; -} - -/* - ** - ** Add already-scaled source bmp to destination bmp. - ** Source bmp may be narrower than destination--if so, it may be fully justifed. - ** dst = destination bitmap - ** src = source bitmap - ** dst and src bpp must match! - ** All rows of src are applied to masterinfo->bmp starting at row masterinfo->rows - ** Full justification is done if requested. - ** - */ -static void bmp_src_to_dst(MASTERINFO *masterinfo, WILLUSBITMAP *src, - WPDFPAGEINFO *pageinfo, int justification_flags, int whitethresh, - int nocr, int dpi) - -{ - WILLUSBITMAP *src1, _src1; - WILLUSBITMAP *tmp; -#ifdef HAVE_OCR - WILLUSBITMAP _tmp; - OCRWORDS _words, *words; -#endif - int dw, dw2; - int i, srcbytespp, srcbytewidth, go_full; - int destwidth, destx0, just; - - if (src->width <= 0 || src->height <= 0) - return; - /* - printf("@bmp_src_to_dst. dst->bpp=%d, src->bpp=%d, src=%d x %d\n",masterinfo->bmp.bpp,src->bpp,src->width,src->height); - */ - /* - { - static int count=0; - static char filename[256]; - - printf(" @bmp_src_to_dst...\n"); - sprintf(filename,"src%05d.png",count++); - bmp_write(src,filename,stdout,100); - } - */ - /* - if (fulljust && dst_fulljustify) - printf("srcbytespp=%d, srcbytewidth=%d, destwidth=%d, destx0=%d, destbytewidth=%d\n", - srcbytespp,srcbytewidth,destwidth,destx0,dstbytewidth); - */ - - /* Determine what justification to use */ - /* Left? */ - if ((justification_flags & 3) == 0 /* Mandatory left just */ - || ((justification_flags & 3) == 3 /* Use user settings */ - && (dst_justify == 0 - || (dst_justify < 0 - && (justification_flags & 0xc) == 0)))) - just = 0; - else if ((justification_flags & 3) == 2 - || ((justification_flags & 3) == 3 - && (dst_justify == 2 - || (dst_justify < 0 - && (justification_flags & 0xc) == 8)))) - just = 2; - else - just = 1; - - /* Full justification? */ - destwidth = (int) (masterinfo->bmp.width - - (dst_marleft + dst_marright) * dst_dpi + .5); - go_full = (destwidth * nocr > src->width - && (((justification_flags & 0x30) == 0x10) - || ((justification_flags & 0x30) == 0 // Use user settings - && (dst_fulljustify == 1 - || (dst_fulljustify < 0 - && (justification_flags & 0xc0) - == 0x40))))); - - /* Cannot fully justify if using crop boxes */ - if (pageinfo != NULL) - go_full = 0; - - /* Put fully justified text into src1 bitmap */ - if (go_full) { - src1 = &_src1; - bmp_init(src1); - bmp_fully_justify(src1, src, nocr * destwidth, whitethresh, just); - } else - src1 = src; - -#if (WILLUSDEBUGX & 1) - printf("@bmp_src_to_dst: jflags=0x%02X just=%d, go_full=%d\n",justification_flags,just,go_full); - printf(" destx0=%d, destwidth=%d, src->width=%d\n",destx0,destwidth,src->width); -#endif -#ifdef HAVE_OCR - if (dst_ocr) { - /* Run OCR on the bitmap */ - words = &_words; - ocrwords_init(words); - ocrwords_fill_in(words, src1, whitethresh, dpi); - /* Scale bitmap and word positions to destination size */ - if (nocr > 1) { - tmp = &_tmp; - bmp_init(tmp); - bmp_integer_resample(tmp, src1, nocr); - ocrwords_int_scale(words, nocr); - } else - tmp = src1; - } else -#endif - tmp = src1; - /* - printf("writing...\n"); - ocrwords_box(words,tmp); - bmp_write(tmp,"out.png",stdout,100); - exit(10); - */ - destx0 = (int) (dst_marleft * dst_dpi + .5); - if (just == 0) - dw = destx0; - else if (just == 1) - dw = destx0 + (destwidth - tmp->width) / 2; - else - dw = destx0 + destwidth - tmp->width; - if (dw < 0) - dw = 0; - /* Add OCR words to destination list */ -#ifdef HAVE_OCR - if (dst_ocr) { - ocrwords_offset(words, dw, masterinfo->rows); - ocrwords_concatenate(dst_ocrwords, words); - ocrwords_free(words); - } -#endif - - /* - ** For now: set destination position in pageinfo structure as pixel position - ** relative to top of master bitmap. scale = the height in pixels on the master bitmap. - */ -#ifdef HAVE_MUPDF - if (pageinfo != NULL) { - WPDFBOX *box; - - box = &pageinfo->boxes.box[pageinfo->boxes.n - 1]; - /* These values will get adjusted in publish_master() */ - box->x1 = dw; - box->y1 = masterinfo->rows; - box->userx = tmp->width; - box->usery = tmp->height; - } -#endif - - /* Add tmp bitmap to dst */ - srcbytespp = tmp->bpp == 24 ? 3 : 1; - srcbytewidth = tmp->width * srcbytespp; - dw2 = masterinfo->bmp.width - tmp->width - dw; - dw *= srcbytespp; - dw2 *= srcbytespp; - for (i = 0; i < tmp->height; i++, masterinfo->rows++) { - unsigned char *pdst, *psrc; - - psrc = bmp_rowptr_from_top(tmp, i); - pdst = bmp_rowptr_from_top(&masterinfo->bmp, masterinfo->rows); - memset(pdst, 255, dw); - pdst += dw; - memcpy(pdst, psrc, srcbytewidth); - pdst += srcbytewidth; - memset(pdst, 255, dw2); - } - -#ifdef HAVE_OCR - if (dst_ocr && nocr > 1) - bmp_free(tmp); -#endif - if (go_full) - bmp_free(src1); -} - -/* - ** Spread words out in src and put into jbmp at scaling nocr - ** In case the text can't be expanded enough, - ** just=0 (left justify), 1 (center), 2 (right justify) - */ -static void bmp_fully_justify(WILLUSBITMAP *jbmp, WILLUSBITMAP *src, - int jbmpwidth, int whitethresh, int just) - -{ - BMPREGION srcregion; - BREAKINFO *colbreaks, _colbreaks; - WILLUSBITMAP gray; - int *gappos, *gapsize; - int i, srcbytespp, srcbytewidth, jbmpbytewidth, newwidth, destx0, ng; - static char *funcname = "bmp_fully_justify"; - - /* - { - char filename[256]; - count++; - sprintf(filename,"out%03d.png",count); - bmp_write(src,filename,stdout,100); - } - */ - /* Init/allocate destination bitmap */ - jbmp->width = jbmpwidth; - jbmp->height = src->height; - jbmp->bpp = src->bpp; - if (jbmp->bpp == 8) - for (i = 0; i < 256; i++) - jbmp->red[i] = jbmp->green[i] = jbmp->blue[i] = i; - bmp_alloc(jbmp); - - /* Find breaks in the text row */ - colbreaks = &_colbreaks; - colbreaks->textrow = NULL; - srcregion.bgcolor = whitethresh; - srcregion.c1 = 0; - srcregion.c2 = src->width - 1; - srcregion.r1 = 0; - srcregion.r2 = src->height - 1; - srcbytespp = src->bpp == 24 ? 3 : 1; - if (srcbytespp == 3) { - srcregion.bmp = src; - srcregion.bmp8 = &gray; - bmp_init(srcregion.bmp8); - bmp_convert_to_greyscale_ex(srcregion.bmp8, src); - } else { - srcregion.bmp = src; - srcregion.bmp8 = src; - } - breakinfo_alloc(103, colbreaks, src->width); - { - int *colcount, *rowcount; - - colcount = rowcount = NULL; - willus_dmem_alloc_warn(8, (void **) &colcount, - sizeof(int) * (src->width + src->height), funcname, 10); - rowcount = &colcount[src->width]; - bmpregion_one_row_find_breaks(&srcregion, colbreaks, colcount, rowcount, - 1); - willus_dmem_free(8, (double **) &colcount, funcname); - } - if (srcbytespp == 3) - bmp_free(srcregion.bmp8); - ng = colbreaks->n - 1; - gappos = NULL; - if (ng > 0) { - int maxsize, ms2, mingap, j; - - willus_dmem_alloc_warn(9, (void **) &gappos, (2 * sizeof(int)) * ng, - funcname, 10); - gapsize = &gappos[ng]; - for (i = 0; i < ng; i++) { - gappos[i] = colbreaks->textrow[i].c2 + 1; - gapsize[i] = colbreaks->textrow[i].gap; - } - - /* Take only the largest group of gaps */ - for (maxsize = i = 0; i < ng; i++) - if (maxsize < gapsize[i]) - maxsize = gapsize[i]; - mingap = srcregion.lcheight * word_spacing; - if (mingap < 2) - mingap = 2; - if (maxsize > mingap) - maxsize = mingap; - ms2 = maxsize / 2; - for (i = j = 0; i < ng; i++) - if (gapsize[i] > ms2) { - if (j != i) { - gapsize[j] = gapsize[i]; - gappos[j] = gappos[i]; - } - j++; - } - ng = j; - - /* Figure out total pixel expansion */ - newwidth = src->width * 1.25; - if (newwidth > jbmp->width) - newwidth = jbmp->width; - } else - newwidth = src->width; - breakinfo_free(103, colbreaks); - - /* Starting column in destination bitmap */ - if (just == 1) - destx0 = (jbmp->width - newwidth) / 2; - else if (just == 2) - destx0 = (jbmp->width - newwidth); - else - destx0 = 0; - - jbmpbytewidth = bmp_bytewidth(jbmp); - srcbytewidth = bmp_bytewidth(src); - - /* Clear entire fully justified bitmap */ - memset(bmp_rowptr_from_top(jbmp, 0), 255, jbmpbytewidth * jbmp->height); - - /* Spread out source pieces to fully justify them */ - for (i = 0; i <= ng; i++) { - int j, dx0, dx, sx0; - unsigned char *pdst, *psrc; - - dx = i < ng ? - (i > 0 ? gappos[i] - gappos[i - 1] : gappos[i] + 1) : - (i > 0 ? src->width - (gappos[i - 1] + 1) : src->width); - dx *= srcbytespp; - sx0 = i == 0 ? 0 : (gappos[i - 1] + 1); - dx0 = destx0 + sx0 + (i == 0 ? 0 : (newwidth - src->width) * i / ng); - psrc = bmp_rowptr_from_top(src, 0) + sx0 * srcbytespp; - pdst = bmp_rowptr_from_top(jbmp, 0) + dx0 * srcbytespp; - for (j = 0; j < src->height; j++, pdst += jbmpbytewidth, psrc += - srcbytewidth) - memcpy(pdst, psrc, dx); - } - if (gappos != NULL) - willus_dmem_free(9, (double **) &gappos, funcname); -} - -/* - ** flags&1 : trim c1 - ** flags&2 : trim c2 - ** flags&4 : trim r1 - ** flags&8 : trim r2 - ** flags&16 : Find rowbase, font size, etc. - ** - ** Row base is where row dist crosses 50% on r2 side. - ** Font size is where row dist crosses 5% on other side (r1 side). - ** Lowercase font size is where row dist crosses 50% on r1 side. - ** - ** For 12 pt font: - ** Single spacing is 14.66 pts (Calibri), 13.82 pts (Times), 13.81 pts (Arial) - ** Size of cap letter is 7.7 pts (Calibri), 8.1 pts (Times), 8.7 pts (Arial) - ** Size of small letter is 5.7 pts (Calibri), 5.6 pts (Times), 6.5 pts (Arial) - ** Mean line spacing = 1.15 - 1.22 (~1.16) - ** Mean cap height = 0.68 - ** Mean small letter height = 0.49 - ** - */ -static void bmpregion_trim_margins(BMPREGION *region, int *colcount0, - int *rowcount0, int flags) - -{ - int i, j, n; /* ,r1,r2,dr1,dr2,dr,vtrim,vspace; */ - int *colcount, *rowcount; - static char *funcname = "bmpregion_trim_margins"; - - /* To detect a hyphen, we need to trim and calc text base row */ - if (flags & 32) - flags |= 0x1f; - if (colcount0 == NULL) - willus_dmem_alloc_warn(10, (void **) &colcount, - sizeof(int) * (region->c2 + 1), funcname, 10); - else - colcount = colcount0; - if (rowcount0 == NULL) - willus_dmem_alloc_warn(11, (void **) &rowcount, - sizeof(int) * (region->r2 + 1), funcname, 10); - else - rowcount = rowcount0; - n = region->c2 - region->c1 + 1; - /* - printf("Trim: reg=(%d,%d) - (%d,%d)\n",region->c1,region->r1,region->c2,region->r2); - if (region->c2+1 > cca || region->r2+1 > rca) - { - printf("A ha 0!\n"); - exit(10); - } - */ - memset(colcount, 0, (region->c2 + 1) * sizeof(int)); - memset(rowcount, 0, (region->r2 + 1) * sizeof(int)); - for (j = region->r1; j <= region->r2; j++) { - unsigned char *p; - p = bmp_rowptr_from_top(region->bmp8, j) + region->c1; - for (i = 0; i < n; i++, p++) - if (p[0] < region->bgcolor) { - rowcount[j]++; - colcount[i + region->c1]++; - } - } - /* - ** Trim excess margins - */ - if (flags & 1) - trim_to(colcount, ®ion->c1, region->c2, - src_left_to_right ? 2.0 : 4.0); - if (flags & 2) - trim_to(colcount, ®ion->c2, region->c1, - src_left_to_right ? 4.0 : 2.0); - if (colcount0 == NULL) - willus_dmem_free(10, (double **) &colcount, funcname); - if (flags & 4) - trim_to(rowcount, ®ion->r1, region->r2, 4.0); - if (flags & 8) - trim_to(rowcount, ®ion->r2, region->r1, 4.0); - if (flags & 16) { - int maxcount, mc2, h2; - double f; - - maxcount = 0; - for (i = region->r1; i <= region->r2; i++) - if (rowcount[i] > maxcount) - maxcount = rowcount[i]; - mc2 = maxcount / 2; - for (i = region->r2; i >= region->r1; i--) - if (rowcount[i] > mc2) - break; - region->rowbase = i; - for (i = region->r1; i <= region->r2; i++) - if (rowcount[i] > mc2) - break; - region->h5050 = region->lcheight = region->rowbase - i + 1; - mc2 = maxcount / 20; - for (i = region->r1; i <= region->r2; i++) - if (rowcount[i] > mc2) - break; - region->capheight = region->rowbase - i + 1; - /* - ** Sanity check capheight and lcheight - */ - h2 = height2_calc(&rowcount[region->r1], region->r2 - region->r1 + 1); -#if (WILLUSDEBUGX & 8) - if (region->c2-region->c1 > 1500) - printf("reg %d x %d (%d,%d) - (%d,%d) h2=%d ch/h2=%g\n",region->c2-region->c1+1,region->r2-region->r1+1,region->c1,region->r1,region->c2,region->r2,h2,(double)region->capheight/h2); -#endif - if (region->capheight < h2 * 0.75) - region->capheight = h2; - f = (double) region->lcheight / region->capheight; - if (f < 0.55) - region->lcheight = (int) (0.72 * region->capheight + .5); - else if (f > 0.85) - region->lcheight = (int) (0.72 * region->capheight + .5); -#if (WILLUSDEBUGX & 8) - if (region->c2-region->c1 > 1500) - printf(" lcheight final = %d\n",region->lcheight); -#endif -#if (WILLUSDEBUGX & 10) - if (region->c2-region->c1 > 1500 && region->r2-region->r1 < 100) - { - static int append=0; - FILE *f; - int i; - f=fopen("textrows.ep",append==0?"w":"a"); - append=1; - for (i=region->r1;i<=region->r2;i++) - fprintf(f,"%d %g\n",region->rowbase-i,(double)rowcount[i]/maxcount); - fprintf(f,"//nc\n"); - fclose(f); - } -#endif - } else { - region->h5050 = region->r2 - region->r1 + 1; - region->capheight = 0.68 * (region->r2 - region->r1 + 1); - region->lcheight = 0.5 * (region->r2 - region->r1 + 1); - region->rowbase = region->r2; - } -#if (WILLUSDEBUGX & 2) - printf("trim:\n reg->c1=%d, reg->c2=%d\n",region->c1,region->c2); - printf(" reg->r1=%d, reg->r2=%d, reg->rowbase=%d\n\n",region->r1,region->r2,region->rowbase); -#endif - if (rowcount0 == NULL) - willus_dmem_free(11, (double **) &rowcount, funcname); -} - -/* - ** Does region end in a hyphen? If so, fill in HYPHENINFO structure. - */ -static void bmpregion_hyphen_detect(BMPREGION *region) - -{ - int i, j; /* ,r1,r2,dr1,dr2,dr,vtrim,vspace; */ - int width; - int *r0, *r1, *r2, *r3; - int rmin, rmax, rowbytes, nrmid, rsum; - int cstart, cend, cdir; - unsigned char *p; - static char *funcname = "bmpregion_hyphen_detect"; - -#if (WILLUSDEBUGX & 16) - static int count=0; - char pngfile[256]; - FILE *out; - - count++; - printf("@bmpregion_hyphen_detect count=%d\n",count); - sprintf(pngfile,"word%04d.png",count); - bmpregion_write(region,pngfile); - sprintf(pngfile,"word%04d.txt",count); - out=fopen(pngfile,"w"); - fprintf(out,"c1=%d, c2=%d, r1=%d, r2=%d\n",region->c1,region->c2,region->r1,region->r2); - fprintf(out,"lcheight=%d\n",region->lcheight); -#endif - - region->hyphen.ch = -1; - region->hyphen.c2 = -1; - if (!k2_hyphen_detect) - return; - width = region->c2 - region->c1 + 1; - if (width < 2) - return; - willus_dmem_alloc_warn(27, (void **) &r0, sizeof(int) * 4 * width, funcname, - 10); - r1 = &r0[width]; - r2 = &r1[width]; - r3 = &r2[width]; - for (i = 0; i < width; i++) - r0[i] = r1[i] = r2[i] = r3[i] = -1; - rmin = region->rowbase - region->capheight - region->lcheight * .04; - if (rmin < region->r1) - rmin = region->r1; - rmax = region->rowbase + region->lcheight * .04; - if (rmax > region->r2) - rmax = region->r2; - rowbytes = bmp_bytewidth(region->bmp8); - p = bmp_rowptr_from_top(region->bmp8, 0); - nrmid = rsum = 0; - if (src_left_to_right) { - cstart = region->c2; - cend = region->c1 - 1; - cdir = -1; - } else { - cstart = region->c1; - cend = region->c2 + 1; - cdir = 1; - } -#if (WILLUSDEBUGX & 16) - fprintf(out," j r0 r1 r2 r3\n"); -#endif - for (j = cstart; j != cend; j += cdir) { - int r, rmid, dr, drmax; - -// printf("j=%d\n",j); - rmid = (rmin + rmax) / 2; -// printf(" rmid=%d\n",rmid); - drmax = region->r2 + 1 - rmid > rmid - region->r1 + 1 ? - region->r2 + 1 - rmid : rmid - region->r1 + 1; - /* Find dark region closest to center line */ - for (dr = 0; dr < drmax; dr++) { - if (rmid + dr <= region->r2 - && p[(rmid + dr) * rowbytes + j] < region->bgcolor) - break; - if (rmid - dr >= region->r1 - && p[(rmid - dr) * rowbytes + j] < region->bgcolor) { - dr = -dr; - break; - } - } -#if (WILLUSDEBUGX & 16) - fprintf(out," dr=%d/%d, rmid+dr=%d, rmin=%d, rmax=%d, nrmid=%d\n",dr,drmax,rmid+dr,rmin,rmax,nrmid); -#endif - /* No dark detected or mark is outside hyphen region? */ - /* Termination criterion #1 */ - if (dr >= drmax - || (nrmid > 2 && (double) nrmid / region->lcheight > .1 - && (rmid + dr < rmin || rmid + dr > rmax))) { - if (region->hyphen.ch >= 0 && dr >= drmax) - continue; - if (nrmid > 2 && (double) nrmid / region->lcheight > .35) { - region->hyphen.ch = j - cdir; - region->hyphen.r1 = rmin; - region->hyphen.r2 = rmax; - } - if (dr < drmax) { - region->hyphen.c2 = j; - break; - } - continue; - } - if (region->hyphen.ch >= 0) { - region->hyphen.c2 = j; - break; - } - nrmid++; - rmid += dr; - /* Dark spot is outside expected hyphen area */ - /* - if (rmidrmax) - { - if (nrmid>0) - break; - continue; - } - */ - for (r = rmid; r >= region->r1; r--) - if (p[r * rowbytes + j] >= region->bgcolor) - break; - r1[j - region->c1] = r + 1; - r0[j - region->c1] = -1; - if (r >= region->r1) { - for (; r >= region->r1; r--) - if (p[r * rowbytes + j] < region->bgcolor) - break; - if (r >= region->r1) - r0[j - region->c1] = r; - } - for (r = rmid; r <= region->r2; r++) - if (p[r * rowbytes + j] >= region->bgcolor) - break; - r2[j - region->c1] = r - 1; - r3[j - region->c1] = -1; - if (r <= region->r2) { - for (; r <= region->r2; r++) - if (p[r * rowbytes + j] < region->bgcolor) - break; - if (r <= region->r2) - r3[j - region->c1] = r; - } -#if (WILLUSDEBUGX & 16) - fprintf(out," %4d %4d %4d %4d %4d\n",j,r0[j-region->c1],r1[j-region->c1],r2[j-region->c1],r3[j-region->c1]); -#endif - if (region->hyphen.c2 < 0 - && (r0[j - region->c1] >= 0 || r3[j - region->c1] >= 0)) - region->hyphen.c2 = j; - /* Termination criterion #2 */ - if (nrmid > 2 && (double) nrmid / region->lcheight > .35 - && (r1[j - region->c1] > rmax || r2[j - region->c1] < rmin)) { - region->hyphen.ch = j - cdir; - region->hyphen.r1 = rmin; - region->hyphen.r2 = rmax; - if (region->hyphen.c2 < 0) - region->hyphen.c2 = j; -#if (WILLUSDEBUGX & 16) - fprintf(out," Termination #2\n"); -#endif - break; - } - // rc=(r1[j-region->c1]+r2[j-region->c1])/2; - /* DQ possible hyphen if r1/r2 out of range */ - if (nrmid > 1) { - /* Too far away from last values? */ - if ((double) (rmin - r1[j - region->c1]) / region->lcheight > .1 - || (double) (r2[j - region->c1] - rmax) / region->lcheight - > .1) { -#if (WILLUSDEBUGX & 16) - fprintf(out," Too far from last values.\n"); -#endif - break; - } - if ((double) nrmid / region->lcheight > .1 && nrmid > 1) { - if ((double) fabs(rmin - r1[j - region->c1]) / region->lcheight - > .1 - || (double) (rmax - r2[j - region->c1]) - / region->lcheight > .1) { -#if (WILLUSDEBUGX & 16) - fprintf(out," Too far from last values (2).\n"); -#endif - break; - } - } - } - if (nrmid == 1 || r1[j - region->c1] < rmin) - rmin = r1[j - region->c1]; - if (nrmid == 1 || r2[j - region->c1] > rmax) - rmax = r2[j - region->c1]; - if ((double) nrmid / region->lcheight > .1 && nrmid > 1) { - double rmean; - - /* Can't be too thick */ - if ((double) (rmax - rmin + 1) / region->lcheight > .55 - || (double) (rmax - rmin + 1) / region->lcheight < .05) { -#if (WILLUSDEBUGX & 16) - fprintf(out," Too thick or too thin: rmax=%d, rmin=%d, lch=%d rat=%g (.05 - .55).\n", - rmax,rmin,region->lcheight,(double)(rmax-rmin+1)/region->lcheight); -#endif - break; - } - /* Must be reasonably well centered above baseline */ - rmean = (double) (rmax + rmin) / 2; - if ((double) (region->rowbase - rmean) / region->lcheight < 0.35 - || (double) (region->rowbase - rmean) / region->lcheight - > 0.85) { -#if (WILLUSDEBUGX & 16) - fprintf(out," Not well centered (1).\n"); -#endif - break; - } - if ((double) (region->rowbase - rmax) / region->lcheight < 0.2 - || (double) (region->rowbase - rmin) / region->lcheight - > 0.92) { -#if (WILLUSDEBUGX & 16) - fprintf(out," Not well centered (2).\n"); -#endif - break; - } - } - } -#if (WILLUSDEBUGX & 16) - fprintf(out," ch=%d, c2=%d, r1=%d, r2=%d\n",region->hyphen.ch,region->hyphen.c2,region->hyphen.r1,region->hyphen.r2); - fclose(out); -#endif - /* More sanity checks--better to miss a hyphen than falsely detect it. */ - if (region->hyphen.ch >= 0) { - double ar; - /* If it's only a hyphen, then it's probably actually a dash--don't detect it. */ - if (region->hyphen.c2 < 0) - region->hyphen.ch = -1; - /* Check aspect ratio */ - ar = (double) (region->hyphen.r2 - region->hyphen.r1) / nrmid; - if (ar < 0.08 || ar > 0.75) - region->hyphen.ch = -1; - } - willus_dmem_free(27, (double **) &r0, funcname); -#if (WILLUSDEBUGX & 16) - if (region->hyphen.ch>=0) - printf("\n\n GOT HYPHEN.\n\n"); - printf(" Exiting bmpregion_hyphen_detect\n"); -#endif -} - -#if (defined(WILLUSDEBUGX) || defined(WILLUSDEBUG)) -static void bmpregion_write(BMPREGION *region,char *filename) - -{ - int i,bpp; - WILLUSBITMAP *bmp,_bmp; - - bmp=&_bmp; - bmp_init(bmp); - bmp->width=region->c2-region->c1+1; - bmp->height=region->r2-region->r1+1; - bmp->bpp=region->bmp->bpp; - bpp=bmp->bpp==8?1:3; - bmp_alloc(bmp); - for (i=0;i<256;i++) - bmp->red[i]=bmp->green[i]=bmp->blue[i]=i; - for (i=0;iheight;i++) - { - unsigned char *s,*d; - s=bmp_rowptr_from_top(region->bmp,region->r1+i)+region->c1*bpp; - d=bmp_rowptr_from_top(bmp,i); - memcpy(d,s,bmp->width*bpp); - } - bmp_write(bmp,filename,stdout,97); - bmp_free(bmp); -} -#endif - -#if (WILLUSDEBUGX & 6) -static void breakinfo_echo(BREAKINFO *breakinfo) - -{ - int i; - printf("@breakinfo_echo...\n"); - for (i=0;in;i++) - printf(" %2d. r1=%4d, rowbase=%4d, r2=%4d, c1=%4d, c2=%4d\n", - i+1,breakinfo->textrow[i].r1, - breakinfo->textrow[i].rowbase, - breakinfo->textrow[i].r2, - breakinfo->textrow[i].c1, - breakinfo->textrow[i].c2); -} -#endif - -/* - ** Calculate weighted height of a rectangular region. - ** This weighted height is intended to be close to the height of - ** a capital letter, or the height of the majority of the region. - ** - */ -static int height2_calc(int *rc, int n) - -{ - int i, thresh, i1, h2; - int *c; - static char *funcname = "height2_calc"; -#if (WILLUSDEBUGX & 8) - int cmax; -#endif - - if (n <= 0) - return (1); - willus_dmem_alloc_warn(12, (void **) &c, sizeof(int) * n, funcname, 10); - memcpy(c, rc, n * sizeof(int)); - sorti(c, n); -#if (WILLUSDEBUGX & 8) - cmax=c[n-1]; -#endif - for (i = 0; i < n - 1 && c[i] == 0; i++) - ; - thresh = c[(i + n) / 3]; - willus_dmem_free(12, (double **) &c, funcname); - for (i = 0; i < n - 1; i++) - if (rc[i] >= thresh) - break; - i1 = i; - for (i = n - 1; i > i1; i--) - if (rc[i] >= thresh) - break; -#if (WILLUSDEBUGX & 8) -// printf("thresh = %g, i1=%d, i2=%d\n",(double)thresh/cmax,i1,i); -#endif - h2 = i - i1 + 1; /* Guaranteed to be >=1 */ - return (h2); -} - -static void trim_to(int *count, int *i1, int i2, double gaplen) - -{ - int del, dcount, igaplen, clevel, dlevel, defect_start, last_defect; - - igaplen = (int) (gaplen * src_dpi / 72.); - if (igaplen < 1) - igaplen = 1; - /* clevel=(int)(defect_size_pts*src_dpi/72./3.); */ - clevel = 0; - dlevel = (int) (pow(defect_size_pts * src_dpi / 72., 2.) * PI / 4. + .5); - del = i2 > (*i1) ? 1 : -1; - defect_start = -1; - last_defect = -1; - dcount = 0; - for (; (*i1) != i2; (*i1) = (*i1) + del) { - if (count[(*i1)] <= clevel) { - dcount = 0; /* Reset defect size */ - continue; - } - /* Mark found */ - if (dcount == 0) { - if (defect_start >= 0) - last_defect = defect_start; - defect_start = (*i1); - } - dcount += count[(*i1)]; - if (dcount >= dlevel) { - if (last_defect >= 0 && abs(defect_start - last_defect) <= igaplen) - (*i1) = last_defect; - else - (*i1) = defect_start; - return; - } - } - if (defect_start < 0) - return; - if (last_defect < 0) { - (*i1) = defect_start; - return; - } - if (abs(defect_start - last_defect) <= igaplen) - (*i1) = last_defect; - else - (*i1) = defect_start; -} - -/* - ** A region that needs its line spacing and justification analyzed. - ** - ** The region may be wider than the max desirable region width. - ** - ** Input: breakinfo should be valid row-break information for the region. - ** - ** Calls bmpregion_one_row_wrap_and_add() for each text row from the - ** breakinfo structure that is within the region. - ** - */ -static void bmpregion_analyze_justification_and_line_spacing(BMPREGION *region, - BREAKINFO *breakinfo, MASTERINFO *masterinfo, int *colcount, - int *rowcount, WPDFPAGEINFO *pageinfo, int allow_text_wrapping, - double force_scale) - -{ - int i, i1, i2, ntr, mean_row_gap, maxgap, line_spacing, nls, nch; - BMPREGION *newregion, _newregion; - double *id, *c1, *c2, *ch, *lch, *ls; - int *just, *indented, *short_line; - double capheight, lcheight, fontsize; - int textheight, ragged_right, src_line_spacing, mingap; - static char *funcname = "bmpregion_analyze_justification_and_line_spacing"; - -#if (WILLUSDEBUGX & 1) - printf("@bmpregion_analyze_justification_and_line_spacing"); - printf(" (%d,%d) - (%d,%d)\n",region->c1,region->r1,region->c2,region->r2); - printf(" centering = %d\n",breakinfo->centered); -#endif -#if (WILLUSDEBUGX & 2) - breakinfo_echo(breakinfo); -#endif - - /* Locate the vertical part indices in the breakinfo structure */ - newregion = &_newregion; - breakinfo_sort_by_row_position(breakinfo); - for (i = 0; i < breakinfo->n; i++) { - TEXTROW *textrow; - textrow = &breakinfo->textrow[i]; - if ((textrow->r1 + textrow->r2) / 2 >= region->r1) - break; - } - if (i >= breakinfo->n) - return; - i1 = i; - for (; i < breakinfo->n; i++) { - TEXTROW *textrow; - textrow = &breakinfo->textrow[i]; - if ((textrow->r1 + textrow->r2) / 2 > region->r2) - break; - } - i2 = i - 1; - if (i2 < i1) - return; - ntr = i2 - i1 + 1; -#if (WILLUSDEBUGX & 1) - printf(" i1=%d, i2=%d, ntr=%d\n",i1,i2,ntr); -#endif - - willus_dmem_alloc_warn(13, (void **) &c1, sizeof(double) * 6 * ntr, - funcname, 10); - willus_dmem_alloc_warn(14, (void **) &just, sizeof(int) * 3 * ntr, funcname, - 10); - c2 = &c1[ntr]; - ch = &c2[ntr]; - lch = &ch[ntr]; - ls = &lch[ntr]; - id = &ls[ntr]; - indented = &just[ntr]; - short_line = &indented[ntr]; - for (i = 0; i < ntr; i++) - id[i] = i; - - /* Find baselines / font size */ - capheight = lcheight = 0.; - maxgap = -1; - for (nch = nls = 0, i = i1; i <= i2; i++) { - TEXTROW *textrow; - double ar, rh; - int marking_flags; - - textrow = &breakinfo->textrow[i]; - c1[i - i1] = (double) textrow->c1; - c2[i - i1] = (double) textrow->c2; - if (i < i2 && maxgap < textrow->gap) { - maxgap = textrow->gap; - if (maxgap < 2) - maxgap = 2; - } - if (textrow->c2 < textrow->c1) - ar = 100.; - else - ar = (double) (textrow->r2 - textrow->r1 + 1) - / (double) (textrow->c2 - textrow->c1 + 1); - rh = (double) (textrow->r2 - textrow->r1 + 1) / src_dpi; - if (i < i2 && ar <= no_wrap_ar_limit - && rh <= no_wrap_height_limit_inches) - ls[nls++] = breakinfo->textrow[i + 1].r1 - textrow->r1; - if (ar <= no_wrap_ar_limit && rh <= no_wrap_height_limit_inches) { - ch[nch] = textrow->capheight; - lch[nch] = textrow->lcheight; - nch++; - } - - /* Mark region w/gray, mark rowbase also */ - marking_flags = (i == i1 ? 0 : 1) | (i == i2 ? 0 : 2); - if (i < i2 || textrow->r2 - textrow->rowbase > 1) - marking_flags |= 0x10; - (*newregion) = (*region); - newregion->r1 = textrow->r1; - newregion->r2 = textrow->r2; - newregion->c1 = textrow->c1; - newregion->c2 = textrow->c2; - newregion->rowbase = textrow->rowbase; - mark_source_page(newregion, 5, marking_flags); -#if (WILLUSDEBUGX & 1) - printf(" Row %2d: (%4d,%4d) - (%4d,%4d) rowbase=%4d, lch=%d, h5050=%d, rh=%d\n",i-i1+1,textrow->c1,textrow->r1,textrow->c2,textrow->r2,textrow->rowbase,textrow->lcheight,textrow->h5050,textrow->rowheight); -#endif - } - wrapbmp_set_maxgap(maxgap); - if (nch < 1) - capheight = lcheight = 2; // Err on the side of too small - else { - capheight = median_val(ch, nch); - lcheight = median_val(lch, nch); - } -// printf("capheight = %g, lcheight = %g\n",capheight,lcheight); - bmpregion_is_centered(region, breakinfo, i1, i2, &textheight); - /* - ** For 12 pt font: - ** Single spacing is 14.66 pts (Calibri), 13.82 pts (Times), 13.81 pts (Arial) - ** Size of cap letter is 7.7 pts (Calibri), 8.1 pts (Times), 8.7 pts (Arial) - ** Size of small letter is 5.7 pts (Calibri), 5.6 pts (Times), 6.5 pts (Arial) - ** Mean line spacing = 1.15 - 1.22 (~1.16) - ** Mean cap height = 0.68 - ** Mean small letter height = 0.49 - */ - fontsize = (capheight + lcheight) / 1.17; -// printf("font size = %g pts.\n",(fontsize/src_dpi)*72.); - /* - ** Set line spacing for this region - */ - if (nls > 0) - src_line_spacing = median_val(ls, nls); - else - src_line_spacing = fontsize * 1.2; - if (vertical_line_spacing < 0 - && src_line_spacing - <= fabs(vertical_line_spacing) * fontsize * 1.16) - line_spacing = src_line_spacing; - else - line_spacing = fabs(vertical_line_spacing) * fontsize * 1.16; -#if (WILLUSDEBUGX & 1) - printf(" font size = %.2f pts = %d pixels\n",(fontsize/src_dpi)*72.,(int)(fontsize+.5)); - printf(" src_line_spacing = %d, line_spacing = %d\n",src_line_spacing,line_spacing); -#endif - /* - if (ntr==1) - rheight= (int)((breakinfo->textrow[i1].r2 - breakinfo->textrow[i1].r1)*1.25+.5); - else - rheight = (int)((double)(breakinfo->textrow[i2].rowbase - breakinfo->textrow[i1].rowbase)/(ntr-1)+.5); - */ - mean_row_gap = line_spacing - textheight; - if (mean_row_gap <= 1) - mean_row_gap = 1; - mingap = mean_row_gap / 4; - if (mingap < 1) - mingap = 1; - - /* Try to figure out if we have a ragged right edge */ - if (ntr < 3) - ragged_right = 1; - else { - int flushcount; - - if (src_left_to_right) { - for (flushcount = i = 0; i < ntr; i++) { -#if (WILLUSDEBUGX & 1) - printf(" flush_factors[%d] = %g (<.5), %g in (<.1)\n", - i,(double)(region->c2-c2[i])/textheight,(double)(region->c2-c2[i])/src_dpi); -#endif - if ((double) (region->c2 - c2[i]) / textheight < 0.5 - && (double) (region->c2 - c2[i]) / src_dpi < 0.1) - flushcount++; - } - } else { - for (flushcount = i = 0; i < ntr; i++) { -#if (WILLUSDEBUGX & 1) - printf(" flush_factors[%d] = %g (<.5), %g in (<.1)\n", - i,(double)(c1[i]-region->c1)/textheight,(double)(c1[i]-region->c1)/src_dpi); -#endif - if ((double) (c1[i] - region->c1) / textheight < 0.5 - && (double) (c1[i] - region->c1) / src_dpi < 0.1) - flushcount++; - } - } - ragged_right = (flushcount <= ntr / 2); - /* - if (src_left_to_right) - { - sortxyd(c2,id,ntr); - del = region->c2 - c2[ntr-1-ntr/3]; - sortxyd(id,c2,ntr); - } - else - { - sortxyd(c1,id,ntr); - del = c1[ntr/3] - region->c1; - sortxyd(id,c1,ntr); - } - del /= textheight; - printf("del=%g\n",del); - ragged_right = (del > 0.5); - */ - } -#if (WILLUSDEBUGX & 1) - printf("ragged_right=%d\n",ragged_right); -#endif - - /* Store justification and other info line by line */ - for (i = i1; i <= i2; i++) { - double indent1, del; - double i1f, ilfi, i2f, ilf, ifmin, dif; - int centered; - - TEXTROW *textrow; - textrow = &breakinfo->textrow[i]; - i1f = (double) (c1[i - i1] - region->c1) - / (region->c2 - region->c1 + 1); - i2f = (double) (region->c2 - c2[i - i1]) - / (region->c2 - region->c1 + 1); - ilf = src_left_to_right ? i1f : i2f; - ilfi = ilf * (region->c2 - region->c1 + 1) / src_dpi; /* Indent in inches */ - ifmin = i1f < i2f ? i1f : i2f; - dif = fabs(i1f - i2f); - if (ifmin < .01) - ifmin = 0.01; - if (src_left_to_right) - indent1 = (double) (c1[i - i1] - region->c1) / textheight; - else - indent1 = (double) (region->c2 - c2[i - i1]) / textheight; - if (preserve_indentation == 0) indent1 = 0; -// printf(" row %2d: indent1=%g\n",i-i1,indent1); - if (!breakinfo->centered) { - indented[i - i1] = (indent1 > 0.5 && ilfi < 1.2 && ilf < .25); - centered = - (!indented[i - i1] && indent1 > 1.0 && dif / ifmin < 0.5); - } else { - centered = (dif < 0.1 || dif / ifmin < 0.5); - indented[i - i1] = (indent1 > 0.5 && ilfi < 1.2 && ilf < .25 - && !centered); - } -#if (WILLUSDEBUGX & 1) - printf("Indent %d: %d. indent1=%g, ilf=%g, centered=%d\n",i-i1+1,indented[i-i1],indent1,ilf,centered); - printf(" indent1=%g, i1f=%g, i2f=%g\n",indent1,i1f,i2f); -#endif - if (centered) - just[i - i1] = 4; - else { - /* - ** The .01 favors left justification over right justification in - ** close cases. - */ - if (src_left_to_right) - just[i - i1] = indented[i - i1] || (i1f < i2f + .01) ? 0 : 8; - else - just[i - i1] = indented[i - i1] || (i2f < i1f + .01) ? 8 : 0; - } - if (src_left_to_right) - del = (double) (region->c2 - textrow->c2); - else - del = (double) (textrow->c1 - region->c1); - /* Should we keep wrapping after this line? */ - if (!ragged_right) - short_line[i - i1] = (del / textheight > 0.5); - else - short_line[i - i1] = (del / (region->c2 - region->c1) > 0.25); - /* If this row is a bigger/smaller row (font) than the next row, don't wrap. */ - if (!short_line[i - i1] && i < i2) { - TEXTROW *t1; - t1 = &breakinfo->textrow[i + 1]; - if ((textrow->h5050 > t1->h5050 * 1.5 - || textrow->h5050 * 1.5 < t1->h5050) - && (i == 0 - || (i > 0 - && (textrow->rowheight > t1->rowheight * 1.5 - || textrow->rowheight * 1.5 - < t1->rowheight)))) - short_line[i - i1] = 1; - } - if (!ragged_right) - just[i - i1] |= 0x40; -#if (WILLUSDEBUGX & 1) - printf(" just[%d]=0x%02X, shortline[%d]=%d\n",i-i1,just[i-i1],i-i1,short_line[i-i1]); - printf(" textrow->c2=%d, region->c2=%d, del=%g, textheight=%d\n",textrow->c2,region->c2,del,textheight); -#endif - /* If short line, it should still be fully justified if it is wrapped. */ - /* - if (short_line[i-i1]) - just[i-i1] = (just[i-i1]&0xf)|0x60; - */ - } - /* - { - double mean1,mean2,stdev1,stdev2; - array_mean(c1,ntr,&mean1,&stdev1); - array_mean(c2,ntr,&mean2,&stdev2); - printf("Mean c1, c2 = %g, %g; stddevs = %g, %g\n",mean1,mean2,stdev1,stdev2); - printf("textheight = %d, line_spacing = %d\n",textheight,line_spacing); - } - */ - -#if (WILLUSDEBUGX & 1) - if (!allow_text_wrapping) - printf("Processing text row by row (no wrapping)...\n"); -#endif - /* - ** Process row by row - */ - for (i = i1; i <= i2; i++) { - TEXTROW *textrow; - int justflags, trimflags, centered, marking_flags, gap; - -#if (WILLUSDEBUGX & 1) - aprintf("Row " ANSI_YELLOW "%d of %d" ANSI_NORMAL " (wrap=%d)\n",i-i1+1,i2-i1+1,allow_text_wrapping); -#endif - textrow = &breakinfo->textrow[i]; - (*newregion) = (*region); - newregion->r1 = textrow->r1; - newregion->r2 = textrow->r2; -#if (WILLUSDEBUGX & 1) - printf("Row %2d: r1=%4d, r2=%4d, linespacing=%3d\n",i,textrow->r1,textrow->r2,line_spacing); -#endif - - /* The |3 tells it to use the user settings for left/right/center */ - justflags = just[i - i1] | 0x3; - centered = ((justflags & 0xc) == 4); -#if (WILLUSDEBUGX & 1) - printf(" justflags[%d]=0x%2X, centered=%d, indented=%d\n",i-i1,justflags,centered,indented[i-i1]); -#endif - if (allow_text_wrapping) { - /* If this line is indented or if the justification has changed, */ - /* then start a new line. */ - if (centered || indented[i - i1] - || (i > i1 - && (just[i - i1] & 0xc) != (just[i - i1 - 1] & 0xc))) { -#ifdef WILLUSDEBUG - printf("wrapflush4\n"); -#endif - wrapbmp_flush(masterinfo, 0, pageinfo, 1); - } -#ifdef WILLUSDEBUG - printf(" c1=%d, c2=%d\n",newregion->c1,newregion->c2); -#endif - marking_flags = 0xc | (i == i1 ? 0 : 1) | (i == i2 ? 0 : 2); - bmpregion_one_row_wrap_and_add(newregion, breakinfo, i, i1, i2, - masterinfo, justflags, colcount, rowcount, pageinfo, - line_spacing, mean_row_gap, textrow->rowbase, marking_flags, - indented[i - i1]); - if (centered || short_line[i - i1]) { -#ifdef WILLUSDEBUG - printf("wrapflush5\n"); -#endif - wrapbmp_flush(masterinfo, 0, pageinfo, 2); - } - continue; - } -#ifdef WILLUSDEBUG - printf("wrapflush5a\n"); -#endif - - /* No wrapping allowed: process whole line as one region */ - wrapbmp_flush(masterinfo, 0, pageinfo, 1); - /* If default justifications, ignore all analysis and just center it. */ - if (dst_justify < 0 && dst_fulljustify < 0) { - newregion->c1 = region->c1; - newregion->c2 = region->c2; - justflags = 0xad; /* Force centered region, no justification */ - trimflags = 0x80; - } else - trimflags = 0; - /* No wrapping: text wrap, trim flags, vert breaks, fscale, just */ - bmpregion_add(newregion, breakinfo, masterinfo, 0, trimflags, 0, - force_scale, justflags, 5, colcount, rowcount, pageinfo, 0, - textrow->r2 - textrow->rowbase); - /* Compute line spacing between rows */ - { - int thisgap, gap_allowed; - double fs, ls_allowed; - - thisgap = - (i < i2) ? - textrow->gap : - textrow->rowheight - - (textrow->rowbase + last_rowbase_internal); -#if (WILLUSDEBUGX & 1) - printf(" thisgap=%3d, vls = %g\n",thisgap,vertical_line_spacing); -#endif - fs = (textrow->capheight + textrow->lcheight) / 1.17; - if (fs < fontsize / 4.) /* Probably not text?? */ - fs = fontsize; - ls_allowed = fabs(vertical_line_spacing) * fs * 1.16; - /* If close to median line spacing, use median line spacing */ - /* ... Good idea?? */ - if (line_spacing > .5 && fabs(ls_allowed / line_spacing - 1.0) < .2) - ls_allowed = line_spacing; - gap_allowed = (int) (0.5 + ls_allowed - - (textrow->r2 - textrow->r1 + 1)); -#if (WILLUSDEBUGX & 1) - printf(" gap_allowed = %3d\n",gap_allowed); -#endif - if (vertical_line_spacing < 0) - gap = thisgap > gap_allowed ? gap_allowed : thisgap; - else - gap = gap_allowed; - /* - gap = gap1 < gap_allowed ? gap_allowed : gap1; - if (igap > gap1) - { - int gap_allowed; - srcls = (textrow->r2-textrow->r1+1)+textrow->gap; - fs = (textrow->capheight+textrow->lcheight)/1.17; - ls_allowed=fabs(vertical_line_spacing)*fs*1.16; - gap_allowed=ls_allowed-(textrow->r2-textrow->r1+1); - if (gap_allowed < textrow->gap) - gap_allowed = textrow->gap; - gap = gap1 > gap_allowed ? gap_allowed : gap1; - } - else - gap = textrow->gap; - } - else - { - gap = textrow->rowheight - (textrow->rowbase + last_rowbase_internal); - if (gap < mean_row_gap/2.) - gap = mean_row_gap; - } - - } - else - { - gap = line_spacing - (textrow->r2-textrow->r1+1); - if (gap < mean_row_gap/2.) - gap = mean_row_gap; - } - */ - if (gap < mingap) - gap = mingap; -#if (WILLUSDEBUGX & 1) - printf(" gap = %3d (mingap=%d)\n",gap,mingap); -#endif - if (i < i2) - dst_add_gap_src_pixels("No-wrap line", masterinfo, gap); - else { - last_h5050_internal = textrow->h5050; - beginning_gap_internal = gap; - } - } - } - willus_dmem_free(14, (double **) &just, funcname); - willus_dmem_free(13, (double **) &c1, funcname); -#ifdef WILLUSDEBUG - printf("Done wrap_and_add.\n"); -#endif -} - -static int bmpregion_is_centered(BMPREGION *region, BREAKINFO *breakinfo, - int i1, int i2, int *th) - -{ - int j, i, cc, n1, ntr; - int textheight; - -#if (WILLUSDEBUGX & 1) - printf("@bmpregion_is_centered: region=(%d,%d) - (%d,%d)\n",region->c1,region->r1,region->c2,region->r2); - printf(" nrows = %d\n",i2-i1+1); -#endif - ntr = i2 - i1 + 1; - for (j = 0; j < 3; j++) { - for (n1 = textheight = 0, i = i1; i <= i2; i++) { - TEXTROW *textrow; - double ar, rh; - - textrow = &breakinfo->textrow[i]; - if (textrow->c2 < textrow->c1) - ar = 100.; - else - ar = (double) (textrow->r2 - textrow->r1 + 1) - / (double) (textrow->c2 - textrow->c1 + 1); - rh = (double) (textrow->r2 - textrow->r1 + 1) / src_dpi; - if (j == 2 || (j >= 1 && rh <= no_wrap_height_limit_inches) - || (j == 0 && rh <= no_wrap_height_limit_inches - && ar <= no_wrap_ar_limit)) { - textheight += textrow->rowbase - textrow->r1 + 1; - n1++; - } - } - if (n1 > 0) - break; - } - textheight = (int) ((double) textheight / n1 + .5); - if (th != NULL) { - (*th) = textheight; -#if (WILLUSDEBUGX & 1) - printf(" textheight assigned (%d)\n",textheight); -#endif - return (breakinfo->centered); - } - - /* - ** Does region appear to be centered? - */ - for (cc = 0, i = i1; i <= i2; i++) { - double indent1, indent2; - -#if (WILLUSDEBUGX & 1) - printf(" tr[%d].c1,c2 = %d, %d\n",i,breakinfo->textrow[i].c1,breakinfo->textrow[i].c2); -#endif - indent1 = (double) (breakinfo->textrow[i].c1 - region->c1) / textheight; - indent2 = (double) (region->c2 - breakinfo->textrow[i].c2) / textheight; -#if (WILLUSDEBUGX & 1) - printf(" tr[%d].indent1,2 = %g, %g\n",i,indent1,indent2); -#endif - /* If only one line and it spans the entire region, call it centered */ - /* Sometimes this won't be the right thing to to. */ - if (i1 == i2 && indent1 < .5 && indent2 < .5) { -#if (WILLUSDEBUGX & 1) - printf(" One line default to bigger region (%s).\n",breakinfo->centered?"not centered":"centered"); -#endif - return (1); - } - if (fabs(indent1 - indent2) > 1.5) { -#if (WILLUSDEBUGX & 1) - printf(" Region not centered.\n"); -#endif - return (0); - } - if (indent1 > 1.0) - cc++; - } -#if (WILLUSDEBUGX & 1) - printf("Region centering: i=%d, i2=%d, cc=%d, ntr=%d\n",i,i2,cc,ntr); -#endif - if (cc > ntr / 2) { -#if (WILLUSDEBUGX & 1) - printf(" Region is centered (enough obviously centered lines).\n"); -#endif - return (1); - } -#if (WILLUSDEBUGX & 1) - printf(" Not centered (not enough obviously centered lines).\n"); -#endif - return (0); -} - -/* array.c */ -/* - ** - ** Compute mean and standard deviation - ** - */ -double array_mean(double *a, int n, double *mean, double *stddev) - -{ - int i; - double sum, avg, sum_sq; - - if (n < 1) - return (0.); - for (sum = sum_sq = i = 0; i < n; i++) - sum += a[i]; - avg = sum / n; - if (mean != NULL) - (*mean) = avg; - if (stddev != NULL) { - double sum_sq; - - for (sum_sq = i = 0; i < n; i++) - sum_sq += (a[i] - avg) * (a[i] - avg); - (*stddev) = sqrt(sum_sq / n); - } - return (avg); -} - -/* - ** CAUTION: This function re-orders the x[] array! - */ -static double median_val(double *x, int n) - -{ - int i1, n1; - - if (n < 4) - return (array_mean(x, n, NULL, NULL)); - sortd(x, n); - if (n == 4) { - n1 = 2; - i1 = 1; - } else if (n == 5) { - n1 = 3; - i1 = 1; - } else { - n1 = n / 3; - i1 = (n - n1) / 2; - } - return (array_mean(&x[i1], n1, NULL, NULL)); -} - -/* - ** - ** Searches the region for vertical break points and stores them into - ** the BREAKINFO structure. - ** - ** apsize_in = averaging aperture size in inches. Use -1 for dynamic aperture. - ** - */ -static void bmpregion_find_vertical_breaks(BMPREGION *region, - BREAKINFO *breakinfo, int *colcount, int *rowcount, double apsize_in) - -{ - static char *funcname = "bmpregion_find_vertical_breaks"; - int nr, i, brc, brcmin, dtrc, trc, aperture, aperturemax, figrow, labelrow; - int ntr, rhmin_pix; - BMPREGION *newregion, _newregion; - int *rowthresh; - double min_fig_height, max_fig_gap, max_label_height; - - min_fig_height = dst_min_figure_height_in; - max_fig_gap = 0.16; - max_label_height = 0.5; - /* Trim region and populate colcount/rowcount arrays */ - bmpregion_trim_margins(region, colcount, rowcount, src_trim ? 0xf : 0); - newregion = &_newregion; - (*newregion) = (*region); - if (debug) - printf("@bmpregion_find_vertical_breaks: (%d,%d) - (%d,%d)\n", - region->c1, region->r1, region->c2, region->r2); - /* - ** brc = consecutive blank pixel rows - ** trc = consecutive non-blank pixel rows - ** dtrc = number of non blank pixel rows since last dump - */ - nr = region->r2 - region->r1 + 1; - willus_dmem_alloc_warn(15, (void **) &rowthresh, sizeof(int) * nr, funcname, - 10); - brcmin = max_vertical_gap_inches * src_dpi; - aperturemax = (int) (src_dpi / 72. + .5); - if (aperturemax < 2) - aperturemax = 2; - aperture = (int) (src_dpi * apsize_in + .5); - /* - for (i=region->r1;i<=region->r2;i++) - printf("rowcount[%d]=%d\n",i,rowcount[i]); - */ - breakinfo->rhmean_pixels = 0; // Mean text row height - ntr = 0; // Number of text rows - /* Fill rowthresh[] array */ - for (dtrc = 0, i = region->r1; i <= region->r2; i++) { - int ii, i1, i2, sum, pt; - - if (apsize_in < 0.) { - aperture = (int) (dtrc / 13.7 + .5); - if (aperture > aperturemax) - aperture = aperturemax; - if (aperture < 2) - aperture = 2; - } - i1 = i - aperture / 2; - i2 = i1 + aperture - 1; - if (i1 < region->r1) - i1 = region->r1; - if (i2 > region->r2) - i2 = region->r2; - pt = (int) ((i2 - i1 + 1) * gtr_in * src_dpi + .5); /* pixel count threshold */ - if (pt < 1) - pt = 1; - /* Sum over row aperture */ - for (sum = 0, ii = i1; ii <= i2; sum += rowcount[ii], ii++) - ; - /* Does row have few enough black pixels to be considered blank? */ - if ((rowthresh[i - region->r1] = 10 * sum / pt) <= 40) { - if (dtrc > 0) { - breakinfo->rhmean_pixels += dtrc; - ntr++; - } - dtrc = 0; - } else - dtrc++; - } - if (dtrc > 0) { - breakinfo->rhmean_pixels += dtrc; - ntr++; - } - if (ntr > 0) - breakinfo->rhmean_pixels /= ntr; - /* - printf("rhmean=%d (ntr=%d)\n",breakinfo->rhmean_pixels,ntr); - { - FILE *f; - static int count=0; - f=fopen("rthresh.ep",count==0?"w":"a"); - count++; - for (i=region->r1;i<=region->r2;i++) - nprintf(f,"%d\n",rowthresh[i-region->r1]); - nprintf(f,"//nc\n"); - fclose(f); - } - */ - /* Minimum text row height required (pixels) */ - rhmin_pix = breakinfo->rhmean_pixels / 3; - if (rhmin_pix < .04 * src_dpi) - rhmin_pix = .04 * src_dpi; - if (rhmin_pix > .13 * src_dpi) - rhmin_pix = .13 * src_dpi; - if (rhmin_pix < 1) - rhmin_pix = 1; - /* - for (rmax=region->r2;rmax>region->r1;rmax--) - if (rowthresh[rmax-region->r1]>10) - break; - */ - /* Look for "row" gaps in the region so that it can be broken into */ - /* multiple "rows". */ - breakinfo->n = 0; - for (labelrow = figrow = -1, dtrc = trc = brc = 0, i = region->r1; - i <= region->r2 + 1; i++) { - /* Does row have few enough black pixels to be considered blank? */ - if (i > region->r2 || rowthresh[i - region->r1] <= 10) { - trc = 0; - brc++; - /* - ** Max allowed white space between rows = max_vertical_gap_inches - */ - if (dtrc == 0 && i <= region->r2) { - if (brc > brcmin) - newregion->r1++; - continue; - } - /* - ** Big enough blank gap, so add one row / line - */ - if (dtrc + brc >= rhmin_pix || i > region->r2) { - int i0, iopt; - double region_height_inches; - double gap_inches; - - if (dtrc < src_dpi * 0.02) - dtrc = src_dpi * 0.02; - if (dtrc < 2) - dtrc = 2; - /* Look for more optimum point */ - if (i <= region->r2) { - for (i0 = iopt = i; i <= region->r2 && i - i0 < dtrc; i++) { - if (rowthresh[i - region->r1] - < rowthresh[iopt - region->r1]) { - iopt = i; - if (rowthresh[i - region->r1] == 0) - break; - } - if (rowthresh[i - region->r1] > 100) - break; - } - /* If at end of region and haven't found perfect break, stay at end */ - if (i > region->r2 && rowthresh[iopt - region->r1] > 0) - i = region->r2; - else - i = iopt; - } - newregion->r2 = i - 1; - region_height_inches = (double) (newregion->r2 - newregion->r1 - + 1) / src_dpi; - - /* Could this region be a figure? */ - if (i <= region->r2 && figrow < 0 - && region_height_inches >= min_fig_height) { - /* If so, set figrow and don't process it yet. */ - figrow = newregion->r1; - labelrow = -1; - newregion->r1 = i; - dtrc = trc = 0; - brc = 1; - continue; - } - /* Are we processing a figure? */ - if (figrow >= 0) { - /* Compute most recent gap */ - if (labelrow >= 0) - gap_inches = (double) (labelrow - newregion->r1) - / src_dpi; - else - gap_inches = -1.; - /* If gap and region height are small enough, tack them on to the figure. */ - if (region_height_inches < max_label_height - && gap_inches > 0. && gap_inches < max_fig_gap) - newregion->r1 = figrow; - else { - /* Not small enough--dump the previous figure. */ - newregion->r2 = newregion->r1 - 1; - newregion->r1 = figrow; - newregion->c1 = region->c1; - newregion->c2 = region->c2; - bmpregion_trim_margins(newregion, colcount, rowcount, - 0x1f); - if (newregion->r2 > newregion->r1) - textrow_assign_bmpregion( - &breakinfo->textrow[breakinfo->n++], - newregion); - if (i <= region->r2 && gap_inches > 0. - && gap_inches < max_fig_gap) { - /* This new region might be a figure--set it as the new figure */ - /* and don't dump it yet. */ - figrow = newregion->r2 + 1; - labelrow = -1; - newregion->r1 = i; - dtrc = trc = 0; - brc = 1; - continue; - } else { - newregion->r1 = newregion->r2 + 1; - newregion->r2 = i - 1; - } - } - /* Cancel figure processing */ - figrow = -1; - labelrow = -1; - } - /* - if (newregion->r2 >= rmax) - i=newregion->r2=region->r2; - */ - newregion->c1 = region->c1; - newregion->c2 = region->c2; - bmpregion_trim_margins(newregion, colcount, rowcount, 0x1f); - if (newregion->r2 > newregion->r1) - textrow_assign_bmpregion( - &breakinfo->textrow[breakinfo->n++], newregion); - newregion->r1 = i; - dtrc = trc = 0; - brc = 1; - } - } else { - if (figrow >= 0 && labelrow < 0) - labelrow = i; - dtrc++; - trc++; - brc = 0; - } - } - /* Re-did logic in 1.52 so that this next part is no longer necessary */ -#ifdef COMMENT - newregion->r2=region->r2; - if (dtrc>0 && newregion->r2-newregion->r1+1 > 0) - { - /* If we were processing a figure, include it. */ - if (figrow>=0) - newregion->r1=figrow; - newregion->c1=region->c1; - newregion->c2=region->c2; - bmpregion_trim_margins(newregion,colcount,rowcount,0x1f); - printf("Final add: %d - %d\n",newregion->r1,newregion->r2); - if (newregion->r2>newregion->r1) - textrow_assign_bmpregion(&breakinfo->textrow[breakinfo->n++],newregion); - } -#endif - /* Compute gaps between rows and row heights */ - breakinfo_compute_row_gaps(breakinfo, region->r2); - willus_dmem_free(15, (double **) &rowthresh, funcname); -} - -static void textrow_assign_bmpregion(TEXTROW *textrow, BMPREGION *region) - -{ - textrow->r1 = region->r1; - textrow->r2 = region->r2; - textrow->c1 = region->c1; - textrow->c2 = region->c2; - textrow->rowbase = region->rowbase; - textrow->lcheight = region->lcheight; - textrow->capheight = region->capheight; - textrow->h5050 = region->h5050; -} - -static void breakinfo_compute_row_gaps(BREAKINFO *breakinfo, int r2) - -{ - int i, n; - - n = breakinfo->n; - if (n <= 0) - return; - breakinfo->textrow[0].rowheight = breakinfo->textrow[0].r2 - - breakinfo->textrow[0].r1; - for (i = 0; i < n - 1; i++) - breakinfo->textrow[i].gap = breakinfo->textrow[i + 1].r1 - - breakinfo->textrow[i].rowbase - 1; - /* - breakinfo->textrow[i].rowheight = breakinfo->textrow[i+1].r1 - breakinfo->textrow[i].r1; - */ - for (i = 1; i < n; i++) - breakinfo->textrow[i].rowheight = breakinfo->textrow[i].rowbase - - breakinfo->textrow[i - 1].rowbase; - breakinfo->textrow[n - 1].gap = r2 - breakinfo->textrow[n - 1].rowbase; -} - -static void breakinfo_compute_col_gaps(BREAKINFO *breakinfo, int c2) - -{ - int i, n; - - n = breakinfo->n; - if (n <= 0) - return; - for (i = 0; i < n - 1; i++) { - breakinfo->textrow[i].gap = breakinfo->textrow[i + 1].c1 - - breakinfo->textrow[i].c2 - 1; - breakinfo->textrow[i].rowheight = breakinfo->textrow[i + 1].c1 - - breakinfo->textrow[i].c1; - } - breakinfo->textrow[n - 1].gap = c2 - breakinfo->textrow[n - 1].c2; - breakinfo->textrow[n - 1].rowheight = breakinfo->textrow[n - 1].c2 - - breakinfo->textrow[n - 1].c1; -} - -static void breakinfo_remove_small_col_gaps(BREAKINFO *breakinfo, int lcheight, - double mingap) - -{ - int i, j; - - if (mingap < word_spacing) - mingap = word_spacing; - for (i = 0; i < breakinfo->n - 1; i++) { - double gap; - - gap = (double) breakinfo->textrow[i].gap / lcheight; - if (gap >= mingap) - continue; - breakinfo->textrow[i].c2 = breakinfo->textrow[i + 1].c2; - breakinfo->textrow[i].gap = breakinfo->textrow[i + 1].gap; - if (breakinfo->textrow[i + 1].r1 < breakinfo->textrow[i].r1) - breakinfo->textrow[i].r1 = breakinfo->textrow[i + 1].r1; - if (breakinfo->textrow[i + 1].r2 > breakinfo->textrow[i].r2) - breakinfo->textrow[i].r2 = breakinfo->textrow[i + 1].r2; - for (j = i + 1; j < breakinfo->n - 1; j++) - breakinfo->textrow[j] = breakinfo->textrow[j + 1]; - breakinfo->n--; - i--; - } -} - -static void breakinfo_remove_small_rows(BREAKINFO *breakinfo, double fracrh, - double fracgap, BMPREGION *region, int *colcount, int *rowcount) - -{ - int i, j, mg, mh, mg0, mg1; - int c1, c2, nc; - int *rh, *gap; - static char *funcname = "breakinfo_remove_small_rows"; - -#if (WILLUSDEBUGX & 2) - printf("@breakinfo_remove_small_rows(fracrh=%g,fracgap=%g)\n",fracrh,fracgap); -#endif - if (breakinfo->n < 2) - return; - c1 = region->c1; - c2 = region->c2; - nc = c2 - c1 + 1; - willus_dmem_alloc_warn(16, (void **) &rh, 2 * sizeof(int) * breakinfo->n, - funcname, 10); - gap = &rh[breakinfo->n]; - for (i = 0; i < breakinfo->n; i++) { - rh[i] = breakinfo->textrow[i].r2 - breakinfo->textrow[i].r1 + 1; - if (i < breakinfo->n - 1) - gap[i] = breakinfo->textrow[i].gap; - } - sorti(rh, breakinfo->n); - sorti(gap, breakinfo->n - 1); - mh = rh[breakinfo->n / 2]; - mh *= fracrh; - if (mh < 1) - mh = 1; - mg0 = gap[(breakinfo->n - 1) / 2]; - mg = mg0 * fracgap; - mg1 = mg0 * 0.7; - if (mg < 1) - mg = 1; -#if (WILLUSDEBUGX & 2) - printf("mh = %d x %g = %d\n",rh[breakinfo->n/2],fracrh,mh); - printf("mg = %d x %g = %d\n",gap[breakinfo->n/2],fracgap,mg); -#endif - for (i = 0; i < breakinfo->n; i++) { - TEXTROW *textrow; - int trh, gs1, gs2, g1, g2, gap_is_big, row_too_small; - double m1, m2, row_width_inches; - - textrow = &breakinfo->textrow[i]; - trh = textrow->r2 - textrow->r1 + 1; - if (i == 0) { - g1 = mg0 + 1; - gs1 = mg + 1; - } else { - g1 = textrow->r1 - breakinfo->textrow[i - 1].r2 - 1; - gs1 = breakinfo->textrow[i - 1].gap; - } - if (i == breakinfo->n - 1) { - g2 = mg0 + 1; - gs2 = mg + 1; - } else { - g2 = breakinfo->textrow[i + 1].r1 - textrow->r2 - 1; - gs2 = breakinfo->textrow[i].gap; - } -#if (WILLUSDEBUGX & 2) - printf(" rowheight[%d] = %d, mh=%d, gs1=%d, gs2=%d\n",i,trh,mh,gs1,gs2); -#endif - gap_is_big = (trh >= mh || (gs1 >= mg && gs2 >= mg)); - /* - ** Is the row width small and centered? If so, it should probably - ** be attached to its nearest neighbor--it's usually a fragment of - ** an equation or a table/figure. - */ - row_width_inches = (double) (textrow->c2 - textrow->c1 + 1) / src_dpi; - m1 = fabs(textrow->c1 - c1) / nc; - m2 = fabs(textrow->c2 - c2) / nc; - row_too_small = m1 > 0.1 && m2 > 0.1 - && row_width_inches < little_piece_threshold_inches - && (g1 <= mg1 || g2 <= mg1); -#if (WILLUSDEBUGX & 2) - printf(" m1=%g, m2=%g, rwi=%g, g1=%d, g2=%d, mg0=%d\n",m1,m2,row_width_inches,g1,g2,mg0); -#endif - if (gap_is_big && !row_too_small) - continue; -#if (WILLUSDEBUGX & 2) - printf(" row[%d] to be combined w/next row.\n",i); -#endif - if (row_too_small) { - if (g1 < g2) - i--; - } else { - if (gs1 < gs2) - i--; - } - /* - printf("Removing row. nrows=%d, rh=%d, gs1=%d, gs2=%d\n",breakinfo->n,trh,gs1,gs2); - printf(" mh = %d, mg = %d\n",rh[breakinfo->n/2],gap[(breakinfo->n-1)/2]); - */ - breakinfo->textrow[i].r2 = breakinfo->textrow[i + 1].r2; - if (breakinfo->textrow[i + 1].c2 > breakinfo->textrow[i].c2) - breakinfo->textrow[i].c2 = breakinfo->textrow[i + 1].c2; - if (breakinfo->textrow[i + 1].c1 < breakinfo->textrow[i].c1) - breakinfo->textrow[i].c1 = breakinfo->textrow[i + 1].c1; - /* Re-compute rowbase, capheight, lcheight */ - { - BMPREGION newregion; - newregion = (*region); - newregion.c1 = breakinfo->textrow[i].c1; - newregion.c2 = breakinfo->textrow[i].c2; - newregion.r1 = breakinfo->textrow[i].r1; - newregion.r2 = breakinfo->textrow[i].r2; - bmpregion_trim_margins(&newregion, colcount, rowcount, 0x1f); - newregion.c1 = breakinfo->textrow[i].c1; - newregion.c2 = breakinfo->textrow[i].c2; - newregion.r1 = breakinfo->textrow[i].r1; - newregion.r2 = breakinfo->textrow[i].r2; - textrow_assign_bmpregion(&breakinfo->textrow[i], &newregion); - } - for (j = i + 1; j < breakinfo->n - 1; j++) - breakinfo->textrow[j] = breakinfo->textrow[j + 1]; - breakinfo->n--; - i--; - } - willus_dmem_free(16, (double **) &rh, funcname); -} - -static void breakinfo_alloc(int index, BREAKINFO *breakinfo, int nrows) - -{ - static char *funcname = "breakinfo_alloc"; - - willus_dmem_alloc_warn(index, (void **) &breakinfo->textrow, - sizeof(TEXTROW) * (nrows / 2 + 2), funcname, 10); -} - -static void breakinfo_free(int index, BREAKINFO *breakinfo) - -{ - static char *funcname = "breakinfo_free"; - - willus_dmem_free(index, (double **) &breakinfo->textrow, funcname); -} - -static void breakinfo_sort_by_gap(BREAKINFO *breakinfo) - -{ - int n, top, n1; - TEXTROW *x, x0; - - x = breakinfo->textrow; - n = breakinfo->n; - if (n < 2) - return; - top = n / 2; - n1 = n - 1; - while (1) { - if (top > 0) { - top--; - x0 = x[top]; - } else { - x0 = x[n1]; - x[n1] = x[0]; - n1--; - if (!n1) { - x[0] = x0; - return; - } - } - { - int parent, child; - - parent = top; - child = top * 2 + 1; - while (child <= n1) { - if (child < n1 && x[child].gap < x[child + 1].gap) - child++; - if (x0.gap < x[child].gap) { - x[parent] = x[child]; - parent = child; - child += (parent + 1); - } else - break; - } - x[parent] = x0; - } - } -} - -static void breakinfo_sort_by_row_position(BREAKINFO *breakinfo) - -{ - int n, top, n1; - TEXTROW *x, x0; - - x = breakinfo->textrow; - n = breakinfo->n; - if (n < 2) - return; - top = n / 2; - n1 = n - 1; - while (1) { - if (top > 0) { - top--; - x0 = x[top]; - } else { - x0 = x[n1]; - x[n1] = x[0]; - n1--; - if (!n1) { - x[0] = x0; - return; - } - } - { - int parent, child; - - parent = top; - child = top * 2 + 1; - while (child <= n1) { - if (child < n1 && x[child].r1 < x[child + 1].r1) - child++; - if (x0.r1 < x[child].r1) { - x[parent] = x[child]; - parent = child; - child += (parent + 1); - } else - break; - } - x[parent] = x0; - } - } -} - -/* - ** Add a vertically-contiguous rectangular region to the destination bitmap. - ** The rectangular region may be broken up horizontally (wrapped). - */ -static void bmpregion_one_row_find_breaks(BMPREGION *region, - BREAKINFO *breakinfo, int *colcount, int *rowcount, int add_to_dbase) - -{ - int nc, i, mingap, col0, dr, thlow, thhigh; - int *bp; - BMPREGION *newregion, _newregion; - static char *funcname = "bmpregion_one_row_find_breaks"; - - if (debug) - printf("@bmpregion_one_row_find_breaks(%d,%d)-(%d,%d)\n", region->c1, - region->r1, region->c2, region->r2); - newregion = &_newregion; - (*newregion) = (*region); - bmpregion_trim_margins(newregion, colcount, rowcount, 0x1f); - region->lcheight = newregion->lcheight; - region->capheight = newregion->capheight; - region->rowbase = newregion->rowbase; - region->h5050 = newregion->h5050; - nc = newregion->c2 - newregion->c1 + 1; - breakinfo->n = 0; - if (nc < 6) - return; - /* - ** Look for "space-sized" gaps, i.e. gaps that would occur between words. - ** Use this as pixel counting aperture. - */ - dr = newregion->lcheight; - mingap = dr * word_spacing * 0.8; - if (mingap < 2) - mingap = 2; - - /* - ** Find places where there are gaps (store in bp array) - ** Could do this more intelligently--maybe calculate a histogram? - */ - willus_dmem_alloc_warn(18, (void **) &bp, sizeof(int) * nc, funcname, 10); - for (i = 0; i < nc; i++) - bp[i] = 0; - if (src_left_to_right) { - for (i = newregion->c1; i <= newregion->c2; i++) { - int i1, i2, pt, sum, ii; - i1 = i - mingap / 2; - i2 = i1 + mingap - 1; - if (i1 < newregion->c1) - i1 = newregion->c1; - if (i2 > newregion->c2) - i2 = newregion->c2; - pt = (int) ((i2 - i1 + 1) * gtw_in * src_dpi + .5); - if (pt < 1) - pt = 1; - for (sum = 0, ii = i1; ii <= i2; ii++, sum += colcount[ii]) - ; - bp[i - newregion->c1] = 10 * sum / pt; - } - } else { - for (i = newregion->c2; i >= newregion->c1; i--) { - int i1, i2, pt, sum, ii; - i1 = i - mingap / 2; - i2 = i1 + mingap - 1; - if (i1 < newregion->c1) - i1 = newregion->c1; - if (i2 > newregion->c2) - i2 = newregion->c2; - pt = (int) ((i2 - i1 + 1) * gtw_in * src_dpi + .5); - if (pt < 1) - pt = 1; - for (sum = 0, ii = i1; ii <= i2; ii++, sum += colcount[ii]) - ; - bp[i - newregion->c1] = 10 * sum / pt; - } - } -#if (WILLUSDEBUGX & 4) - if (region->r1 > 3699 && region->r1<3750) - { - static int a=0; - FILE *f; - f=fopen("outbp.ep",a==0?"w":"a"); - a++; - fprintf(f,"/sa l \"(%d,%d)-(%d,%d) lch=%d\" 2\n",region->c1,region->r1,region->c2,region->r2,region->lcheight); - for (i=0;ic1; col0 <= newregion->c2; col0++) { - int copt, c0; - BMPREGION xregion; - - xregion = (*newregion); - xregion.c1 = col0; - for (; col0 <= newregion->c2; col0++) - if (bp[col0 - newregion->c1] >= thhigh) - break; - if (col0 > newregion->c2) - break; - for (col0++; col0 <= newregion->c2; col0++) - if (bp[col0 - newregion->c1] < thlow) - break; - for (copt = c0 = col0; col0 <= newregion->c2 && col0 - c0 <= dr; - col0++) { - if (bp[col0 - newregion->c1] < bp[copt - newregion->c1]) - copt = col0; - if (bp[col0 - newregion->c1] > thhigh) - break; - } - if (copt > newregion->c2) - copt = newregion->c2; - xregion.c2 = copt; - if (xregion.c2 - xregion.c1 < 2) - continue; - bmpregion_trim_margins(&xregion, colcount, rowcount, 0x1f); - textrow_assign_bmpregion(&breakinfo->textrow[breakinfo->n++], &xregion); - col0 = copt; - if (copt == newregion->c2) - break; - } - breakinfo_compute_col_gaps(breakinfo, newregion->c2); - willus_dmem_free(18, (double **) &bp, funcname); - - /* Remove small gaps */ - { - double median_gap; - word_gaps_add(add_to_dbase ? breakinfo : NULL, region->lcheight, - &median_gap); - breakinfo_remove_small_col_gaps(breakinfo, region->lcheight, - median_gap / 1.9); - } -} - -/* - ** pi = preserve indentation - */ -static void bmpregion_one_row_wrap_and_add(BMPREGION *region, - BREAKINFO *rowbreakinfo, int index, int i1, int i2, - MASTERINFO *masterinfo, int justflags, int *colcount, int *rowcount, - WPDFPAGEINFO *pageinfo, int line_spacing, int mean_row_gap, int rowbase, - int marking_flags, int pi) - -{ - int nc, nr, i, i0, gappix; - double aspect_ratio, region_height; - BREAKINFO *colbreaks, _colbreaks; - BMPREGION *newregion, _newregion; - -#if (WILLUSDEBUGX & 4) - printf("@bmpregion_one_row_wrap_and_add, index=%d, i1=%d, i2=%d\n",index,i1,i2); -#endif - newregion = &_newregion; - (*newregion) = (*region); - bmpregion_trim_margins(newregion, colcount, rowcount, 0xf); - nc = newregion->c2 - newregion->c1 + 1; - nr = newregion->r2 - newregion->r1 + 1; - if (nc < 6) - return; - aspect_ratio = (double) nr / nc; - region_height = (double) nr / src_dpi; - if (aspect_ratio > no_wrap_ar_limit - && region_height > no_wrap_height_limit_inches) { - newregion->r1 = region->r1; - newregion->r2 = region->r2; -#ifdef WILLUSDEBUG - printf("wrapflush6\n"); -#endif - wrapbmp_flush(masterinfo, 0, pageinfo, 1); - if (index > i1) - dst_add_gap_src_pixels("Tall region", masterinfo, - rowbreakinfo->textrow[index - 1].gap); - bmpregion_add(newregion, rowbreakinfo, masterinfo, 0, 0xf, 0, -1.0, 0, - 2, colcount, rowcount, pageinfo, 0xf, - rowbreakinfo->textrow[index].r2 - - rowbreakinfo->textrow[index].rowbase); - if (index < i2) - gap_override_internal = rowbreakinfo->textrow[index].gap; - return; - } - colbreaks = &_colbreaks; - colbreaks->textrow = NULL; - breakinfo_alloc(106, colbreaks, newregion->c2 - newregion->c1 + 1); - bmpregion_one_row_find_breaks(newregion, colbreaks, colcount, rowcount, 1); - if (pi && colbreaks->n > 0) { - if (src_left_to_right) - colbreaks->textrow[0].c1 = region->c1; - else - colbreaks->textrow[colbreaks->n - 1].c2 = region->c2; - } - /* - hs=0.; - for (i=0;in;i++) - hs += (colbreaks->textrow[i].r2-colbreaks->textrow[i].r1); - hs /= colbreaks->n; - */ - /* - ** Find appropriate letter height to use for word spacing - */ - { - double median_gap; - word_gaps_add(NULL, newregion->lcheight, &median_gap); - gappix = (int) (median_gap * newregion->lcheight + .5); - } -#if (WILLUSDEBUGX & 4) - printf("Before small gap removal, column breaks:\n"); - breakinfo_echo(colbreaks); -#endif -#if (WILLUSDEBUGX & 4) - printf("After small gap removal, column breaks:\n"); - breakinfo_echo(colbreaks); -#endif - if (show_marked_source) - for (i = 0; i < colbreaks->n; i++) { - BMPREGION xregion; - xregion = (*newregion); - xregion.c1 = colbreaks->textrow[i].c1; - xregion.c2 = colbreaks->textrow[i].c2; - mark_source_page(&xregion, 2, marking_flags); - } -#if (WILLUSDEBUGX & 4) - for (i=0;in;i++) - printf(" colbreak[%d] = %d - %d\n",i,colbreaks->textrow[i].c1,colbreaks->textrow[i].c2); -#endif - /* Maybe skip gaps < 0.5*median_gap or collect gap/rowheight ratios and skip small gaps */ - /* (Could be thrown off by full-justified articles where some lines have big gaps.) */ - /* Need do call a separate function that removes these gaps. */ - for (i0 = 0; i0 < colbreaks->n;) { - int i1, i2, toolong, rw, remaining_width_pixels; - BMPREGION reg; - - toolong = 0; /* Avoid compiler warning */ - for (i = i0; i < colbreaks->n; i++) { - int wordgap; - - wordgap = wrapbmp_ends_in_hyphen() ? 0 : gappix; - i1 = src_left_to_right ? i0 : colbreaks->n - 1 - i; - i2 = src_left_to_right ? i : colbreaks->n - 1 - i0; - rw = (colbreaks->textrow[i2].c2 - colbreaks->textrow[i1].c1 + 1); - remaining_width_pixels = wrapbmp_remaining(); - toolong = (rw + wordgap > remaining_width_pixels); -#if (WILLUSDEBUGX & 4) - printf(" i1=%d, i2=%d, rw=%d, rw+gap=%d, remainder=%d, toolong=%d\n",i1,i2,rw,rw+wordgap,remaining_width_pixels,toolong); -#endif - /* - ** If we're too long with just one word and there is already - ** stuff on the queue, then flush it and re-evaluate. - */ - if (i == i0 && toolong && wrapbmp_width() > 0) { -#ifdef WILLUSDEBUG - printf("wrapflush8\n"); -#endif - wrapbmp_flush(masterinfo, 1, pageinfo, 0); - i--; - continue; - } - /* - ** If we're not too long and we're not done yet, add another word. - */ - if (i < colbreaks->n - 1 && !toolong) - continue; - /* - ** Add the regions from i0 to i (or i0 to i-1) - */ - break; - } - if (i > i0 && toolong) - i--; - i1 = src_left_to_right ? i0 : colbreaks->n - 1 - i; - i2 = src_left_to_right ? i : colbreaks->n - 1 - i0; - reg = (*newregion); - reg.c1 = colbreaks->textrow[i1].c1; - reg.c2 = colbreaks->textrow[i2].c2; -#if (WILLUSDEBUGX & 4) - printf(" Adding i1=%d to i2=%d\n",i1,i2); -#endif - /* Trim the word top/bottom */ - bmpregion_trim_margins(®, colcount, rowcount, 0xc); - reg.c1 = colbreaks->textrow[i1].c1; - reg.c2 = colbreaks->textrow[i2].c2; - reg.lcheight = newregion->lcheight; - reg.capheight = newregion->capheight; - reg.rowbase = newregion->rowbase; - reg.h5050 = newregion->h5050; - if (reg.r1 > reg.rowbase) - reg.r1 = reg.rowbase; - if (reg.r2 < reg.rowbase) - reg.r2 = reg.rowbase; - /* Add it to the existing line queue */ - wrapbmp_add(®, gappix, line_spacing, rowbase, mean_row_gap, - justflags); - if (toolong) { -#ifdef WILLUSDEBUG - printf("wrapflush7\n"); -#endif - wrapbmp_flush(masterinfo, 1, pageinfo, 0); - } - i0 = i + 1; - } - breakinfo_free(106, colbreaks); -} - -static WILLUSBITMAP _wrapbmp, *wrapbmp; -static int wrapbmp_base; -static int wrapbmp_line_spacing; -static int wrapbmp_gap; -static int wrapbmp_bgcolor; -static int wrapbmp_just; -static int wrapbmp_rhmax; -static int wrapbmp_thmax; -static int wrapbmp_maxgap = 2; -static int wrapbmp_height_extended; -static HYPHENINFO wrapbmp_hyphen; - -void wrapbmp_init(void) - -{ - wrapbmp = &_wrapbmp; - bmp_init(wrapbmp); - wrapbmp_set_color(dst_color); - wrapbmp->width = 0; - wrapbmp->height = 0; - wrapbmp_base = 0; - wrapbmp_line_spacing = -1; - wrapbmp_gap = -1; - wrapbmp_bgcolor = -1; - wrapbmp_height_extended = 0; - wrapbmp_just = 0x8f; - wrapbmp_rhmax = -1; - wrapbmp_thmax = -1; - wrapbmp_hyphen.ch = -1; - just_flushed_internal = 0; - beginning_gap_internal = -1; - last_h5050_internal = -1; -} - -static int wrapbmp_ends_in_hyphen(void) - -{ - return (wrapbmp_hyphen.ch >= 0); -} - -static void wrapbmp_set_color(int is_color) - -{ - if (is_color) - wrapbmp->bpp = 24; - else { - int i; - - wrapbmp->bpp = 8; - for (i = 0; i < 256; i++) - wrapbmp->red[i] = wrapbmp->blue[i] = wrapbmp->green[i] = i; - } -} - -static void wrapbmp_free(void) - -{ - bmp_free(wrapbmp); -} - -static void wrapbmp_set_maxgap(int value) - -{ - wrapbmp_maxgap = value; -} - -static int wrapbmp_width(void) - -{ - return (wrapbmp->width); -} - -static int wrapbmp_remaining(void) - -{ - int maxpix, w; - maxpix = max_region_width_inches * src_dpi; - /* Don't include hyphen if wrapbmp ends in a hyphen */ - if (wrapbmp_hyphen.ch < 0) - w = wrapbmp->width; - else if (src_left_to_right) - w = wrapbmp_hyphen.c2 + 1; - else - w = wrapbmp->width - wrapbmp_hyphen.c2; - return (maxpix - w); -} - -/* - ** region = bitmap region to add to line - ** gap = horizontal pixel gap between existing region and region being added - ** line_spacing = desired spacing between lines of text (pixels) - ** rbase = position of baseline in region - ** gio = gap if over--gap above top of text if it goes over line_spacing. - */ -// static int bcount=0; -static void wrapbmp_add(BMPREGION *region, int gap, int line_spacing, int rbase, - int gio, int just_flags) - -{ - WILLUSBITMAP *tmp, _tmp; - int i, rh, th, bw, new_base, h2, bpp, width0; -// static char filename[256]; - -#ifdef WILLUSDEBUG - printf("@wrapbmp_add %d x %d (w=%d).\n",region->c2-region->c1+1,region->r2-region->r1+1,wrapbmp->width); -#endif - bmpregion_hyphen_detect(region); /* Figure out if what we're adding ends in a hyphen */ - if (wrapbmp_ends_in_hyphen()) - gap = 0; - wrapbmp_hyphen_erase(); - just_flushed_internal = 0; // Reset "just flushed" flag - beginning_gap_internal = -1; // Reset top-of-page or top-of-column gap - last_h5050_internal = -1; // Reset last row font size - if (line_spacing > wrapbmp_line_spacing) - wrapbmp_line_spacing = line_spacing; - if (gio > wrapbmp_gap) - wrapbmp_gap = gio; - wrapbmp_bgcolor = region->bgcolor; - wrapbmp_just = just_flags; - /* - printf(" c1=%d, c2=%d, r1=%d, r2=%d\n",region->c1,region->c2,region->r1,region->r2); - printf(" gap=%d, line_spacing=%d, rbase=%d, gio=%d\n",gap,line_spacing,rbase,gio); - */ - bpp = dst_color ? 3 : 1; - rh = rbase - region->r1 + 1; - if (rh > wrapbmp_rhmax) - wrapbmp_rhmax = rh; - th = rh + (region->r2 - rbase); - if (th > wrapbmp_thmax) - wrapbmp_thmax = th; - /* - { - WILLUSBITMAP *bmp,_bmp; - - bmp=&_bmp; - bmp_init(bmp); - bmp->height=region->r2-region->r1+1; - bmp->width=region->c2-region->c1+1; - bmp->bpp=bpp*8; - if (bpp==1) - for (i=0;i<256;i++) - bmp->red[i]=bmp->blue[i]=bmp->green[i]=i; - bmp_alloc(bmp); - bw=bmp_bytewidth(bmp); - memset(bmp_rowptr_from_top(bmp,0),255,bw*bmp->height); - for (i=region->r1;i<=region->r2;i++) - { - unsigned char *d,*s; - d=bmp_rowptr_from_top(bmp,i-region->r1); - s=bmp_rowptr_from_top(dst_color?region->bmp:region->bmp8,i)+bpp*region->c1; - if (i==rbase) - memset(d,0,bw); - else - memcpy(d,s,bw); - } - sprintf(filename,"out%05d.png",bcount++); - bmp_write(bmp,filename,stdout,100); - bmp_free(bmp); - } - */ - if (wrapbmp->width == 0) { - /* Put appropriate gap in */ - if (last_rowbase_internal >= 0 - && rh < wrapbmp_line_spacing - last_rowbase_internal) { - rh = wrapbmp_line_spacing - last_rowbase_internal; - if (rh < 2) - rh = 2; - th = rh + (region->r2 - rbase); - wrapbmp_height_extended = 0; - } else - wrapbmp_height_extended = (last_rowbase_internal >= 0); - wrapbmp_base = rh - 1; - wrapbmp->height = th; -#ifdef WILLUSDEBUG - printf("@wrapbmp_add: bmpheight set to %d (wls=%d, lrbi=%d)\n",wrapbmp->height,wrapbmp_line_spacing,last_rowbase_internal); -#endif - wrapbmp->width = region->c2 - region->c1 + 1; - bmp_alloc(wrapbmp); - bw = bmp_bytewidth(wrapbmp); - memset(bmp_rowptr_from_top(wrapbmp, 0), 255, bw * wrapbmp->height); - for (i = region->r1; i <= region->r2; i++) { - unsigned char *d, *s; - d = bmp_rowptr_from_top(wrapbmp, wrapbmp_base + (i - rbase)); - s = bmp_rowptr_from_top(dst_color ? region->bmp : region->bmp8, i) - + bpp * region->c1; - memcpy(d, s, bw); - } -#ifdef WILLUSDEBUG - if (wrapbmp->height<=wrapbmp_base) - { - printf("1. SCREEECH!\n"); - printf("wrapbmp = %d x %d, base=%d\n",wrapbmp->width,wrapbmp->height,wrapbmp_base); - exit(10); - } -#endif - /* Copy hyphen info from added region */ - wrapbmp_hyphen = region->hyphen; - if (wrapbmp_ends_in_hyphen()) { - wrapbmp_hyphen.r1 += (wrapbmp_base - rbase); - wrapbmp_hyphen.r2 += (wrapbmp_base - rbase); - wrapbmp_hyphen.ch -= region->c1; - wrapbmp_hyphen.c2 -= region->c1; - } - return; - } - width0 = wrapbmp->width; /* Starting wrapbmp width */ - tmp = &_tmp; - bmp_init(tmp); - bmp_copy(tmp, wrapbmp); - tmp->width += gap + region->c2 - region->c1 + 1; - if (rh > wrapbmp_base) { - wrapbmp_height_extended = 1; - new_base = rh - 1; - } else - new_base = wrapbmp_base; - if (region->r2 - rbase > wrapbmp->height - 1 - wrapbmp_base) - h2 = region->r2 - rbase; - else - h2 = wrapbmp->height - 1 - wrapbmp_base; - tmp->height = new_base + h2 + 1; - bmp_alloc(tmp); - bw = bmp_bytewidth(tmp); - memset(bmp_rowptr_from_top(tmp, 0), 255, bw * tmp->height); - bw = bmp_bytewidth(wrapbmp); - /* - printf("3. wbh=%d x %d, tmp=%d x %d x %d, new_base=%d, wbbase=%d\n",wrapbmp->width,wrapbmp->height,tmp->width,tmp->height,tmp->bpp,new_base,wrapbmp_base); - */ - for (i = 0; i < wrapbmp->height; i++) { - unsigned char *d, *s; - d = bmp_rowptr_from_top(tmp, i + new_base - wrapbmp_base) - + (src_left_to_right ? 0 : tmp->width - 1 - wrapbmp->width) - * bpp; - s = bmp_rowptr_from_top(wrapbmp, i); - memcpy(d, s, bw); - } - bw = bpp * (region->c2 - region->c1 + 1); - if (region->r1 + new_base - rbase < 0 - || region->r2 + new_base - rbase > tmp->height - 1) { - aprintf(ANSI_YELLOW "INTERNAL ERROR--TMP NOT DIMENSIONED PROPERLY.\n"); - aprintf("(%d-%d), tmp->height=%d\n" ANSI_NORMAL, - region->r1 + new_base - rbase, region->r2 + new_base - rbase, - tmp->height); - exit(10); - } - for (i = region->r1; i <= region->r2; i++) { - unsigned char *d, *s; - - d = bmp_rowptr_from_top(tmp, i + new_base - rbase) - + (src_left_to_right ? wrapbmp->width + gap : 0) * bpp; - s = bmp_rowptr_from_top(dst_color ? region->bmp : region->bmp8, i) - + bpp * region->c1; - memcpy(d, s, bw); - } - bmp_copy(wrapbmp, tmp); - bmp_free(tmp); - /* Copy region's hyphen info */ - wrapbmp_hyphen = region->hyphen; - if (wrapbmp_ends_in_hyphen()) { - wrapbmp_hyphen.r1 += (new_base - rbase); - wrapbmp_hyphen.r2 += (new_base - rbase); - if (src_left_to_right) { - wrapbmp_hyphen.ch += width0 + gap - region->c1; - wrapbmp_hyphen.c2 += width0 + gap - region->c1; - } else { - wrapbmp_hyphen.ch -= region->c1; - wrapbmp_hyphen.c2 -= region->c1; - } - } - wrapbmp_base = new_base; -#ifdef WILLUSDEBUG - if (wrapbmp->height<=wrapbmp_base) - { - printf("2. SCREEECH!\n"); - printf("wrapbmp = %d x %d, base=%d\n",wrapbmp->width,wrapbmp->height,wrapbmp_base); - exit(10); - } -#endif -} - -static void wrapbmp_flush(MASTERINFO *masterinfo, int allow_full_justification, - WPDFPAGEINFO *pageinfo, int use_bgi) - -{ - BMPREGION region; - WILLUSBITMAP *bmp8, _bmp8; - int gap, just, nomss, dh; - int *colcount, *rowcount; - static char *funcname = "wrapbmp_flush"; -// char filename[256]; - - if (wrapbmp->width <= 0) { - if (use_bgi == 1 && beginning_gap_internal > 0) - dst_add_gap_src_pixels("wrapbmp_bgi0", masterinfo, - beginning_gap_internal); - beginning_gap_internal = -1; - last_h5050_internal = -1; - if (use_bgi) - just_flushed_internal = 1; - return; - } -#ifdef WILLUSDEBUG - printf("@wrapbmp_flush()\n"); -#endif - /* - { - char filename[256]; - int i; - static int bcount=0; - for (i=0;iheight;i++) - { - unsigned char *p; - int j; - p=bmp_rowptr_from_top(wrapbmp,i); - for (j=0;jwidth;j++) - if (p[j]>240) - p[j]=192; - } - sprintf(filename,"out%05d.png",bcount++); - bmp_write(wrapbmp,filename,stdout,100); - } - */ - colcount = rowcount = NULL; - willus_dmem_alloc_warn(19, (void **) &colcount, - (wrapbmp->width + 16) * sizeof(int), funcname, 10); - willus_dmem_alloc_warn(20, (void **) &rowcount, - (wrapbmp->height + 16) * sizeof(int), funcname, 10); - region.c1 = 0; - region.c2 = wrapbmp->width - 1; - region.r1 = 0; - region.r2 = wrapbmp->height - 1; - region.rowbase = wrapbmp_base; - region.bmp = wrapbmp; - region.bgcolor = wrapbmp_bgcolor; -#ifdef WILLUSDEBUG - printf("Bitmap is %d x %d (baseline=%d)\n",wrapbmp->width,wrapbmp->height,wrapbmp_base); -#endif - - /* Sanity check on row spacing -- don't let it be too large. */ - nomss = wrapbmp_rhmax * 1.7; /* Nominal single-spaced height for this row */ - if (last_rowbase_internal < 0) - dh = 0; - else { - dh = (int) (wrapbmp_line_spacing - last_rowbase_internal - - 1.2 * fabs(vertical_line_spacing) * nomss + .5); - if (vertical_line_spacing < 0.) { - int dh1; - if (wrapbmp_maxgap > 0) - dh1 = region.rowbase + 1 - wrapbmp_rhmax - wrapbmp_maxgap; - else - dh1 = (int) (wrapbmp_line_spacing - last_rowbase_internal - - 1.2 * nomss + .5); - if (dh1 > dh) - dh = dh1; - } - } - if (dh > 0) { -#ifdef WILLUSDEBUG - aprintf(ANSI_YELLOW "dh > 0 = %d" ANSI_NORMAL "\n",dh); - printf(" wrapbmp_line_spacing=%d\n",wrapbmp_line_spacing); - printf(" nomss = %d\n",nomss); - printf(" vls = %g\n",vertical_line_spacing); - printf(" lrbi=%d\n",last_rowbase_internal); - printf(" wrapbmp_maxgap=%d\n",wrapbmp_maxgap); - printf(" wrapbmp_rhmax=%d\n",wrapbmp_rhmax); -#endif - region.r1 = dh; - /* - if (dh>200) - { - bmp_write(wrapbmp,"out.png",stdout,100); - exit(10); - } - */ - } - if (wrapbmp->bpp == 24) { - bmp8 = &_bmp8; - bmp_init(bmp8); - bmp_convert_to_greyscale_ex(bmp8, wrapbmp); - region.bmp8 = bmp8; - } else - region.bmp8 = wrapbmp; - if (gap_override_internal > 0) { - region.r1 = wrapbmp_base - wrapbmp_rhmax + 1; - if (region.r1 < 0) - region.r1 = 0; - if (region.r1 > wrapbmp_base) - region.r1 = wrapbmp_base; - gap = gap_override_internal; - gap_override_internal = -1; - } else { - if (wrapbmp_height_extended) - gap = wrapbmp_gap; - else - gap = 0; - } -#ifdef WILLUSDEBUG - printf("wf: gap=%d\n",gap); -#endif - if (gap > 0) - dst_add_gap_src_pixels("wrapbmp", masterinfo, gap); - if (!allow_full_justification) - just = (wrapbmp_just & 0xcf) | 0x20; - else - just = wrapbmp_just; - bmpregion_add(®ion, NULL, masterinfo, 0, 0, 0, -1.0, just, 2, colcount, - rowcount, pageinfo, 0xf, wrapbmp->height - 1 - wrapbmp_base); - if (wrapbmp->bpp == 24) - bmp_free(bmp8); - willus_dmem_free(20, (double **) &rowcount, funcname); - willus_dmem_free(19, (double **) &colcount, funcname); - wrapbmp->width = 0; - wrapbmp->height = 0; - wrapbmp_line_spacing = -1; - wrapbmp_gap = -1; - wrapbmp_rhmax = -1; - wrapbmp_thmax = -1; - wrapbmp_hyphen.ch = -1; - if (use_bgi == 1 && beginning_gap_internal > 0) - dst_add_gap_src_pixels("wrapbmp_bgi1", masterinfo, - beginning_gap_internal); - beginning_gap_internal = -1; - last_h5050_internal = -1; - if (use_bgi) - just_flushed_internal = 1; -} - -static void wrapbmp_hyphen_erase(void) - -{ - WILLUSBITMAP *bmp, _bmp; - int bw, bpp, c0, c1, c2, i; - - if (wrapbmp_hyphen.ch < 0) - return; -#if (WILLUSDEBUGX & 16) - printf("@hyphen_erase, bmp=%d x %d x %d\n",wrapbmp->width,wrapbmp->height,wrapbmp->bpp); - printf(" ch=%d, c2=%d, r1=%d, r2=%d\n",wrapbmp_hyphen.ch,wrapbmp_hyphen.c2,wrapbmp_hyphen.r1,wrapbmp_hyphen.r2); -#endif - bmp = &_bmp; - bmp_init(bmp); - bmp->bpp = wrapbmp->bpp; - if (bmp->bpp == 8) - for (i = 0; i < 256; i++) - bmp->red[i] = bmp->blue[i] = bmp->green[i] = i; - bmp->height = wrapbmp->height; - if (src_left_to_right) { - bmp->width = wrapbmp_hyphen.c2 + 1; - c0 = 0; - c1 = wrapbmp_hyphen.ch; - c2 = bmp->width - 1; - } else { - bmp->width = wrapbmp->width - wrapbmp_hyphen.c2; - c0 = wrapbmp_hyphen.c2; - c1 = 0; - c2 = wrapbmp_hyphen.ch - wrapbmp_hyphen.c2; - } - bmp_alloc(bmp); - bpp = bmp->bpp == 24 ? 3 : 1; - bw = bpp * bmp->width; - for (i = 0; i < bmp->height; i++) - memcpy(bmp_rowptr_from_top(bmp, i), - bmp_rowptr_from_top(wrapbmp, i) + bpp * c0, bw); - bw = (c2 - c1 + 1) * bpp; - if (bw > 0) - for (i = wrapbmp_hyphen.r1; i <= wrapbmp_hyphen.r2; i++) - memset(bmp_rowptr_from_top(bmp, i) + bpp * c1, 255, bw); -#if (WILLUSDEBUGX & 16) - { - static int count=1; - char filename[256]; - sprintf(filename,"be%04d.png",count); - bmp_write(wrapbmp,filename,stdout,100); - sprintf(filename,"ae%04d.png",count); - bmp_write(bmp,filename,stdout,100); - count++; - } -#endif - bmp_copy(wrapbmp, bmp); - bmp_free(bmp); -} - -/* - ** src is only allocated if dst_color != 0 - */ -static void white_margins(WILLUSBITMAP *src, WILLUSBITMAP *srcgrey) - -{ - int i, n; - BMPREGION *region, _region; - - region = &_region; - region->bmp = srcgrey; - get_white_margins(region); - n = region->c1; - for (i = 0; i < srcgrey->height; i++) { - unsigned char *p; - if (dst_color) { - p = bmp_rowptr_from_top(src, i); - memset(p, 255, n * 3); - } - p = bmp_rowptr_from_top(srcgrey, i); - memset(p, 255, n); - } - n = srcgrey->width - 1 - region->c2; - for (i = 0; i < srcgrey->height; i++) { - unsigned char *p; - if (dst_color) { - p = bmp_rowptr_from_top(src, i) + 3 * (src->width - n); - memset(p, 255, n * 3); - } - p = bmp_rowptr_from_top(srcgrey, i) + srcgrey->width - n; - memset(p, 255, n); - } - n = region->r1; - for (i = 0; i < n; i++) { - unsigned char *p; - if (dst_color) { - p = bmp_rowptr_from_top(src, i); - memset(p, 255, src->width * 3); - } - p = bmp_rowptr_from_top(srcgrey, i); - memset(p, 255, srcgrey->width); - } - n = srcgrey->height - 1 - region->r2; - for (i = srcgrey->height - n; i < srcgrey->height; i++) { - unsigned char *p; - if (dst_color) { - p = bmp_rowptr_from_top(src, i); - memset(p, 255, src->width * 3); - } - p = bmp_rowptr_from_top(srcgrey, i); - memset(p, 255, srcgrey->width); - } -} - -static void get_white_margins(BMPREGION *region) - -{ - int n; - double defval; - - defval = 0.25; - if (mar_left < 0.) - mar_left = defval; - n = (int) (0.5 + mar_left * src_dpi); - if (n > region->bmp->width) - n = region->bmp->width; - region->c1 = n; - if (mar_right < 0.) - mar_right = defval; - n = (int) (0.5 + mar_right * src_dpi); - if (n > region->bmp->width) - n = region->bmp->width; - region->c2 = region->bmp->width - 1 - n; - if (mar_top < 0.) - mar_top = defval; - n = (int) (0.5 + mar_top * src_dpi); - if (n > region->bmp->height) - n = region->bmp->height; - region->r1 = n; - if (mar_bot < 0.) - mar_bot = defval; - n = (int) (0.5 + mar_bot * src_dpi); - if (n > region->bmp->height) - n = region->bmp->height; - region->r2 = region->bmp->height - 1 - n; -} - -/* - ** bitmap_orientation() - ** - ** 1.0 means neutral - ** - ** >> 1.0 means document is likely portrait (no rotation necessary) - ** (max is 100.) - ** - ** << 1.0 means document is likely landscape (need to rotate it) - ** (min is 0.01) - ** - */ -static double bitmap_orientation(WILLUSBITMAP *bmp) - -{ - int i, ic, wtcalc; - double hsum, vsum, rat; - - wtcalc = -1; - for (vsum = 0., hsum = 0., ic = 0, i = 20; i <= 85; i += 5, ic++) { - double nv, nh; - int wth, wtv; - -#ifdef DEBUG - printf("h %d:\n",i); -#endif - if (ic == 0) - wth = -1; - else - wth = wtcalc; - wth = -1; - nh = bmp_inflections_horizontal(bmp, 8, i, &wth); -#ifdef DEBUG - { - FILE *f; - f=fopen("inf.ep","a"); - fprintf(f,"/ag\n"); - fclose(f); - } - printf("v %d:\n",i); -#endif - if (ic == 0) - wtv = -1; - else - wtv = wtcalc; - wtv = -1; - nv = bmp_inflections_vertical(bmp, 8, i, &wtv); - if (ic == 0) { - if (wtv > wth) - wtcalc = wtv; - else - wtcalc = wth; - continue; - } -// exit(10); - hsum += nh * i * i * i; - vsum += nv * i * i * i; - } - if (vsum == 0. && hsum == 0.) - rat = 1.0; - else if (hsum < vsum && hsum / vsum < .01) - rat = 100.; - else - rat = vsum / hsum; - if (rat < .01) - rat = .01; - // printf(" page %2d: %8.4f\n",pagenum,rat); - // fprintf(out,"\t%8.4f",vsum/hsum); - // fprintf(out,"\n"); - return (rat); -} - -static double bmp_inflections_vertical(WILLUSBITMAP *srcgrey, int ndivisions, - int delta, int *wthresh) - -{ - int y0, y1, ny, i, nw, nisum, ni, wt, wtmax; - double *g; - char *funcname = "bmp_inflections_vertical"; - - nw = srcgrey->width / ndivisions; - y0 = srcgrey->height / 6; - y1 = srcgrey->height - y0; - ny = y1 - y0; - willus_dmem_alloc_warn(21, (void **) &g, ny * sizeof(double), funcname, 10); - wtmax = -1; - for (nisum = 0, i = 0; i < 10; i++) { - int x0, x1, nx, j; - - x0 = (srcgrey->width - nw) * (i + 2) / 13; - x1 = x0 + nw; - if (x1 > srcgrey->width) - x1 = srcgrey->width; - nx = x1 - x0; - for (j = y0; j < y1; j++) { - int k, rsum; - unsigned char *p; - - p = bmp_rowptr_from_top(srcgrey, j) + x0; - for (rsum = k = 0; k < nx; k++, p++) - rsum += p[0]; - g[j - y0] = (double) rsum / nx; - } - wt = (*wthresh); - ni = inflection_count(g, ny, delta, &wt); - if ((*wthresh) < 0 && ni >= 3 && wt > wtmax) - wtmax = wt; - if (ni > nisum) - nisum = ni; - } - willus_dmem_free(21, &g, funcname); - if ((*wthresh) < 0) - (*wthresh) = wtmax; - return (nisum); -} - -static double bmp_inflections_horizontal(WILLUSBITMAP *srcgrey, int ndivisions, - int delta, int *wthresh) - -{ - int x0, x1, nx, bw, i, nh, nisum, ni, wt, wtmax; - double *g; - char *funcname = "bmp_inflections_vertical"; - - nh = srcgrey->height / ndivisions; - x0 = srcgrey->width / 6; - x1 = srcgrey->width - x0; - nx = x1 - x0; - bw = bmp_bytewidth(srcgrey); - willus_dmem_alloc_warn(22, (void **) &g, nx * sizeof(double), funcname, 10); - wtmax = -1; - for (nisum = 0, i = 0; i < 10; i++) { - int y0, y1, ny, j; - - y0 = (srcgrey->height - nh) * (i + 2) / 13; - y1 = y0 + nh; - if (y1 > srcgrey->height) - y1 = srcgrey->height; - ny = y1 - y0; - for (j = x0; j < x1; j++) { - int k, rsum; - unsigned char *p; - - p = bmp_rowptr_from_top(srcgrey, y0) + j; - for (rsum = k = 0; k < ny; k++, p += bw) - rsum += p[0]; - g[j - x0] = (double) rsum / ny; - } - wt = (*wthresh); - ni = inflection_count(g, nx, delta, &wt); - if ((*wthresh) < 0 && ni >= 3 && wt > wtmax) - wtmax = wt; - if (ni > nisum) - nisum = ni; - } - willus_dmem_free(22, &g, funcname); - if ((*wthresh) < 0) - (*wthresh) = wtmax; - return (nisum); -} - -static int inflection_count(double *x, int n, int delta, int *wthresh) - -{ - int i, i0, ni, ww, c, ct, wt, mode; - double meandi, meandisq, f1, f2, stdev; - double *xs; - static int hist[256]; - static char *funcname = "inflection_count"; - - /* Find threshold white value that peaks must exceed */ - if ((*wthresh) < 0) { - for (i = 0; i < 256; i++) - hist[i] = 0; - for (i = 0; i < n; i++) { - i0 = floor(x[i]); - if (i0 > 255) - i0 = 255; - hist[i0]++; - } - ct = n * .15; - for (c = 0, i = 255; i >= 0; i--) { - c += hist[i]; - if (c > ct) - break; - } - wt = i - 10; - if (wt < 192) - wt = 192; -#ifdef DEBUG - printf("wt=%d\n",wt); -#endif - (*wthresh) = wt; - } else - wt = (*wthresh); - ww = n / 150; - if (ww < 1) - ww = 1; - willus_dmem_alloc_warn(23, (void **) &xs, sizeof(double) * n, funcname, 10); - for (i = 0; i < n - ww; i++) { - int j; - for (xs[i] = 0., j = 0; j < ww; j++, xs[i] += x[i + j]) - ; - xs[i] /= ww; - } - meandi = meandisq = 0.; - if (xs[0] <= wt - delta) - mode = 1; - else if (xs[0] >= wt) - mode = -1; - else - mode = 0; - for (i0 = 0, ni = 0, i = 1; i < n - ww; i++) { - if (mode == 1 && xs[i] >= wt) { - if (i0 > 0) { - meandi += i - i0; - meandisq += (i - i0) * (i - i0); - ni++; - } - i0 = i; - mode = -1; - continue; - } - if (xs[i] <= wt - delta) - mode = 1; - } - stdev = 1.0; /* Avoid compiler warning */ - if (ni > 0) { - meandi /= ni; - meandisq /= ni; - stdev = sqrt(fabs(meandi * meandi - meandisq)); - } - f1 = meandi / n; - if (f1 > .15) - f1 = .15; - if (ni > 2) { - if (stdev / meandi < .05) - f2 = 20.; - else - f2 = meandi / stdev; - } else - f2 = 1.; -#ifdef DEBUG - printf(" ni=%3d, f1=%8.4f, f2=%8.4f, f1*f2*ni=%8.4f\n",ni,f1,f2,f1*f2*ni); - { - static int count=0; - FILE *f; - int i; - f=fopen("inf.ep",count==0?"w":"a"); - count++; - fprintf(f,"/sa l \"%d\" 1\n",ni); - for (i=0;in = boxes->na = 0; - boxes->box = NULL; -} - -static void pdfboxes_free(PDFBOXES *boxes) - -{ - static char *funcname = "pdfboxes_free"; - willus_dmem_free(24, (double **) &boxes->box, funcname); -} - -#ifdef COMMENT -static void pdfboxes_add_box(PDFBOXES *boxes,PDFBOX *box) - -{ - static char *funcname="pdfboxes_add_box"; - - if (boxes->n>=boxes->na) - { - int newsize; - - newsize = boxes->na < 1024 ? 2048 : boxes->na*2; - /* Just calls willus_mem_alloc if oldsize==0 */ - willus_mem_realloc_robust_warn((void **)&boxes->box,newsize*sizeof(PDFBOX), - boxes->na*sizeof(PDFBOX),funcname,10); - boxes->na=newsize; - } - boxes->box[boxes->n++]=(*box); -} - -static void pdfboxes_delete(PDFBOXES *boxes,int n) - -{ - if (n>0 && nn) - { - int i; - for (i=0;in-n;i++) - boxes->box[i]=boxes->box[i+n]; - } - boxes->n -= n; - if (boxes->n < 0) - boxes->n = 0; -} -#endif - -/* - ** Track gaps between words so that we can tell when one is out of family. - ** lcheight = height of a lowercase letter. - */ -static void word_gaps_add(BREAKINFO *breakinfo, int lcheight, - double *median_gap) - -{ - static int nn = 0; - static double gap[1024]; - static char *funcname = "word_gaps_add"; - - if (breakinfo != NULL && breakinfo->n > 1) { - int i; - - for (i = 0; i < breakinfo->n - 1; i++) { - double g; - g = (double) breakinfo->textrow[i].gap / lcheight; - if (g >= word_spacing) { - gap[nn & 0x3ff] = g; - nn++; - } - } - } - if (median_gap != NULL) { - if (nn > 0) { - int n; - static double *gap_sorted; - - n = (nn > 1024) ? 1024 : nn; - willus_dmem_alloc_warn(28, (void **) &gap_sorted, - sizeof(double) * n, funcname, 10); - memcpy(gap_sorted, gap, n * sizeof(double)); - sortd(gap_sorted, n); - (*median_gap) = gap_sorted[n / 2]; - willus_dmem_free(28, &gap_sorted, funcname); - } else - (*median_gap) = 0.7; - } -} - -/* - ** bmp must be grayscale! (cbmp = color, can be null) - */ -static void bmp_detect_vertical_lines(WILLUSBITMAP *bmp, WILLUSBITMAP *cbmp, - double dpi, double minwidth_in, double maxwidth_in, double minheight_in, - double anglemax_deg, int white_thresh) - -{ - int tc, iangle, irow, icol; - int rowstep, na, angle_sign, ccthresh; - int pixmin, halfwidth, bytewidth; - int bs1, nrsteps; - double anglestep; - WILLUSBITMAP *tmp, _tmp; - unsigned char *p0; - unsigned char *t0; - - if (debug) - printf("At bmp_detect_vertical_lines...\n"); - if (!bmp_is_grayscale(bmp)) { - printf( - "Internal error. bmp_detect_vertical_lines passed a non-grayscale bitmap.\n"); - exit(10); - } - tmp = &_tmp; - bmp_init(tmp); - bmp_copy(tmp, bmp); - p0 = bmp_rowptr_from_top(bmp, 0); - t0 = bmp_rowptr_from_top(tmp, 0); - bytewidth = bmp_bytewidth(bmp); - pixmin = (int) (minwidth_in * dpi + .5); - if (pixmin < 1) - pixmin = 1; - halfwidth = pixmin / 4; - if (halfwidth < 1) - halfwidth = 1; - anglestep = atan2((double) halfwidth / dpi, minheight_in); - na = (int) ((anglemax_deg * PI / 180.) / anglestep + .5); - if (na < 1) - na = 1; - rowstep = (int) (dpi / 40. + .5); - if (rowstep < 2) - rowstep = 2; - nrsteps = bmp->height / rowstep; - bs1 = bytewidth * rowstep; - ccthresh = (int) (minheight_in * dpi / rowstep + .5); - if (ccthresh < 2) - ccthresh = 2; - if (debug && verbose) - printf( - " na = %d, rowstep = %d, ccthresh = %d, white_thresh = %d, nrsteps=%d\n", - na, rowstep, ccthresh, white_thresh, nrsteps); - /* - bmp_write(bmp,"out.png",stdout,97); - wfile_written_info("out.png",stdout); - */ - for (tc = 0; tc < 100; tc++) { - int ccmax, ic0max, ir0max; - double tanthmax; - - ccmax = -1; - ic0max = ir0max = 0; - tanthmax = 0.; - for (iangle = 0; iangle <= na; iangle++) { - for (angle_sign = 1; angle_sign >= -1; angle_sign -= 2) { - double th, tanth, tanthx; - int ic1, ic2; - - if (iangle == 0 && angle_sign == -1) - continue; - th = (PI / 180.) * iangle * angle_sign * fabs(anglemax_deg) - / na; - tanth = tan(th); - tanthx = tanth * rowstep; - if (angle_sign == 1) { - ic1 = -(int) (bmp->height * tanth + 1.); - ic2 = bmp->width - 1; - } else { - ic1 = (int) (-bmp->height * tanth + 1.); - ic2 = bmp->width - 1 + (int) (-bmp->height * tanth + 1.); - } -// printf("iangle=%2d, angle_sign=%2d, ic1=%4d, ic2=%4d\n",iangle,angle_sign,ic1,ic2); - for (icol = ic1; icol <= ic2; icol++) { - unsigned char *p, *t; - int cc, ic0, ir0; - p = p0; - t = t0; - if (icol < 0 || icol > bmp->width - 1) - for (irow = 0; irow < nrsteps; irow++, p += bs1, t += - bs1) { - int ic; - ic = icol + irow * tanthx; - if (ic >= 0 && ic < bmp->width) - break; - } - else - irow = 0; - for (ir0 = ic0 = cc = 0; irow < nrsteps; - irow++, p += bs1, t += bs1) { - int ic; - ic = icol + irow * tanthx; - if (ic < 0 || ic >= bmp->width) - break; - if ((p[ic] < white_thresh - || p[ic + bytewidth] < white_thresh) - && (t[ic] < white_thresh - || t[ic + bytewidth] < white_thresh)) { - if (cc == 0) { - ic0 = ic; - ir0 = irow * rowstep; - } - cc++; - if (cc > ccmax) { - ccmax = cc; - tanthmax = tanth; - ic0max = ic0; - ir0max = ir0; - } - } else - cc = 0; - } - } - } - } - if (ccmax < ccthresh) - break; - if (debug) - printf( - " Vert line detected: ccmax=%d (pix=%d), tanthmax=%g, ic0max=%d, ir0max=%d\n", - ccmax, ccmax * rowstep, tanthmax, ic0max, ir0max); - if (!vert_line_erase(bmp, cbmp, tmp, ir0max, ic0max, tanthmax, - minheight_in, minwidth_in, maxwidth_in, white_thresh)) - break; - } - /* - bmp_write(tmp,"outt.png",stdout,95); - wfile_written_info("outt.png",stdout); - bmp_write(bmp,"out2.png",stdout,95); - wfile_written_info("out2.png",stdout); - exit(10); - */ -} - -/* - ** Calculate max vert line length. Line is terminated by nw consecutive white pixels - ** on either side. - */ -static int vert_line_erase(WILLUSBITMAP *bmp, WILLUSBITMAP *cbmp, - WILLUSBITMAP *tmp, int row0, int col0, double tanth, - double minheight_in, double minwidth_in, double maxwidth_in, - int white_thresh) - -{ - int lw, cc, maxdev, nw, dir, i, n; - int *c1, *c2, *w; - static char *funcname = "vert_line_erase"; - - willus_dmem_alloc_warn(26, (void **) &c1, sizeof(int) * 3 * bmp->height, - funcname, 10); - c2 = &c1[bmp->height]; - w = &c2[bmp->height]; - /* - maxdev = (int)((double)bmp->height / minheight_in +.5); - if (maxdev < 3) - maxdev=3; - */ - nw = (int) ((double) src_dpi / 100. + .5); - if (nw < 2) - nw = 2; - maxdev = nw; - for (i = 0; i < bmp->height; i++) - c1[i] = c2[i] = -1; - n = 0; - for (dir = -1; dir <= 1; dir += 2) { - int del, brc; - - brc = 0; - for (del = (dir == -1) ? 0 : 1; 1; del++) { - int r, c; - unsigned char *p; - - r = row0 + dir * del; - if (r < 0 || r > bmp->height - 1) - break; - c = col0 + (r - row0) * tanth; - if (c < 0 || c > bmp->width - 1) - break; - p = bmp_rowptr_from_top(bmp, r); - for (i = c; i <= c + maxdev && i < bmp->width; i++) - if (p[i] < white_thresh) - break; - if (i > c + maxdev || i >= bmp->width) { - for (i = c - 1; i >= c - maxdev && i >= 0; i--) - if (p[i] < white_thresh) - break; - if (i < c - maxdev || i < 0) { - brc++; - if (brc >= nw) - break; - continue; - } - } - brc = 0; - for (c = i, cc = 0; i < bmp->width; i++) - if (p[i] < white_thresh) - cc = 0; - else { - cc++; - if (cc >= nw) - break; - } - c2[r] = i - cc; - if (c2[r] > bmp->width - 1) - c2[r] = bmp->width - 1; - for (cc = 0, i = c; i >= 0; i--) - if (p[i] < white_thresh) - cc = 0; - else { - cc++; - if (cc >= nw) - break; - } - c1[r] = i + cc; - if (c1[r] < 0) - c1[r] = 0; - w[n++] = c2[r] - c1[r] + 1; - c1[r] -= cc; - if (c1[r] < 0) - c1[r] = 0; - c2[r] += cc; - if (c2[r] > bmp->width - 1) - c2[r] = bmp->width - 1; - } - } - if (n > 1) - sorti(w, n); - if (n < 10 || n < minheight_in * src_dpi || w[n / 4] < minwidth_in * src_dpi - || w[3 * n / 4] > maxwidth_in * src_dpi - || (erase_vertical_lines == 1 && w[n - 1] > maxwidth_in * src_dpi)) { - /* Erase area in temp bitmap */ - for (i = 0; i < bmp->height; i++) { - unsigned char *p; - int cmax; - - if (c1[i] < 0 || c2[i] < 0) - continue; - cmax = (c2[i] - c1[i]) + 1; - p = bmp_rowptr_from_top(tmp, i) + c1[i]; - for (; cmax > 0; cmax--, p++) - (*p) = 255; - } - } else { - /* Erase line width in source bitmap */ - lw = w[3 * n / 4] + nw * 2; - if (lw > maxwidth_in * src_dpi / 2) - lw = maxwidth_in * src_dpi / 2; - for (i = 0; i < bmp->height; i++) { - unsigned char *p; - int c0, cmin, cmax, count, white; - - if (c1[i] < 0 || c2[i] < 0) - continue; - c0 = col0 + (i - row0) * tanth; - cmin = c0 - lw - 1; - if (cmin < c1[i]) - cmin = c1[i]; - cmax = c0 + lw + 1; - if (cmax > c2[i]) - cmax = c2[i]; - p = bmp_rowptr_from_top(bmp, i); - c0 = (p[cmin] > p[cmax]) ? cmin : cmax; - white = p[c0]; - if (white <= white_thresh) - white = white_thresh + 1; - if (white > 255) - white = 255; - count = (cmax - cmin) + 1; - p = &p[cmin]; - for (; count > 0; count--, p++) - (*p) = white; - if (cbmp != NULL) { - unsigned char *p0; - p = bmp_rowptr_from_top(cbmp, i); - p0 = p + c0 * 3; - p = p + cmin * 3; - count = (cmax - cmin) + 1; - for (; count > 0; count--, p += 3) { - p[0] = p0[0]; - p[1] = p0[1]; - p[2] = p0[2]; - } - } - } - } - willus_dmem_free(26, (double **) &c1, funcname); - return (1); -} - -/* - ** mem_index... controls which memory allocactions get a protective margin - ** around them. - */ -static int mem_index_min = 999; -static int mem_index_max = 999; -static void willus_dmem_alloc_warn(int index, void **ptr, int size, - char *funcname, int exitcode) - -{ - if (index >= mem_index_min && index <= mem_index_max) { - char *ptr1; - void *x; - willus_mem_alloc_warn((void **) &ptr1, size + 2048, funcname, exitcode); - ptr1 += 1024; - x = (void *) ptr1; - (*ptr) = x; - } else - willus_mem_alloc_warn(ptr, size, funcname, exitcode); -} - -static void willus_dmem_free(int index, double **ptr, char *funcname) - -{ - if ((*ptr) == NULL) - return; - if (index >= mem_index_min && index <= mem_index_max) { - double *x; - char *ptr1; - x = (*ptr); - ptr1 = (char *) x; - ptr1 -= 1024; - x = (double *) ptr1; - willus_mem_free(&x, funcname); - (*ptr) = NULL; - } else - willus_mem_free(ptr, funcname); -} - -/* mem.c */ -/* -** The reason I don't simply use malloc is because I want to allocate -** memory using type long instead of type size_t. On some compilers, -** like gcc, these are the same, so it doesn't matter. On other -** compilers, like Turbo C, these are different. -** -*/ -static int willus_mem_alloc(double **ptr,long size,char *name) - - { -#if (defined(WIN32) && !defined(__DMC__)) - unsigned long memsize; - memsize = (unsigned long)size; -#ifdef USEGLOBAL - (*ptr) = (memsize==size) ? (double *)GlobalAlloc(GPTR,memsize) : NULL; -#else - (*ptr) = (memsize==size) ? (double *)CoTaskMemAlloc(memsize) : NULL; -#endif -#else - size_t memsize; - memsize=(size_t)size; - (*ptr) = (memsize==size) ? (double *)malloc(memsize) : NULL; -#endif -/* -{ -f=fopen("mem.dat","a"); -fprintf(f,"willus_mem_alloc(%d,%s)\n",size,name); -fclose(f); -} -*/ - return((*ptr)!=NULL); - } - -/* -** Prints an integer to 's' with commas separating every three digits. -** E.g. 45,399,350 -** Correctly handles negative values. -*/ -static void comma_print(char *s,long size) - - { - int i,m,neg; - char tbuf[80]; - - if (!size) - { - s[0]='0'; - s[1]='\0'; - return; - } - s[0]='\0'; - neg=0; - if (size<0) - { - size=-size; - neg=1; - } - for (i=0,m=size%1000;size;i++,size=(size-m)/1000,m=size%1000) - { - sprintf(tbuf,m==size ? "%d%s":"%03d%s",m,i>0 ? "," : ""); - strcat(tbuf,s); - strcpy(s,tbuf); - } - if (neg) - { - strcpy(tbuf,"-"); - strcat(tbuf,s); - strcpy(s,tbuf); - } - } - - -static void mem_warn(char *name,int size,int exitcode) - - { - static char buf[128]; - - aprintf("\n" ANSI_RED "\aCannot allocate enough memory for " - "function %s." ANSI_NORMAL "\n",name); - comma_print(buf,size); - aprintf(" " ANSI_RED "(Needed %s bytes.)" ANSI_NORMAL "\n\n",buf); - if (exitcode!=0) - { - aprintf(" " ANSI_RED "Program terminated." ANSI_NORMAL "\n\n"); - exit(exitcode); - } - } - -static int willus_mem_alloc_warn(void **ptr, int size, char *name, int exitcode) - -{ - int status; - - status = willus_mem_alloc((double **) ptr, (long) size, name); - if (!status) - mem_warn(name, size, exitcode); - return (status); -} - -static void willus_mem_free(double **ptr, char *name) - -{ - if ((*ptr) != NULL) { -#if (defined(WIN32) && !defined(__DMC__)) -#ifdef USEGLOBAL - GlobalFree((void *)(*ptr)); -#else - CoTaskMemFree((void *)(*ptr)); -#endif -#else - free((void *) (*ptr)); -#endif - (*ptr) = NULL; - } -} - -static int willus_mem_realloc_robust(double **ptr,long newsize,long oldsize,char *name) - - { -#if (defined(WIN32) && !defined(__DMC__)) - unsigned long memsize; - void *newptr; -#else - size_t memsize; - void *newptr; -#endif - -#if (defined(WIN32) && !defined(__DMC__)) - memsize=(unsigned long)newsize; -#else - memsize=(size_t)newsize; -#endif - if (memsize!=newsize) - return(0); - if ((*ptr)==NULL || oldsize<=0) - return(willus_mem_alloc(ptr,newsize,name)); -#if (defined(WIN32) && !defined(__DMC__)) -#ifdef USEGLOBAL - newptr = (void *)GlobalReAlloc((void *)(*ptr),memsize,GMEM_MOVEABLE); -#else - newptr = (void *)CoTaskMemRealloc((void *)(*ptr),memsize); -#endif -#else - newptr = realloc((void *)(*ptr),memsize); -#endif - if (newptr==NULL && willus_mem_alloc((double **)&newptr,newsize,name)) - { - memcpy(newptr,(*ptr),oldsize); - willus_mem_free(ptr,name); - } - if (newptr==NULL) - return(0); - - (*ptr) = newptr; - return(1); - } - - -static int willus_mem_realloc_robust_warn(void **ptr,int newsize,int oldsize,char *name, - int exitcode) - - { - int status; - - status = willus_mem_realloc_robust((double **)ptr,newsize,oldsize,name); - if (!status) - mem_warn(name,newsize,exitcode); - return(status); - } - -/* math.c */ -static void sortd(double *x, int n) - -{ - int top, n1; - double x0; - - if (n < 2) - return; - top = n / 2; - n1 = n - 1; - while (1) { - if (top > 0) { - top--; - x0 = x[top]; - } else { - x0 = x[n1]; - x[n1] = x[0]; - n1--; - if (!n1) { - x[0] = x0; - return; - } - } - { - int parent, child; - - parent = top; - child = top * 2 + 1; - while (child <= n1) { - if (child < n1 && x[child] < x[child + 1]) - child++; - if (x0 < x[child]) { - x[parent] = x[child]; - parent = child; - child += (parent + 1); - } else - break; - } - x[parent] = x0; - } - } -} - -static void sorti(int *x, int n) - -{ - int top, n1; - int x0; - - if (n < 2) - return; - top = n / 2; - n1 = n - 1; - while (1) { - if (top > 0) { - top--; - x0 = x[top]; - } else { - x0 = x[n1]; - x[n1] = x[0]; - n1--; - if (!n1) { - x[0] = x0; - return; - } - } - { - int parent, child; - - parent = top; - child = top * 2 + 1; - while (child <= n1) { - if (child < n1 && x[child] < x[child + 1]) - child++; - if (x0 < x[child]) { - x[parent] = x[child]; - parent = child; - child += (parent + 1); - } else - break; - } - x[parent] = x0; - } - } -} - -/* bmp.c */ -/* - ** Should call bmp_set_type() right after this to set the bitmap type. - */ - -#define RGBSET24(bmp,ptr,r,g,b) \ - if (bmp->type==WILLUSBITMAP_TYPE_NATIVE) \ - { \ - ptr[0]=r; \ - ptr[1]=g; \ - ptr[2]=b; \ - } \ - else \ - { \ - ptr[2]=r; \ - ptr[1]=g; \ - ptr[0]=b; \ - } - -#define RGBGET(bmp,ptr,r,g,b) \ - if (bmp->bpp==8) \ - { \ - r=bmp->red[ptr[0]]; \ - g=bmp->green[ptr[0]]; \ - b=bmp->blue[ptr[0]]; \ - } \ - else if (bmp->type==WILLUSBITMAP_TYPE_NATIVE) \ - { \ - r=ptr[0]; \ - g=ptr[1]; \ - b=ptr[2]; \ - } \ - else \ - { \ - r=ptr[2]; \ - g=ptr[1]; \ - b=ptr[0]; \ - } - -#define RGBGETINCPTR(bmp,ptr,r,g,b) \ - if (bmp->bpp==8) \ - { \ - r=bmp->red[ptr[0]]; \ - g=bmp->green[ptr[0]]; \ - b=bmp->blue[ptr[0]]; \ - ptr++; \ - } \ - else if (bmp->type==WILLUSBITMAP_TYPE_NATIVE) \ - { \ - r=ptr[0]; \ - g=ptr[1]; \ - b=ptr[2]; \ - ptr+=3; \ - } \ - else \ - { \ - r=ptr[2]; \ - g=ptr[1]; \ - b=ptr[0]; \ - ptr+=3; \ - } - -static void bmp_init(WILLUSBITMAP *bmap) - -{ - bmap->data = NULL; - bmap->size_allocated = 0; - bmap->type = WILLUSBITMAP_TYPE_NATIVE; -} - -static int bmp_bytewidth_win32(WILLUSBITMAP *bmp) - - { - return(((bmp->bpp==24 ? bmp->width*3 : bmp->width)+3)&(~0x3)); - } - -/* - ** The width, height, and bpp parameters of the WILLUSBITMAP structure - ** should be set before calling this function. - */ -static int bmp_alloc(WILLUSBITMAP *bmap) - -{ - int size; - static char *funcname = "bmp_alloc"; - - if (bmap->bpp != 8 && bmap->bpp != 24) { - printf("Internal error: call to bmp_alloc has bpp!=8 and bpp!=24!\n"); - exit(10); - } - /* Choose the max size even if not WIN32 to avoid memory faults */ - /* and to allow the possibility of changing the "type" of the */ - /* bitmap without reallocating memory. */ - size = bmp_bytewidth_win32(bmap) * bmap->height; - if (bmap->data != NULL && bmap->size_allocated >= size) - return (1); - if (bmap->data != NULL) - willus_mem_realloc_robust_warn((void **) &bmap->data, size, - bmap->size_allocated, funcname, 10); - else - willus_mem_alloc_warn((void **) &bmap->data, size, funcname, 10); - bmap->size_allocated = size; - return (1); -} - -static void bmp_free(WILLUSBITMAP *bmap) - - { - if (bmap->data!=NULL) - { - willus_mem_free((double **)&bmap->data,"bmp_free"); - bmap->data=NULL; - bmap->size_allocated=0; - } - } - -/* -** If 8-bit, the bitmap is filled with . -** If 24-bit, it gets , , values. -*/ -static void bmp_fill(WILLUSBITMAP *bmp,int r,int g,int b) - - { - int y,n; - - if (bmp->bpp==8 || (r==g && r==b)) - { - memset(bmp->data,r,bmp->size_allocated); - return; - } - if (bmp->type==WILLUSBITMAP_TYPE_WIN32 && bmp->bpp==24) - { - y=r; - r=b; - b=y; - } - for (y=bmp->height-1;y>=0;y--) - { - unsigned char *p; - - p=bmp_rowptr_from_top(bmp,y); - for (n=bmp->width-1;n>=0;n--) - { - (*p)=r; - p++; - (*p)=g; - p++; - (*p)=b; - p++; - } - } - } - - -static int bmp_copy(WILLUSBITMAP *dest, WILLUSBITMAP *src) - -{ - dest->width = src->width; - dest->height = src->height; - dest->bpp = src->bpp; - dest->type = src->type; - if (!bmp_alloc(dest)) - return (0); - memcpy(dest->data, src->data, src->height * bmp_bytewidth(src)); - memcpy(dest->red, src->red, sizeof(int) * 256); - memcpy(dest->green, src->green, sizeof(int) * 256); - memcpy(dest->blue, src->blue, sizeof(int) * 256); - return (1); -} - -static int bmp_bytewidth(WILLUSBITMAP *bmp) { - return (bmp->bpp == 24 ? bmp->width * 3 : bmp->width); -} - -/* - ** row==0 ==> top row of bitmap - ** row==bmp->height-1 ==> bottom row of bitmap - ** (regardless of bitmap type) - */ -static unsigned char *bmp_rowptr_from_top(WILLUSBITMAP *bmp, int row) - -{ - if (bmp->type == WILLUSBITMAP_TYPE_WIN32) - return (&bmp->data[bmp_bytewidth(bmp) * (bmp->height - 1 - row)]); - else - return (&bmp->data[bmp_bytewidth(bmp) * row]); -} - -/* - ** Allocate more bitmap rows. - ** ratio typically something like 1.5 or 2.0 - */ -static void bmp_more_rows(WILLUSBITMAP *bmp, double ratio, int pixval) - -{ - int new_height, new_bytes, bw; - static char *funcname = "bmp_more_rows"; - - new_height = (int) (bmp->height * ratio + .5); - if (new_height <= bmp->height) - return; - bw = bmp_bytewidth(bmp); - new_bytes = bw * new_height; - if (new_bytes > bmp->size_allocated) { - willus_mem_realloc_robust_warn((void **) &bmp->data, new_bytes, - bmp->size_allocated, funcname, 10); - bmp->size_allocated = new_bytes; - } - /* Fill in */ - memset(bmp_rowptr_from_top(bmp, bmp->height), pixval, - (new_height - bmp->height) * bw); - bmp->height = new_height; -} - -static double resample_single(double *y,double x1,double x2) - - { - int i,i1,i2; - double dx,dx1,dx2,sum; - - i1=floor(x1); - i2=floor(x2); - if (i1==i2) - return(y[i1]); - dx=x2-x1; - if (dx>1.) - dx=1.; - dx1= 1.-(x1-i1); - dx2= x2-i2; - sum=0.; - if (dx1 > 1e-8*dx) - sum += dx1*y[i1]; - if (dx2 > 1e-8*dx) - sum += dx2*y[i2]; - for (i=i1+1;i<=i2-1;sum+=y[i],i++); - return(sum/(x2-x1)); - } - -/* -** Resample src[] into dst[]. -** Examples: resample_1d(dst,src,0.,5.,5) would simply copy the -** first five elements of src[] to dst[]. -** -** resample_1d(dst,src,0.,5.,10) would work as follows: -** dst[0] and dst[1] would get src[0]. -** dst[2] and dst[3] would get src[1]. -** and so on. -** -*/ -static void resample_1d(double *dst,double *src,double x1,double x2, - int n) - - { - int i; - double new,last; - - last=x1; - for (i=0;itype==WILLUSBITMAP_TYPE_WIN32 && color>=0) - color=2-color; - for (row=0;rowbpp==8) - { - switch (color) - { - case -1: - for (col=0,p+=x0;colred[p[0]]; - break; - case 1: - for (col=0,p+=x0;colgreen[p[0]]; - break; - case 2: - for (col=0,p+=x0;colblue[p[0]]; - break; - } - } - else - { - p+=color; - for (col=0,p+=3*x0;colwidth (x-coord), and top to bottom go from - ** 0.0 to src->height (y-coord). - ** The cropped rectangle (x1,y1) to (x2,y2) is placed into - ** the destination bitmap, which need not be allocated yet. - ** - ** The destination bitmap will be 8-bit grayscale if the source bitmap - ** passes the bmp_is_grayscale() function. Otherwise it will be 24-bit. - ** - ** Returns 0 for okay. - ** -1 for not enough memory. - ** -2 for bad cropping area or destination bitmap size - */ -static int bmp_resample(WILLUSBITMAP *dest, WILLUSBITMAP *src, double x1, - double y1, double x2, double y2, int newwidth, int newheight) - -{ - int gray, maxlen, colorplanes; - double t; - double *tempbmp; - double *temprow; - int color, hmax, row, col, dy; - static char *funcname = "bmp_resample"; - - /* Clip and sort x1,y1 and x2,y2 */ - if (x1 > src->width) - x1 = src->width; - else if (x1 < 0.) - x1 = 0.; - if (x2 > src->width) - x2 = src->width; - else if (x2 < 0.) - x2 = 0.; - if (y1 > src->height) - y1 = src->height; - else if (y1 < 0.) - y1 = 0.; - if (y2 > src->height) - y2 = src->height; - else if (y2 < 0.) - y2 = 0.; - if (x2 < x1) { - t = x2; - x2 = x1; - x1 = t; - } - if (y2 < y1) { - t = y2; - y2 = y1; - y1 = t; - } - dy = y2 - y1; - dy += 2; - if (x2 - x1 == 0. || y2 - y1 == 0.) - return (-2); - - /* Allocate temp storage */ - maxlen = x2 - x1 > dy + newheight ? (int) (x2 - x1) : dy + newheight; - maxlen += 16; - hmax = newheight > dy ? newheight : dy; - if (!willus_mem_alloc(&temprow, maxlen * sizeof(double), funcname)) - return (-1); - if (!willus_mem_alloc(&tempbmp, hmax * newwidth * sizeof(double), - funcname)) { - willus_mem_free(&temprow, funcname); - return (-1); - } - if ((gray = bmp_is_grayscale(src)) != 0) { - int i; - dest->bpp = 8; - for (i = 0; i < 256; i++) - dest->red[i] = dest->blue[i] = dest->green[i] = i; - } else - dest->bpp = 24; - dest->width = newwidth; - dest->height = newheight; - dest->type = WILLUSBITMAP_TYPE_NATIVE; - if (!bmp_alloc(dest)) { - willus_mem_free(&tempbmp, funcname); - willus_mem_free(&temprow, funcname); - return (-1); - } - colorplanes = gray ? 1 : 3; - for (color = 0; color < colorplanes; color++) { - bmp_resample_1(tempbmp, src, x1, y1, x2, y2, newwidth, newheight, - temprow, gray ? -1 : color); - for (row = 0; row < newheight; row++) { - unsigned char *p; - double *s; - p = bmp_rowptr_from_top(dest, row) + color; - s = &tempbmp[row * newwidth]; - if (colorplanes == 1) - for (col = 0; col < newwidth; - p[0] = (int) (s[0] + .5), col++, s++, p++) - ; - else - for (col = 0; col < newwidth; - p[0] = (int) (s[0] + .5), col++, s++, p += colorplanes) - ; - } - } - willus_mem_free(&tempbmp, funcname); - willus_mem_free(&temprow, funcname); - return (0); -} - -static int bmp8_greylevel_convert(int r,int g,int b) - - { - return((int)((r*0.3+g*0.59+b*0.11)*1.002)); - } - -/* -** One of dest or src can be NULL, which is the -** same as setting them equal to each other, but -** in this case, the bitmap must be 24-bit! -*/ -static int bmp_is_grayscale(WILLUSBITMAP *bmp) - - { - int i; - if (bmp->bpp!=8) - return(0); - for (i=0;i<256;i++) - if (bmp->red[i]!=i || bmp->green[i]!=i || bmp->blue[i]!=i) - return(0); - return(1); - } - -static void bmp_color_xform8(WILLUSBITMAP *dest,WILLUSBITMAP *src,unsigned char *newval) - - { - int i,ir; - - if (src==NULL) - src=dest; - if (dest==NULL) - dest=src; - if (dest!=src) - { - dest->width = src->width; - dest->height = src->height; - dest->bpp = 8; - for (i=0;i<256;i++) - dest->red[i]=dest->green[i]=dest->blue[i]=i; - bmp_alloc(dest); - } - for (ir=0;irheight;ir++) - { - unsigned char *sp,*dp; - sp=bmp_rowptr_from_top(src,ir); - dp=bmp_rowptr_from_top(dest,ir); - for (i=0;iwidth;i++) - dp[i]=newval[sp[i]]; - } - } - -/* -** One of dest or src can be NULL, which is the -** same as setting them equal to each other, but -** in this case, the bitmap must be 24-bit! -*/ -static void bmp_color_xform(WILLUSBITMAP *dest,WILLUSBITMAP *src,unsigned char *newval) - - { - int ir,ic; - - if (src==NULL) - src=dest; - if (dest==NULL) - dest=src; - if (bmp_is_grayscale(src)) - { - bmp_color_xform8(dest,src,newval); - return; - } - if (dest!=src) - { - dest->width = src->width; - dest->height = src->height; - dest->bpp = 24; - bmp_alloc(dest); - } - for (ir=0;irheight;ir++) - { - unsigned char *sp,*dp; - sp=bmp_rowptr_from_top(src,ir); - dp=bmp_rowptr_from_top(dest,ir); - for (ic=0;icwidth;ic++,dp+=3) - { - int r,g,b; - - RGBGETINCPTR(src,sp,r,g,b); - r=newval[r]; - g=newval[g]; - b=newval[b]; - RGBSET24(dest,dp,r,g,b); - } - } - } - -/* -** One of dest or src can be NULL, which is the -** same as setting them equal to each other, but -** in this case, the bitmap must be 24-bit! -** Note: contrast > 1 will increase the contrast. -** contrast < 1 will decrease the contrast. -** contrast of 0 will make all pixels the same value. -** contrast of 1 will not change the image. -*/ -static void bmp_contrast_adjust(WILLUSBITMAP *dest,WILLUSBITMAP *src,double contrast) - - { - int i; - static unsigned char newval[256]; - - for (i=0;i<256;i++) - { - double x,y; - int sgn,v; - x=(i-127.5)/127.5; - sgn = x<0 ? -1 : 1; - if (contrast<0) - sgn = -sgn; - x=fabs(x); - if (fabs(contrast)>1.5) - y=x<.99999 ? 1-exp(fabs(contrast)*x/(x-1)) : 1.; - else - { - y=fabs(contrast)*x; - if (y>1.) - y=1.; - } - y = 127.5+y*sgn*127.5; - v = (int)(y+.5); - if (v<0) - v=0; - if (v>255) - v=255; - newval[i] = v; - } - bmp_color_xform(dest,src,newval); - } - -/* - ** Convert bitmap to grey-scale in-situ - */ -static void bmp_convert_to_greyscale_ex(WILLUSBITMAP *dst, WILLUSBITMAP *src) - -{ - int oldbpr, newbpr, bpp, dp, rownum, colnum, i; - - oldbpr = bmp_bytewidth(src); - dp = src->bpp == 8 ? 1 : 3; - bpp = src->bpp; - dst->bpp = 8; - for (i = 0; i < 256; i++) - dst->red[i] = dst->green[i] = dst->blue[i] = i; - if (dst != src) { - dst->width = src->width; - dst->height = src->height; - bmp_alloc(dst); - } - newbpr = bmp_bytewidth(dst); - /* Possibly restore src->bpp to 24 so RGBGET works right (src & dst may be the same) */ - src->bpp = bpp; - for (rownum = 0; rownum < src->height; rownum++) { - unsigned char *oldp, *newp; - oldp = &src->data[oldbpr * rownum]; - newp = &dst->data[newbpr * rownum]; - for (colnum = 0; colnum < src->width; colnum++, oldp += dp, newp++) { - int r, g, b; - RGBGET(src, oldp, r, g, b); - (*newp) = bmp8_greylevel_convert(r, g, b); - } - } - dst->bpp = 8; /* Possibly restore dst->bpp to 8 since src & dst may be the same. */ -} - -/* - ** Bitmap is assumed to be grayscale - */ -static double bmp_row_by_row_stdev(WILLUSBITMAP *bmp, int ccount, - int whitethresh, double theta_radians) - -{ - int dc1, dc2, c1, c2; - int r, n, nn, dw; - double tanth, csum, csumsq, stdev; - - c1 = bmp->width / 15.; - c2 = bmp->width - c1; - dw = (int) ((c2 - c1) / ccount + .5); - if (dw < 1) - dw = 1; - tanth = -tan(theta_radians); - dc1 = (int) (tanth * bmp->width); - if (dc1 < 0) { - dc1 = 1 - dc1; - dc2 = 0; - } else { - dc2 = -dc1 - 1; - dc1 = 0; - } - dc1 += bmp->height / 15.; - dc2 -= bmp->height / 15.; - csum = csumsq = 0.; - n = 0; - for (r = dc1 + 1; r < bmp->height + dc2 - 1; r++) { - int c, count, r0last; - double dcount; - unsigned char *p; - - r0last = 0; - p = bmp_rowptr_from_top(bmp, r0last); - for (nn = count = 0, c = c1; c < c2; c += dw) { - int r0; - - r0 = r + tanth * c; - if (r0 < 0 || r0 >= bmp->height) - continue; - if (r0 != r0last) { - r0last = r0; - p = bmp_rowptr_from_top(bmp, r0last); - } - nn++; - if (p[c] < whitethresh) - count++; - } - dcount = 100. * count / nn; - csum += dcount; - csumsq += dcount * dcount; - n++; - } - stdev = sqrt(fabs((csum / n) * (csum / n) - csumsq / n)); - return (stdev); -} - -/* - ** y0 = 0 ==> bottom row! - */ -static void bmp_pix_vali(WILLUSBITMAP *bmp, int x0, int y0, int *r, int *g, int *b) - -{ - unsigned char *p; - int rr, gg, bb; - - p = bmp_rowptr_from_top(bmp, bmp->height - 1 - y0); - p = &p[x0 * (bmp->bpp >> 3)]; - RGBGET(bmp, p, rr, gg, bb); - (*r) = rr; - (*g) = gg; - (*b) = bb; -} - -/* - ** y0 = 0 ==> bottom row! - */ -static int bmp_grey_pix_vali(WILLUSBITMAP *bmp, int x0, int y0) - -{ - unsigned char *p; - int r, g, b; - - p = bmp_rowptr_from_top(bmp, bmp->height - 1 - y0); - p = &p[x0 * (bmp->bpp >> 3)]; - RGBGET(bmp, p, r, g, b); - return (bmp8_greylevel_convert(r, g, b)); -} - -/* - ** Return pix value (0.0 - 255.0) in double precision given - ** a double precision position. Bitmap is assumed to be 8-bit greyscale. - ** - ** x0,y0 are from bottom corner. - ** x0=0.5, y0=0.5 would give exactly the value of the pixel - ** in the lower left corner of the bitmap. - */ -double bmp_grey_pix_vald(WILLUSBITMAP *bmp, double x0, double y0) - -{ - int ix0, iy0, ix1, iy1; - double fx0, fx1, fy0, fy1; - - ix0 = (int) (x0 - .5); - ix1 = ix0 + 1; - iy0 = (int) (y0 - .5); - iy1 = iy0 + 1; - BOUND(ix0, 0, bmp->width - 1); - BOUND(ix1, 0, bmp->width - 1); - BOUND(iy0, 0, bmp->height - 1); - BOUND(iy1, 0, bmp->height - 1); - fx0 = 1. - fabs(ix0 + 0.5 - x0); - if (fx0 < 0.) - fx0 = 0.; - fx1 = 1. - fabs(ix1 + 0.5 - x0); - if (fx1 < 0.) - fx1 = 0.; - fy0 = 1. - fabs(iy0 + 0.5 - y0); - if (fy0 < 0.) - fy0 = 0.; - fy1 = 1. - fabs(iy1 + 0.5 - y0); - if (fy1 < 0.) - fy1 = 0.; - if ((fx0 == 0. && fx1 == 0.) || (fy0 == 0. && fy1 == 0.)) - return (-1.); - return ((fy0 - * (fx0 * bmp_grey_pix_vali(bmp, ix0, iy0) - + fx1 * bmp_grey_pix_vali(bmp, ix1, iy0)) - + fy1 - * (fx0 * bmp_grey_pix_vali(bmp, ix0, iy1) - + fx1 * bmp_grey_pix_vali(bmp, ix1, iy1))) - / ((fx0 + fx1) * (fy0 + fy1))); -} - - -/* - ** Return pix values (0.0 - 255.0) in double precision given - ** a double precision position. - ** - ** x0,y0 are from BOTTOM CORNER. - ** x0=0.5, y0=0.5 would give exactly the value of the pixel - ** in the lower left corner of the bitmap. - */ -static void bmp_pix_vald(WILLUSBITMAP *bmp, double x0, double y0, double *r, double *g, - double *b) - -{ - int ix0, iy0, ix1, iy1; - double fx0, fx1, fy0, fy1; - int r00, r10, r01, r11; - int g00, g10, g01, g11; - int b00, b10, b01, b11; - - ix0 = (int) (x0 - .5); - ix1 = ix0 + 1; - iy0 = (int) (y0 - .5); - iy1 = iy0 + 1; - BOUND(ix0, 0, bmp->width - 1); - BOUND(ix1, 0, bmp->width - 1); - BOUND(iy0, 0, bmp->height - 1); - BOUND(iy1, 0, bmp->height - 1); - fx0 = 1. - fabs(ix0 + 0.5 - x0); - if (fx0 < 0.) - fx0 = 0.; - fx1 = 1. - fabs(ix1 + 0.5 - x0); - if (fx1 < 0.) - fx1 = 0.; - fy0 = 1. - fabs(iy0 + 0.5 - y0); - if (fy0 < 0.) - fy0 = 0.; - fy1 = 1. - fabs(iy1 + 0.5 - y0); - if (fy1 < 0.) - fy1 = 0.; - if ((fx0 == 0. && fx1 == 0.) || (fy0 == 0. && fy1 == 0.)) { - (*r) = (*g) = (*b) = -1.; - return; - } - bmp_pix_vali(bmp, ix0, iy0, &r00, &g00, &b00); - bmp_pix_vali(bmp, ix1, iy0, &r10, &g10, &b10); - bmp_pix_vali(bmp, ix0, iy1, &r01, &g01, &b01); - bmp_pix_vali(bmp, ix1, iy1, &r11, &g11, &b11); - (*r) = ((fy0 * (fx0 * r00 + fx1 * r10) + fy1 * (fx0 * r01 + fx1 * r11)) - / ((fx0 + fx1) * (fy0 + fy1))); - (*g) = ((fy0 * (fx0 * g00 + fx1 * g10) + fy1 * (fx0 * g01 + fx1 * g11)) - / ((fx0 + fx1) * (fy0 + fy1))); - (*b) = ((fy0 * (fx0 * b00 + fx1 * b10) + fy1 * (fx0 * b01 + fx1 * b11)) - / ((fx0 + fx1) * (fy0 + fy1))); -} - -static void bmp_rotate_fast(WILLUSBITMAP *bmp, double degrees, int expand) - -{ - WILLUSBITMAP _dst, *dst; - double th, sth, cth; - int i, r, g, b, w, h, row, col; - - dst = &_dst; - th = degrees * PI / 180.; - sth = sin(th); - cth = cos(th); - if (expand) { - w = (int) (fabs(bmp->width * cth) + fabs(bmp->height * sth) + .5); - h = (int) (fabs(bmp->height * cth) + fabs(bmp->width * sth) + .5); - } else { - w = bmp->width; - h = bmp->height; - } - dst = &_dst; - bmp_init(dst); - dst->width = w; - dst->height = h; - dst->bpp = bmp->bpp; - if (dst->bpp == 8) - for (i = 0; i <= 255; i++) - dst->red[i] = dst->green[i] = dst->blue[i] = i; - bmp_alloc(dst); - bmp_pix_vali(bmp, 0, 0, &r, &g, &b); - bmp_fill(dst, r, g, b); - if (dst->bpp == 8) - for (row = 0; row < dst->height; row++) { - unsigned char *p; - double x1, y1, x2, y2; - - y2 = dst->height / 2. - row; - p = bmp_rowptr_from_top(dst, row); - for (x2 = -dst->width / 2., col = 0; col < dst->width; - col++, p++, x2 += 1.0) { - double g; - x1 = -.5 + bmp->width / 2. + x2 * cth + y2 * sth; - y1 = -.5 + bmp->height / 2. + y2 * cth - x2 * sth; - if (x1 < 0. || x1 >= bmp->width || y1 < 0. || y1 >= bmp->height) - continue; - g = bmp_grey_pix_vald(bmp, x1, y1); - if (g >= 0.) - p[0] = g; - } - } - else - for (row = 0; row < dst->height; row++) { - unsigned char *p; - double x1, y1, x2, y2; - - y2 = dst->height / 2. - row; - p = bmp_rowptr_from_top(dst, row); - for (x2 = -dst->width / 2., col = 0; col < dst->width; col++, p += - 3, x2 += 1.0) { - double rr, gg, bb; - x1 = -.5 + bmp->width / 2. + x2 * cth + y2 * sth; - y1 = -.5 + bmp->height / 2. + y2 * cth - x2 * sth; - if (x1 < 0. || x1 >= bmp->width || y1 < 0. || y1 >= bmp->height) - continue; - bmp_pix_vald(bmp, x1, y1, &rr, &gg, &bb); - if (rr < 0.) - continue; - p[0] = rr; - p[1] = gg; - p[2] = bb; - } - } - bmp_copy(bmp, dst); - bmp_free(dst); -} - -static double bmp_autostraighten(WILLUSBITMAP *src, WILLUSBITMAP *srcgrey, int white, - double maxdegrees, double mindegrees, int debug) - -{ - int i, na, n, imax; - double stepsize, sdmin, sdmax, rotdeg; - double *sdev; - static int rpc = 0; - static char *funcname = "bmp_autostraighten"; - - rpc++; - stepsize = .5; - na = (int) (maxdegrees / stepsize + .5); - if (na < 1) - na = 1; - n = 1 + na * 2; - sdmin = 999.; - sdmax = -999.; - imax = 0; - willus_mem_alloc_warn((void **) &sdev, n * sizeof(double), funcname, 10); - for (i = 0; i < n; i++) { - double theta, sdev0; - - theta = (i - na) * stepsize * PI / 180.; - sdev0 = bmp_row_by_row_stdev(srcgrey, 400, white, theta); - if (sdmin > sdev0) - sdmin = sdev0; - if (sdmax < sdev0) { - imax = i; - sdmax = sdev0; - } - sdev[i] = sdev0; - } - if (sdmax <= 0.) { - willus_mem_free((double **) &sdev, funcname); - return (0.); - } - for (i = 0; i < n; i++) - sdev[i] /= sdmax; - sdmin /= sdmax; - rotdeg = -(imax - na) * stepsize; - if (sdmin > 0.95 || fabs(rotdeg) <= mindegrees - || fabs(fabs(rotdeg) - fabs(maxdegrees)) < 0.25) { - willus_mem_free((double **) &sdev, funcname); - return (0.); - } - if (imax >= 3 && imax <= n - 4) { - double sd1min, sd2min, sdthresh; - - for (sd1min = sdev[imax - 1], i = imax - 2; i >= 0; i--) - if (sd1min > sdev[i]) - sd1min = sdev[i]; - for (sd2min = sdev[imax + 1], i = imax + 2; i < n; i++) - if (sd2min > sdev[i]) - sd2min = sdev[i]; - sdthresh = sd1min > sd2min ? sd1min * 1.01 : sd2min * 1.01; - if (sdthresh < 0.9) - sdthresh = 0.9; - if (sdthresh < 0.95) { - double deg1, deg2; - - for (i = imax - 1; i >= 0; i--) - if (sdev[i] < sdthresh) - break; - deg1 = - stepsize - * ((i - na) - + (sdthresh - sdev[i]) - / (sdev[i + 1] - sdev[i])); - for (i = imax + 1; i < n - 1; i++) - if (sdev[i] < sdthresh) - break; - deg2 = - stepsize - * ((i - na) - - (sdthresh - sdev[i]) - / (sdev[i - 1] - sdev[i])); - if (deg2 - deg1 < 2.5) { - rotdeg = -(deg1 + deg2) / 2.; - if (debug) - printf("/sa l \"srcpage %d, %.1f%% line\" 2\n/sa m 2 2\n" - "%g 0\n%g 1\n//nc\n" - "/sa l \"srcpage %d, %.1f%% line\" 2\n/sa m 2 2\n" - "%g 0\n%g 1\n//nc\n", rpc, sdthresh * 100., - deg1, deg1, rpc, sdthresh * 100., deg2, deg2); - } - } - } - printf("\n(Straightening page: rotating cc by %.2f deg.)\n", rotdeg); - /* BMP rotation fills with pixel value at (0,0) */ - srcgrey->data[0] = 255; - bmp_rotate_fast(srcgrey, rotdeg, 0); - if (src != NULL) { - src->data[0] = src->data[1] = src->data[2] = 255; - bmp_rotate_fast(src, rotdeg, 0); - } - willus_mem_free((double **) &sdev, funcname); - return (rotdeg); -} - -static void bmp_flip_horizontal(WILLUSBITMAP *bmp) - -{ - int i, j, bpp; - - bpp = bmp->bpp / 8; - for (i = 0; i < bmp->height; i++) { - unsigned char *p, *p2; - - p = bmp_rowptr_from_top(bmp, i); - p2 = &p[(bmp->width - 1) * bpp]; - for (; p < p2; p += bpp, p2 -= bpp) - for (j = 0; j < bpp; j++) { - unsigned char t; - t = p[j]; - p[j] = p2[j]; - p2[j] = t; - } - } -} - -static void bmp_flip_vertical(WILLUSBITMAP *bmp) - -{ - int i, bw, n; - - bw = bmp_bytewidth(bmp); - n = bmp->height / 2; - for (i = 0; i < n; i++) { - unsigned char *p, *p2; - int j; - - p = bmp_rowptr_from_top(bmp, i); - p2 = bmp_rowptr_from_top(bmp, bmp->height - i - 1); - for (j = bw; j > 0; j--, p++, p2++) { - unsigned char t; - t = p[0]; - p[0] = p2[0]; - p2[0] = t; - } - } -} - -static int bmp_rotate_90(WILLUSBITMAP *bmp) - -{ - WILLUSBITMAP *sbmp, _sbmp; - int bpp, dbw, sr; - - sbmp = &_sbmp; - bmp_init(sbmp); - if (!bmp_copy(sbmp, bmp)) - return (0); - bmp->width = sbmp->height; - bmp->height = sbmp->width; - bpp = bmp->bpp / 8; - if (!bmp_alloc(bmp)) { - bmp_free(sbmp); - return (0); - } - dbw = (int) (bmp_rowptr_from_top(bmp, 1) - bmp_rowptr_from_top(bmp, 0)); - for (sr = 0; sr < sbmp->height; sr++) { - unsigned char *sp, *dp; - int j, sc; - - sp = bmp_rowptr_from_top(sbmp, sr); - dp = bmp_rowptr_from_top(bmp, bmp->height - 1) + bpp * sr; - for (sc = sbmp->width; sc > 0; sc--, dp -= dbw) - for (j = 0; j < bpp; j++, sp++) - dp[j] = sp[0]; - } - bmp_free(sbmp); - return (1); -} - -static int bmp_rotate_270(WILLUSBITMAP *bmp) - -{ - WILLUSBITMAP *sbmp, _sbmp; - int bpp, dbw, sr; - - sbmp = &_sbmp; - bmp_init(sbmp); - if (!bmp_copy(sbmp, bmp)) - return (0); - bmp->width = sbmp->height; - bmp->height = sbmp->width; - bpp = bmp->bpp / 8; - if (!bmp_alloc(bmp)) { - bmp_free(sbmp); - return (0); - } - dbw = (int) (bmp_rowptr_from_top(bmp, 1) - bmp_rowptr_from_top(bmp, 0)); - for (sr = 0; sr < sbmp->height; sr++) { - unsigned char *sp, *dp; - int j, sc; - - sp = bmp_rowptr_from_top(sbmp, sr); - dp = bmp_rowptr_from_top(bmp, 0) + bpp * (sbmp->height - 1 - sr); - for (sc = sbmp->width; sc > 0; sc--, dp += dbw) - for (j = 0; j < bpp; j++, sp++) - dp[j] = sp[0]; - } - bmp_free(sbmp); - return (1); -} - -/* - ** 1 = okay, 0 = fail - */ -static int bmp_rotate_right_angle(WILLUSBITMAP *bmp, int degrees) - -{ - int d; - - d = degrees % 360; - if (d < 0) - d += 360; - d = (d + 45) / 90; - if (d == 1) - return (bmp_rotate_90(bmp)); - if (d == 2) { - bmp_flip_horizontal(bmp); - bmp_flip_vertical(bmp); - return (1); - } - if (d == 3) - return (bmp_rotate_270(bmp)); - return (1); -} - -/* bmpmupdf.c */ -static int bmpmupdf_pixmap_to_bmp(WILLUSBITMAP *bmp, fz_context *ctx, - fz_pixmap *pixmap) - -{ - unsigned char *p; - int ncomp, i, row, col; - - bmp->width = fz_pixmap_width(ctx, pixmap); - bmp->height = fz_pixmap_height(ctx, pixmap); - ncomp = fz_pixmap_components(ctx, pixmap); - /* Has to be 8-bit or RGB */ - if (ncomp != 2 && ncomp != 4) - return (-1); - bmp->bpp = (ncomp == 2) ? 8 : 24; - bmp_alloc(bmp); - if (ncomp == 2) - for (i = 0; i < 256; i++) - bmp->red[i] = bmp->green[i] = bmp->blue[i] = i; - p = fz_pixmap_samples(ctx, pixmap); - if (ncomp == 1) - for (row = 0; row < bmp->height; row++) { - unsigned char *dest; - dest = bmp_rowptr_from_top(bmp, row); - memcpy(dest, p, bmp->width); - p += bmp->width; - } - else if (ncomp == 2) - for (row = 0; row < bmp->height; row++) { - unsigned char *dest; - dest = bmp_rowptr_from_top(bmp, row); - for (col = 0; col < bmp->width; col++, dest++, p += 2) - dest[0] = p[0]; - } - else - for (row = 0; row < bmp->height; row++) { - unsigned char *dest; - dest = bmp_rowptr_from_top(bmp, row); - for (col = 0; col < bmp->width; - col++, dest += ncomp - 1, p += ncomp) - memcpy(dest, p, ncomp - 1); - } - return (0); -} - -static void handle(int wait, ddjvu_context_t *ctx) - { - const ddjvu_message_t *msg; - - if (!ctx) - return; - if (wait) - msg = ddjvu_message_wait(ctx); - while ((msg = ddjvu_message_peek(ctx))) - { - switch(msg->m_any.tag) - { - case DDJVU_ERROR: - fprintf(stderr,"ddjvu: %s\n", msg->m_error.message); - if (msg->m_error.filename) - fprintf(stderr,"ddjvu: '%s:%d'\n", - msg->m_error.filename, msg->m_error.lineno); - exit(10); - default: - break; - } - } - ddjvu_message_pop(ctx); -} - -/* wmupdf.c */ -static void wpdfboxes_init(WPDFBOXES *boxes) - -{ - boxes->n = boxes->na = 0; - boxes->box = NULL; -} - -static void wpdfboxes_free(WPDFBOXES *boxes) - -{ - static char *funcname = "wpdfboxes_free"; - willus_mem_free((double **) &boxes->box, funcname); -} - -static void wpdfboxes_add_box(WPDFBOXES *boxes, WPDFBOX *box) - -{ - static char *funcname = "wpdfboxes_add_box"; - - if (boxes->n >= boxes->na) { - int newsize; - - newsize = boxes->na < 1024 ? 2048 : boxes->na * 2; - willus_mem_realloc_robust_warn((void **) &boxes->box, - newsize * sizeof(WPDFBOX), boxes->na * sizeof(WPDFBOX), - funcname, 10); - boxes->na = newsize; - } - boxes->box[boxes->n++] = (*box); -} - diff --git a/k2pdfopt.h b/k2pdfopt.h deleted file mode 100644 index 72615efa1..000000000 --- a/k2pdfopt.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - ** k2pdfopt.h K2pdfopt optimizes PDF/DJVU files for mobile e-readers - ** (e.g. the Kindle) and smartphones. It works well on - ** multi-column PDF/DJVU files. K2pdfopt is freeware. - ** - ** Copyright (C) 2012 http://willus.com - ** - ** This program is free software: you can redistribute it and/or modify - ** it under the terms of the GNU Affero General Public License as - ** published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. - ** - ** You should have received a copy of the GNU Affero General Public License - ** along with this program. If not, see . - ** - */ - -#ifndef _K2PDFOPT_H -#define _K2PDFOPT_H - -#include -#include - -typedef unsigned char uint8_t; -typedef struct KOPTContext { - int trim; - int wrap; - int indent; - int rotate; - int columns; - int offset_x; - int offset_y; - int dev_width; - int dev_height; - int page_width; - int page_height; - int straighten; - int justification; - - double zoom; - double margin; - double quality; - double contrast; - double defect_size; - double line_spacing; - double word_spacing; - - uint8_t *data; -} KOPTContext; - -void k2pdfopt_mupdf_reflow(KOPTContext *kc, fz_document *doc, fz_page *page, fz_context *ctx); -void k2pdfopt_djvu_reflow(KOPTContext *kc, ddjvu_page_t *page, ddjvu_context_t *ctx, ddjvu_render_mode_t mode, ddjvu_format_t *fmt); - -#endif - diff --git a/libk2pdfopt b/libk2pdfopt new file mode 160000 index 000000000..3a2023a51 --- /dev/null +++ b/libk2pdfopt @@ -0,0 +1 @@ +Subproject commit 3a2023a5139bb76c4d106b4425db960f0bc20332