Mercurial > hgrepos > Python2 > PyMuPDF
comparison 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 |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 /*====================================================================* | |
| 2 - Copyright (C) 2001 Leptonica. All rights reserved. | |
| 3 - | |
| 4 - Redistribution and use in source and binary forms, with or without | |
| 5 - modification, are permitted provided that the following conditions | |
| 6 - are met: | |
| 7 - 1. Redistributions of source code must retain the above copyright | |
| 8 - notice, this list of conditions and the following disclaimer. | |
| 9 - 2. Redistributions in binary form must reproduce the above | |
| 10 - copyright notice, this list of conditions and the following | |
| 11 - disclaimer in the documentation and/or other materials | |
| 12 - provided with the distribution. | |
| 13 - | |
| 14 - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 15 - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 16 - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 17 - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY | |
| 18 - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
| 19 - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
| 20 - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
| 21 - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
| 22 - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
| 23 - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
| 24 - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 25 *====================================================================*/ | |
| 26 | |
| 27 /*! | |
| 28 * \file pixtiling.c | |
| 29 * <pre> | |
| 30 * | |
| 31 * PIXTILING *pixTilingCreate() | |
| 32 * void *pixTilingDestroy() | |
| 33 * l_int32 pixTilingGetCount() | |
| 34 * l_int32 pixTilingGetSize() | |
| 35 * PIX *pixTilingGetTile() | |
| 36 * l_int32 pixTilingNoStripOnPaint() | |
| 37 * l_int32 pixTilingPaintTile() | |
| 38 * | |
| 39 * This provides a simple way to split an image into tiles | |
| 40 * and to perform operations independently on each tile. | |
| 41 * | |
| 42 * The tile created with pixTilingGetTile() can have pixels in | |
| 43 * adjacent tiles for computation. The number of extra pixels | |
| 44 * on each side of the tile is given by an 'overlap' parameter | |
| 45 * to pixTilingCreate(). For tiles at the boundary of | |
| 46 * the input image, quasi-overlap pixels are created by reflection | |
| 47 * symmetry into the tile. | |
| 48 * | |
| 49 * Here's a typical intended usage. Suppose you want to parallelize | |
| 50 * the operation on an image, by operating on tiles. For each | |
| 51 * tile, you want to generate an in-place image result at the same | |
| 52 * resolution. Suppose you choose a one-dimensional vertical tiling, | |
| 53 * where the desired tile width is 256 pixels and the overlap is | |
| 54 * 30 pixels on left and right sides: | |
| 55 * | |
| 56 * PIX *pixd = pixCreateTemplate(pixs); // output | |
| 57 * PIXTILING *pt = pixTilingCreate(pixs, 0, 1, 256, 30, 0); | |
| 58 * pixTilingGetCount(pt, &nx, NULL); | |
| 59 * for (j = 0; j < nx; j++) { | |
| 60 * PIX *pixt = pixTilingGetTile(pt, 0, j); | |
| 61 * SomeInPlaceOperation(pixt, 30, 0, ...); | |
| 62 * pixTilingPaintTile(pixd, 0, j, pixt, pt); | |
| 63 * pixDestroy(&pixt); | |
| 64 * } | |
| 65 * | |
| 66 * In this example, note the following: | |
| 67 * ~ The unspecfified in-place operation could instead generate | |
| 68 * a new pix. If this is done, the resulting pix must be the | |
| 69 * same size as pixt, because pixTilingPaintTile() makes that | |
| 70 * assumption, removing the overlap pixels before painting | |
| 71 * into the destination. | |
| 72 * ~ The 'overlap' parameters have been included in your function, | |
| 73 * to indicate which pixels are not in the exterior overlap region. | |
| 74 * You will need to change only pixels that are not in the overlap | |
| 75 * region, because those are the pixels that will be painted | |
| 76 * into the destination. | |
| 77 * ~ For tiles on the outside of the image, mirrored pixels are | |
| 78 * added to substitute for the overlap that is added to interior | |
| 79 * tiles. This allows you to implement your function without | |
| 80 * reference to which tile it is; no special coding is necessary | |
| 81 * for pixels that are near the image boundary. | |
| 82 * ~ The tiles are labeled by (i, j) = (row, column), | |
| 83 * and in this example there is one row and nx columns. | |
| 84 * </pre> | |
| 85 */ | |
| 86 | |
| 87 #ifdef HAVE_CONFIG_H | |
| 88 #include <config_auto.h> | |
| 89 #endif /* HAVE_CONFIG_H */ | |
| 90 | |
| 91 #include "allheaders.h" | |
| 92 #include "pix_internal.h" | |
| 93 | |
| 94 /*! | |
| 95 * \brief pixTilingCreate() | |
| 96 * | |
| 97 * \param[in] pixs pix to be tiled; any depth; colormap OK | |
| 98 * \param[in] nx number of tiles across image | |
| 99 * \param[in] ny number of tiles down image | |
| 100 * \param[in] w desired width of each tile | |
| 101 * \param[in] h desired height of each tile | |
| 102 * \param[in] xoverlap overlap into neighboring tiles on each side | |
| 103 * \param[in] yoverlap overlap into neighboring tiles above and below | |
| 104 * \return pixtiling, or NULL on error | |
| 105 * | |
| 106 * <pre> | |
| 107 * Notes: | |
| 108 * (1) We put a clone of pixs in the PixTiling. | |
| 109 * (2) The input to pixTilingCreate() for horizontal tiling can be | |
| 110 * either the number of tiles across the image or the approximate | |
| 111 * width of the tiles. If the latter, the actual width will be | |
| 112 * determined by making all tiles but the last of equal width, and | |
| 113 * making the last as close to the others as possible. The same | |
| 114 * consideration is applied independently to the vertical tiling. | |
| 115 * To specify tile width, set nx = 0; to specify the number of | |
| 116 * tiles horizontally across the image, set w = 0. | |
| 117 * (3) If pixs is to be tiled in one-dimensional strips, use ny = 1 for | |
| 118 * vertical strips and nx = 1 for horizontal strips. | |
| 119 * (4) The overlap must not be larger than the width or height of | |
| 120 * the leftmost or topmost tile(s). | |
| 121 * </pre> | |
| 122 */ | |
| 123 PIXTILING * | |
| 124 pixTilingCreate(PIX *pixs, | |
| 125 l_int32 nx, | |
| 126 l_int32 ny, | |
| 127 l_int32 w, | |
| 128 l_int32 h, | |
| 129 l_int32 xoverlap, | |
| 130 l_int32 yoverlap) | |
| 131 { | |
| 132 l_int32 width, height; | |
| 133 PIXTILING *pt; | |
| 134 | |
| 135 if (!pixs) | |
| 136 return (PIXTILING *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 137 if (nx < 1 && w < 1) | |
| 138 return (PIXTILING *)ERROR_PTR("invalid width spec", __func__, NULL); | |
| 139 if (ny < 1 && h < 1) | |
| 140 return (PIXTILING *)ERROR_PTR("invalid height spec", __func__, NULL); | |
| 141 | |
| 142 /* Find the tile width and number of tiles. All tiles except the | |
| 143 * rightmost ones have the same width. The width of the | |
| 144 * rightmost ones are at least the width of the others and | |
| 145 * less than twice that width. Ditto for tile height. */ | |
| 146 pixGetDimensions(pixs, &width, &height, NULL); | |
| 147 if (nx == 0) | |
| 148 nx = L_MAX(1, width / w); | |
| 149 w = width / nx; /* possibly reset */ | |
| 150 if (ny == 0) | |
| 151 ny = L_MAX(1, height / h); | |
| 152 h = height / ny; /* possibly reset */ | |
| 153 if (xoverlap > w || yoverlap > h) { | |
| 154 L_INFO("tile width = %d, tile height = %d\n", __func__, w, h); | |
| 155 return (PIXTILING *)ERROR_PTR("overlap too large", __func__, NULL); | |
| 156 } | |
| 157 | |
| 158 pt = (PIXTILING *)LEPT_CALLOC(1, sizeof(PIXTILING)); | |
| 159 pt->pix = pixClone(pixs); | |
| 160 pt->xoverlap = xoverlap; | |
| 161 pt->yoverlap = yoverlap; | |
| 162 pt->nx = nx; | |
| 163 pt->ny = ny; | |
| 164 pt->w = w; | |
| 165 pt->h = h; | |
| 166 pt->strip = TRUE; | |
| 167 return pt; | |
| 168 } | |
| 169 | |
| 170 | |
| 171 /*! | |
| 172 * \brief pixTilingDestroy() | |
| 173 * | |
| 174 * \param[in,out] ppt will be set to null before returning | |
| 175 * \return void | |
| 176 */ | |
| 177 void | |
| 178 pixTilingDestroy(PIXTILING **ppt) | |
| 179 { | |
| 180 PIXTILING *pt; | |
| 181 | |
| 182 if (ppt == NULL) { | |
| 183 L_WARNING("ptr address is null!\n", __func__); | |
| 184 return; | |
| 185 } | |
| 186 | |
| 187 if ((pt = *ppt) == NULL) | |
| 188 return; | |
| 189 | |
| 190 pixDestroy(&pt->pix); | |
| 191 LEPT_FREE(pt); | |
| 192 *ppt = NULL; | |
| 193 } | |
| 194 | |
| 195 | |
| 196 /*! | |
| 197 * \brief pixTilingGetCount() | |
| 198 * | |
| 199 * \param[in] pt pixtiling | |
| 200 * \param[out] pnx [optional] nx; can be null | |
| 201 * \param[out] pny [optional] ny; can be null | |
| 202 * \return 0 if OK, 1 on error | |
| 203 */ | |
| 204 l_ok | |
| 205 pixTilingGetCount(PIXTILING *pt, | |
| 206 l_int32 *pnx, | |
| 207 l_int32 *pny) | |
| 208 { | |
| 209 if (!pt) | |
| 210 return ERROR_INT("pt not defined", __func__, 1); | |
| 211 if (pnx) *pnx = pt->nx; | |
| 212 if (pny) *pny = pt->ny; | |
| 213 return 0; | |
| 214 } | |
| 215 | |
| 216 | |
| 217 /*! | |
| 218 * \brief pixTilingGetSize() | |
| 219 * | |
| 220 * \param[in] pt pixtiling | |
| 221 * \param[out] pw [optional] tile width; can be null | |
| 222 * \param[out] ph [optional] tile height; can be null | |
| 223 * \return 0 if OK, 1 on error | |
| 224 */ | |
| 225 l_ok | |
| 226 pixTilingGetSize(PIXTILING *pt, | |
| 227 l_int32 *pw, | |
| 228 l_int32 *ph) | |
| 229 { | |
| 230 if (!pt) | |
| 231 return ERROR_INT("pt not defined", __func__, 1); | |
| 232 if (pw) *pw = pt->w; | |
| 233 if (ph) *ph = pt->h; | |
| 234 return 0; | |
| 235 } | |
| 236 | |
| 237 | |
| 238 /*! | |
| 239 * \brief pixTilingGetTile() | |
| 240 * | |
| 241 * \param[in] pt pixtiling | |
| 242 * \param[in] i tile row index | |
| 243 * \param[in] j tile column index | |
| 244 * \return pixd tile with appropriate boundary (overlap) pixels added, | |
| 245 * or NULL on error | |
| 246 */ | |
| 247 PIX * | |
| 248 pixTilingGetTile(PIXTILING *pt, | |
| 249 l_int32 i, | |
| 250 l_int32 j) | |
| 251 { | |
| 252 l_int32 wpix, hpix, wt, ht, nx, ny; | |
| 253 l_int32 xoverlap, yoverlap, wtlast, htlast; | |
| 254 l_int32 left, top, xtraleft, xtraright, xtratop, xtrabot, width, height; | |
| 255 BOX *box; | |
| 256 PIX *pixs, *pixt, *pixd; | |
| 257 | |
| 258 if (!pt) | |
| 259 return (PIX *)ERROR_PTR("pt not defined", __func__, NULL); | |
| 260 if ((pixs = pt->pix) == NULL) | |
| 261 return (PIX *)ERROR_PTR("pix not found", __func__, NULL); | |
| 262 pixTilingGetCount(pt, &nx, &ny); | |
| 263 if (i < 0 || i >= ny) | |
| 264 return (PIX *)ERROR_PTR("invalid row index i", __func__, NULL); | |
| 265 if (j < 0 || j >= nx) | |
| 266 return (PIX *)ERROR_PTR("invalid column index j", __func__, NULL); | |
| 267 | |
| 268 /* Grab the tile with as much overlap as exists within the | |
| 269 * input pix. First, compute the (left, top) coordinates. */ | |
| 270 pixGetDimensions(pixs, &wpix, &hpix, NULL); | |
| 271 pixTilingGetSize(pt, &wt, &ht); | |
| 272 xoverlap = pt->xoverlap; | |
| 273 yoverlap = pt->yoverlap; | |
| 274 wtlast = wpix - wt * (nx - 1); | |
| 275 htlast = hpix - ht * (ny - 1); | |
| 276 left = L_MAX(0, j * wt - xoverlap); | |
| 277 top = L_MAX(0, i * ht - yoverlap); | |
| 278 | |
| 279 /* Get the width and height of the tile, including whatever | |
| 280 * overlap is available. */ | |
| 281 if (nx == 1) | |
| 282 width = wpix; | |
| 283 else if (j == 0) | |
| 284 width = wt + xoverlap; | |
| 285 else if (j == nx - 1) | |
| 286 width = wtlast + xoverlap; | |
| 287 else | |
| 288 width = wt + 2 * xoverlap; | |
| 289 | |
| 290 if (ny == 1) | |
| 291 height = hpix; | |
| 292 else if (i == 0) | |
| 293 height = ht + yoverlap; | |
| 294 else if (i == ny - 1) | |
| 295 height = htlast + yoverlap; | |
| 296 else | |
| 297 height = ht + 2 * yoverlap; | |
| 298 box = boxCreate(left, top, width, height); | |
| 299 pixt = pixClipRectangle(pixs, box, NULL); | |
| 300 boxDestroy(&box); | |
| 301 | |
| 302 /* If no overlap, do not add any special case borders */ | |
| 303 if (xoverlap == 0 && yoverlap == 0) | |
| 304 return pixt; | |
| 305 | |
| 306 /* Add overlap as a mirrored border, in the 8 special cases where | |
| 307 * the tile touches the border of the input pix. The xtratop (etc) | |
| 308 * parameters are required where the tile is either full width | |
| 309 * or full height. */ | |
| 310 xtratop = xtrabot = xtraleft = xtraright = 0; | |
| 311 if (nx == 1) | |
| 312 xtraleft = xtraright = xoverlap; | |
| 313 if (ny == 1) | |
| 314 xtratop = xtrabot = yoverlap; | |
| 315 if (i == 0 && j == 0) | |
| 316 pixd = pixAddMirroredBorder(pixt, xoverlap, xtraright, | |
| 317 yoverlap, xtrabot); | |
| 318 else if (i == 0 && j == nx - 1) | |
| 319 pixd = pixAddMirroredBorder(pixt, xtraleft, xoverlap, | |
| 320 yoverlap, xtrabot); | |
| 321 else if (i == ny - 1 && j == 0) | |
| 322 pixd = pixAddMirroredBorder(pixt, xoverlap, xtraright, | |
| 323 xtratop, yoverlap); | |
| 324 else if (i == ny - 1 && j == nx - 1) | |
| 325 pixd = pixAddMirroredBorder(pixt, xtraleft, xoverlap, | |
| 326 xtratop, yoverlap); | |
| 327 else if (i == 0) | |
| 328 pixd = pixAddMirroredBorder(pixt, 0, 0, yoverlap, xtrabot); | |
| 329 else if (i == ny - 1) | |
| 330 pixd = pixAddMirroredBorder(pixt, 0, 0, xtratop, yoverlap); | |
| 331 else if (j == 0) | |
| 332 pixd = pixAddMirroredBorder(pixt, xoverlap, xtraright, 0, 0); | |
| 333 else if (j == nx - 1) | |
| 334 pixd = pixAddMirroredBorder(pixt, xtraleft, xoverlap, 0, 0); | |
| 335 else | |
| 336 pixd = pixClone(pixt); | |
| 337 pixDestroy(&pixt); | |
| 338 | |
| 339 return pixd; | |
| 340 } | |
| 341 | |
| 342 | |
| 343 /*! | |
| 344 * \brief pixTilingNoStripOnPaint() | |
| 345 * | |
| 346 * \param[in] pt pixtiling | |
| 347 * \return 0 if OK, 1 on error | |
| 348 * | |
| 349 * <pre> | |
| 350 * Notes: | |
| 351 * (1) The default for paint is to strip out the overlap pixels | |
| 352 * that are added by pixTilingGetTile(). However, some | |
| 353 * operations will generate an image with these pixels | |
| 354 * stripped off. This tells the paint operation not | |
| 355 * to strip the added boundary pixels when painting. | |
| 356 * </pre> | |
| 357 */ | |
| 358 l_ok | |
| 359 pixTilingNoStripOnPaint(PIXTILING *pt) | |
| 360 { | |
| 361 if (!pt) | |
| 362 return ERROR_INT("pt not defined", __func__, 1); | |
| 363 pt->strip = FALSE; | |
| 364 return 0; | |
| 365 } | |
| 366 | |
| 367 | |
| 368 /*! | |
| 369 * \brief pixTilingPaintTile() | |
| 370 * | |
| 371 * \param[in] pixd dest: paint tile onto this, without overlap | |
| 372 * \param[in] i tile row index | |
| 373 * \param[in] j tile column index | |
| 374 * \param[in] pixs source: tile to be painted from | |
| 375 * \param[in] pt pixtiling struct | |
| 376 * \return 0 if OK, 1 on error | |
| 377 */ | |
| 378 l_ok | |
| 379 pixTilingPaintTile(PIX *pixd, | |
| 380 l_int32 i, | |
| 381 l_int32 j, | |
| 382 PIX *pixs, | |
| 383 PIXTILING *pt) | |
| 384 { | |
| 385 l_int32 w, h; | |
| 386 | |
| 387 if (!pixd) | |
| 388 return ERROR_INT("pixd not defined", __func__, 1); | |
| 389 if (!pixs) | |
| 390 return ERROR_INT("pixs not defined", __func__, 1); | |
| 391 if (!pt) | |
| 392 return ERROR_INT("pt not defined", __func__, 1); | |
| 393 if (i < 0 || i >= pt->ny) | |
| 394 return ERROR_INT("invalid row index i", __func__, 1); | |
| 395 if (j < 0 || j >= pt->nx) | |
| 396 return ERROR_INT("invalid column index j", __func__, 1); | |
| 397 | |
| 398 /* Strip added border pixels off if requested */ | |
| 399 pixGetDimensions(pixs, &w, &h, NULL); | |
| 400 if (pt->strip == TRUE) { | |
| 401 pixRasterop(pixd, j * pt->w, i * pt->h, | |
| 402 w - 2 * pt->xoverlap, h - 2 * pt->yoverlap, PIX_SRC, | |
| 403 pixs, pt->xoverlap, pt->yoverlap); | |
| 404 } else { | |
| 405 pixRasterop(pixd, j * pt->w, i * pt->h, w, h, PIX_SRC, pixs, 0, 0); | |
| 406 } | |
| 407 | |
| 408 return 0; | |
| 409 } |
