Mercurial > hgrepos > Python2 > PyMuPDF
diff mupdf-source/source/pdf/pdf-layout.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mupdf-source/source/pdf/pdf-layout.c Mon Sep 15 11:43:07 2025 +0200 @@ -0,0 +1,223 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF 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. +// +// MuPDF 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 MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html> +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see <https://www.artifex.com/> or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + +#include "mupdf/fitz.h" +#include "mupdf/pdf.h" +#include <float.h> +#include <math.h> + +#define LINE_LIMIT (100) +#define LINE_HEIGHT (1.2f) +struct line { const char *a, *b; }; + +struct font_info +{ + fz_context *ctx; + fz_font *font; + float fontsize; +}; + +static float measure_character(struct font_info *info, int c) +{ + fz_font *font; + int gid = fz_encode_character_with_fallback(info->ctx, info->font, c, 0, 0, &font); + return fz_advance_glyph(info->ctx, font, gid, 0) * info->fontsize; +} + + +static int break_lines(struct font_info *info, const char *a, struct line *lines, int maxlines, float width, float *maxwidth) +{ + const char *next, *space = NULL, *b = a; + int c, n = 0; + float space_x, x = 0, w = 0; + + if (maxwidth) + *maxwidth = 0; + + while (*b) + { + next = b + fz_chartorune(&c, b); + if (c == '\r' || c == '\n') + { + if (lines && n < maxlines) + { + lines[n].a = a; + lines[n].b = b; + } + ++n; + if (maxwidth && *maxwidth < x) + *maxwidth = x; + a = next; + x = 0; + space = NULL; + } + else + { + if (c == ' ') + { + space = b; + space_x = x; + } + + w = measure_character(info, c); + if (x + w > width) + { + if (space) + { + if (lines && n < maxlines) + { + lines[n].a = a; + lines[n].b = space; + } + ++n; + if (maxwidth && *maxwidth < space_x) + *maxwidth = space_x; + a = next = space + 1; + x = 0; + space = NULL; + } + else + { + if (lines && n < maxlines) + { + lines[n].a = a; + lines[n].b = b; + } + ++n; + if (maxwidth && *maxwidth < x) + *maxwidth = x; + a = b; + x = w; + space = NULL; + } + } + else + { + x += w; + } + } + b = next; + } + + if (lines && n < maxlines) + { + lines[n].a = a; + lines[n].b = b; + } + ++n; + if (maxwidth && *maxwidth < x) + *maxwidth = x; + return n < maxlines ? n : maxlines; +} + +static fz_matrix show_string(fz_context *ctx, fz_text *text, fz_font *user_font, fz_matrix trm, const char *s, int len, + int wmode, int bidi_level, fz_bidi_direction markup_dir, fz_text_language language) +{ + fz_font *font; + int gid, ucs; + float adv; + int i = 0; + + while (i < len) + { + i += fz_chartorune(&ucs, s + i); + gid = fz_encode_character_with_fallback(ctx, user_font, ucs, 0, language, &font); + fz_show_glyph(ctx, text, font, trm, gid, ucs, wmode, bidi_level, markup_dir, language); + adv = fz_advance_glyph(ctx, font, gid, wmode); + if (wmode == 0) + trm = fz_pre_translate(trm, adv, 0); + else + trm = fz_pre_translate(trm, 0, adv); + } + + return trm; +} + +fz_text *pdf_layout_fit_text(fz_context *ctx, fz_font *font, fz_text_language lang, const char *str, fz_rect bounds) +{ + fz_text *text = NULL; + struct font_info info; + struct line *lines; + float width = bounds.x1 - bounds.x0; + float height = bounds.y1 - bounds.y0; + + lines = fz_malloc_array(ctx, LINE_LIMIT, struct line); + + fz_var(info); + fz_try(ctx) + { + fz_matrix trm; + int target_line_count; + int line_count, l; + float line_len; + fz_rect tbounds; + float xadj, yadj; + fz_text_span *span; + + info.ctx = ctx; + info.font = font; + info.fontsize = 1; + + /* Find out how many lines the text requires without any wrapping */ + target_line_count = break_lines(&info, str, lines, LINE_LIMIT, FLT_MAX, &line_len); + + /* Try increasing line counts, which reduces the font size, until the text fits */ + do + { + info.fontsize = height / (target_line_count * LINE_HEIGHT); + line_count = break_lines(&info, str, lines, LINE_LIMIT, width, &line_len); + } while (line_count > target_line_count++); + + trm = fz_scale(info.fontsize, -info.fontsize); + trm.e += bounds.x0; + trm.f += bounds.y1; + text = fz_new_text(ctx); + for (l = 0; l < line_count; l++) + { + show_string(ctx, text, font, trm, lines[l].a, lines[l].b - lines[l].a, 0, 0, FZ_BIDI_LTR, lang); + trm = fz_pre_translate(trm, 0.0f, -LINE_HEIGHT); + } + tbounds = fz_bound_text(ctx, text, NULL, fz_identity); + xadj = (bounds.x0 + bounds.x1 - tbounds.x0 - tbounds.x1) / 2.0f; + yadj = (bounds.y0 + bounds.y1 - tbounds.y0 - tbounds.y1) / 2.0f; + for (span = text->head; span; span = span->next) + { + int i; + for (i = 0; i < span->len; i++) + { + span->items[i].x += xadj; + span->items[i].y += yadj; + } + } + } + fz_always(ctx) + { + fz_free(ctx, lines); + } + fz_catch(ctx) + { + fz_drop_text(ctx, text); + fz_rethrow(ctx); + } + + return text; +}
