Mercurial > hgrepos > Python2 > PyMuPDF
diff mupdf-source/thirdparty/leptonica/src/pixtiling.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/thirdparty/leptonica/src/pixtiling.c Mon Sep 15 11:43:07 2025 +0200 @@ -0,0 +1,409 @@ +/*====================================================================* + - Copyright (C) 2001 Leptonica. All rights reserved. + - + - Redistribution and use in source and binary forms, with or without + - modification, are permitted provided that the following conditions + - are met: + - 1. Redistributions of source code must retain the above copyright + - notice, this list of conditions and the following disclaimer. + - 2. Redistributions in binary form must reproduce the above + - copyright notice, this list of conditions and the following + - disclaimer in the documentation and/or other materials + - provided with the distribution. + - + - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY + - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *====================================================================*/ + +/*! + * \file pixtiling.c + * <pre> + * + * PIXTILING *pixTilingCreate() + * void *pixTilingDestroy() + * l_int32 pixTilingGetCount() + * l_int32 pixTilingGetSize() + * PIX *pixTilingGetTile() + * l_int32 pixTilingNoStripOnPaint() + * l_int32 pixTilingPaintTile() + * + * This provides a simple way to split an image into tiles + * and to perform operations independently on each tile. + * + * The tile created with pixTilingGetTile() can have pixels in + * adjacent tiles for computation. The number of extra pixels + * on each side of the tile is given by an 'overlap' parameter + * to pixTilingCreate(). For tiles at the boundary of + * the input image, quasi-overlap pixels are created by reflection + * symmetry into the tile. + * + * Here's a typical intended usage. Suppose you want to parallelize + * the operation on an image, by operating on tiles. For each + * tile, you want to generate an in-place image result at the same + * resolution. Suppose you choose a one-dimensional vertical tiling, + * where the desired tile width is 256 pixels and the overlap is + * 30 pixels on left and right sides: + * + * PIX *pixd = pixCreateTemplate(pixs); // output + * PIXTILING *pt = pixTilingCreate(pixs, 0, 1, 256, 30, 0); + * pixTilingGetCount(pt, &nx, NULL); + * for (j = 0; j < nx; j++) { + * PIX *pixt = pixTilingGetTile(pt, 0, j); + * SomeInPlaceOperation(pixt, 30, 0, ...); + * pixTilingPaintTile(pixd, 0, j, pixt, pt); + * pixDestroy(&pixt); + * } + * + * In this example, note the following: + * ~ The unspecfified in-place operation could instead generate + * a new pix. If this is done, the resulting pix must be the + * same size as pixt, because pixTilingPaintTile() makes that + * assumption, removing the overlap pixels before painting + * into the destination. + * ~ The 'overlap' parameters have been included in your function, + * to indicate which pixels are not in the exterior overlap region. + * You will need to change only pixels that are not in the overlap + * region, because those are the pixels that will be painted + * into the destination. + * ~ For tiles on the outside of the image, mirrored pixels are + * added to substitute for the overlap that is added to interior + * tiles. This allows you to implement your function without + * reference to which tile it is; no special coding is necessary + * for pixels that are near the image boundary. + * ~ The tiles are labeled by (i, j) = (row, column), + * and in this example there is one row and nx columns. + * </pre> + */ + +#ifdef HAVE_CONFIG_H +#include <config_auto.h> +#endif /* HAVE_CONFIG_H */ + +#include "allheaders.h" +#include "pix_internal.h" + +/*! + * \brief pixTilingCreate() + * + * \param[in] pixs pix to be tiled; any depth; colormap OK + * \param[in] nx number of tiles across image + * \param[in] ny number of tiles down image + * \param[in] w desired width of each tile + * \param[in] h desired height of each tile + * \param[in] xoverlap overlap into neighboring tiles on each side + * \param[in] yoverlap overlap into neighboring tiles above and below + * \return pixtiling, or NULL on error + * + * <pre> + * Notes: + * (1) We put a clone of pixs in the PixTiling. + * (2) The input to pixTilingCreate() for horizontal tiling can be + * either the number of tiles across the image or the approximate + * width of the tiles. If the latter, the actual width will be + * determined by making all tiles but the last of equal width, and + * making the last as close to the others as possible. The same + * consideration is applied independently to the vertical tiling. + * To specify tile width, set nx = 0; to specify the number of + * tiles horizontally across the image, set w = 0. + * (3) If pixs is to be tiled in one-dimensional strips, use ny = 1 for + * vertical strips and nx = 1 for horizontal strips. + * (4) The overlap must not be larger than the width or height of + * the leftmost or topmost tile(s). + * </pre> + */ +PIXTILING * +pixTilingCreate(PIX *pixs, + l_int32 nx, + l_int32 ny, + l_int32 w, + l_int32 h, + l_int32 xoverlap, + l_int32 yoverlap) +{ +l_int32 width, height; +PIXTILING *pt; + + if (!pixs) + return (PIXTILING *)ERROR_PTR("pixs not defined", __func__, NULL); + if (nx < 1 && w < 1) + return (PIXTILING *)ERROR_PTR("invalid width spec", __func__, NULL); + if (ny < 1 && h < 1) + return (PIXTILING *)ERROR_PTR("invalid height spec", __func__, NULL); + + /* Find the tile width and number of tiles. All tiles except the + * rightmost ones have the same width. The width of the + * rightmost ones are at least the width of the others and + * less than twice that width. Ditto for tile height. */ + pixGetDimensions(pixs, &width, &height, NULL); + if (nx == 0) + nx = L_MAX(1, width / w); + w = width / nx; /* possibly reset */ + if (ny == 0) + ny = L_MAX(1, height / h); + h = height / ny; /* possibly reset */ + if (xoverlap > w || yoverlap > h) { + L_INFO("tile width = %d, tile height = %d\n", __func__, w, h); + return (PIXTILING *)ERROR_PTR("overlap too large", __func__, NULL); + } + + pt = (PIXTILING *)LEPT_CALLOC(1, sizeof(PIXTILING)); + pt->pix = pixClone(pixs); + pt->xoverlap = xoverlap; + pt->yoverlap = yoverlap; + pt->nx = nx; + pt->ny = ny; + pt->w = w; + pt->h = h; + pt->strip = TRUE; + return pt; +} + + +/*! + * \brief pixTilingDestroy() + * + * \param[in,out] ppt will be set to null before returning + * \return void + */ +void +pixTilingDestroy(PIXTILING **ppt) +{ +PIXTILING *pt; + + if (ppt == NULL) { + L_WARNING("ptr address is null!\n", __func__); + return; + } + + if ((pt = *ppt) == NULL) + return; + + pixDestroy(&pt->pix); + LEPT_FREE(pt); + *ppt = NULL; +} + + +/*! + * \brief pixTilingGetCount() + * + * \param[in] pt pixtiling + * \param[out] pnx [optional] nx; can be null + * \param[out] pny [optional] ny; can be null + * \return 0 if OK, 1 on error + */ +l_ok +pixTilingGetCount(PIXTILING *pt, + l_int32 *pnx, + l_int32 *pny) +{ + if (!pt) + return ERROR_INT("pt not defined", __func__, 1); + if (pnx) *pnx = pt->nx; + if (pny) *pny = pt->ny; + return 0; +} + + +/*! + * \brief pixTilingGetSize() + * + * \param[in] pt pixtiling + * \param[out] pw [optional] tile width; can be null + * \param[out] ph [optional] tile height; can be null + * \return 0 if OK, 1 on error + */ +l_ok +pixTilingGetSize(PIXTILING *pt, + l_int32 *pw, + l_int32 *ph) +{ + if (!pt) + return ERROR_INT("pt not defined", __func__, 1); + if (pw) *pw = pt->w; + if (ph) *ph = pt->h; + return 0; +} + + +/*! + * \brief pixTilingGetTile() + * + * \param[in] pt pixtiling + * \param[in] i tile row index + * \param[in] j tile column index + * \return pixd tile with appropriate boundary (overlap) pixels added, + * or NULL on error + */ +PIX * +pixTilingGetTile(PIXTILING *pt, + l_int32 i, + l_int32 j) +{ +l_int32 wpix, hpix, wt, ht, nx, ny; +l_int32 xoverlap, yoverlap, wtlast, htlast; +l_int32 left, top, xtraleft, xtraright, xtratop, xtrabot, width, height; +BOX *box; +PIX *pixs, *pixt, *pixd; + + if (!pt) + return (PIX *)ERROR_PTR("pt not defined", __func__, NULL); + if ((pixs = pt->pix) == NULL) + return (PIX *)ERROR_PTR("pix not found", __func__, NULL); + pixTilingGetCount(pt, &nx, &ny); + if (i < 0 || i >= ny) + return (PIX *)ERROR_PTR("invalid row index i", __func__, NULL); + if (j < 0 || j >= nx) + return (PIX *)ERROR_PTR("invalid column index j", __func__, NULL); + + /* Grab the tile with as much overlap as exists within the + * input pix. First, compute the (left, top) coordinates. */ + pixGetDimensions(pixs, &wpix, &hpix, NULL); + pixTilingGetSize(pt, &wt, &ht); + xoverlap = pt->xoverlap; + yoverlap = pt->yoverlap; + wtlast = wpix - wt * (nx - 1); + htlast = hpix - ht * (ny - 1); + left = L_MAX(0, j * wt - xoverlap); + top = L_MAX(0, i * ht - yoverlap); + + /* Get the width and height of the tile, including whatever + * overlap is available. */ + if (nx == 1) + width = wpix; + else if (j == 0) + width = wt + xoverlap; + else if (j == nx - 1) + width = wtlast + xoverlap; + else + width = wt + 2 * xoverlap; + + if (ny == 1) + height = hpix; + else if (i == 0) + height = ht + yoverlap; + else if (i == ny - 1) + height = htlast + yoverlap; + else + height = ht + 2 * yoverlap; + box = boxCreate(left, top, width, height); + pixt = pixClipRectangle(pixs, box, NULL); + boxDestroy(&box); + + /* If no overlap, do not add any special case borders */ + if (xoverlap == 0 && yoverlap == 0) + return pixt; + + /* Add overlap as a mirrored border, in the 8 special cases where + * the tile touches the border of the input pix. The xtratop (etc) + * parameters are required where the tile is either full width + * or full height. */ + xtratop = xtrabot = xtraleft = xtraright = 0; + if (nx == 1) + xtraleft = xtraright = xoverlap; + if (ny == 1) + xtratop = xtrabot = yoverlap; + if (i == 0 && j == 0) + pixd = pixAddMirroredBorder(pixt, xoverlap, xtraright, + yoverlap, xtrabot); + else if (i == 0 && j == nx - 1) + pixd = pixAddMirroredBorder(pixt, xtraleft, xoverlap, + yoverlap, xtrabot); + else if (i == ny - 1 && j == 0) + pixd = pixAddMirroredBorder(pixt, xoverlap, xtraright, + xtratop, yoverlap); + else if (i == ny - 1 && j == nx - 1) + pixd = pixAddMirroredBorder(pixt, xtraleft, xoverlap, + xtratop, yoverlap); + else if (i == 0) + pixd = pixAddMirroredBorder(pixt, 0, 0, yoverlap, xtrabot); + else if (i == ny - 1) + pixd = pixAddMirroredBorder(pixt, 0, 0, xtratop, yoverlap); + else if (j == 0) + pixd = pixAddMirroredBorder(pixt, xoverlap, xtraright, 0, 0); + else if (j == nx - 1) + pixd = pixAddMirroredBorder(pixt, xtraleft, xoverlap, 0, 0); + else + pixd = pixClone(pixt); + pixDestroy(&pixt); + + return pixd; +} + + +/*! + * \brief pixTilingNoStripOnPaint() + * + * \param[in] pt pixtiling + * \return 0 if OK, 1 on error + * + * <pre> + * Notes: + * (1) The default for paint is to strip out the overlap pixels + * that are added by pixTilingGetTile(). However, some + * operations will generate an image with these pixels + * stripped off. This tells the paint operation not + * to strip the added boundary pixels when painting. + * </pre> + */ +l_ok +pixTilingNoStripOnPaint(PIXTILING *pt) +{ + if (!pt) + return ERROR_INT("pt not defined", __func__, 1); + pt->strip = FALSE; + return 0; +} + + +/*! + * \brief pixTilingPaintTile() + * + * \param[in] pixd dest: paint tile onto this, without overlap + * \param[in] i tile row index + * \param[in] j tile column index + * \param[in] pixs source: tile to be painted from + * \param[in] pt pixtiling struct + * \return 0 if OK, 1 on error + */ +l_ok +pixTilingPaintTile(PIX *pixd, + l_int32 i, + l_int32 j, + PIX *pixs, + PIXTILING *pt) +{ +l_int32 w, h; + + if (!pixd) + return ERROR_INT("pixd not defined", __func__, 1); + if (!pixs) + return ERROR_INT("pixs not defined", __func__, 1); + if (!pt) + return ERROR_INT("pt not defined", __func__, 1); + if (i < 0 || i >= pt->ny) + return ERROR_INT("invalid row index i", __func__, 1); + if (j < 0 || j >= pt->nx) + return ERROR_INT("invalid column index j", __func__, 1); + + /* Strip added border pixels off if requested */ + pixGetDimensions(pixs, &w, &h, NULL); + if (pt->strip == TRUE) { + pixRasterop(pixd, j * pt->w, i * pt->h, + w - 2 * pt->xoverlap, h - 2 * pt->yoverlap, PIX_SRC, + pixs, pt->xoverlap, pt->yoverlap); + } else { + pixRasterop(pixd, j * pt->w, i * pt->h, w, h, PIX_SRC, pixs, 0, 0); + } + + return 0; +}
