Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/leptonica/src/binreduce.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 binreduce.c | |
| 29 * <pre> | |
| 30 * | |
| 31 * Subsampled 2x reduction | |
| 32 * PIX *pixReduceBinary2() | |
| 33 * | |
| 34 * Rank filtered 2x reductions | |
| 35 * PIX *pixReduceRankBinaryCascade() | |
| 36 * PIX *pixReduceRankBinary2() | |
| 37 * | |
| 38 * Permutation table for 2x rank binary reduction | |
| 39 * l_uint8 *makeSubsampleTab2x(void) | |
| 40 * </pre> | |
| 41 */ | |
| 42 | |
| 43 #ifdef HAVE_CONFIG_H | |
| 44 #include <config_auto.h> | |
| 45 #endif /* HAVE_CONFIG_H */ | |
| 46 | |
| 47 #include <string.h> | |
| 48 #include "allheaders.h" | |
| 49 | |
| 50 /*------------------------------------------------------------------* | |
| 51 * Subsampled reduction * | |
| 52 *------------------------------------------------------------------*/ | |
| 53 /*! | |
| 54 * \brief pixReduceBinary2() | |
| 55 * | |
| 56 * \param[in] pixs | |
| 57 * \param[in] intab [optional]; if null, a table is made here | |
| 58 * and destroyed before exit | |
| 59 * \return pixd 2x subsampled, or NULL on error | |
| 60 * | |
| 61 * <pre> | |
| 62 * Notes: | |
| 63 * (1) After folding, the data is in bytes 0 and 2 of the word, | |
| 64 * and the bits in each byte are in the following order | |
| 65 * (with 0 being the leftmost originating pair and 7 being | |
| 66 * the rightmost originating pair): | |
| 67 * 0 4 1 5 2 6 3 7 | |
| 68 * These need to be permuted to | |
| 69 * 0 1 2 3 4 5 6 7 | |
| 70 * which is done with an 8-bit table generated by makeSubsampleTab2x(). | |
| 71 * </pre> | |
| 72 */ | |
| 73 PIX * | |
| 74 pixReduceBinary2(PIX *pixs, | |
| 75 l_uint8 *intab) | |
| 76 { | |
| 77 l_uint8 byte0, byte1; | |
| 78 l_uint8 *tab; | |
| 79 l_uint16 shortd; | |
| 80 l_int32 i, id, j, ws, hs, wpls, wpld, wplsi; | |
| 81 l_uint32 word; | |
| 82 l_uint32 *datas, *datad, *lines, *lined; | |
| 83 PIX *pixd; | |
| 84 | |
| 85 if (!pixs || pixGetDepth(pixs) != 1) | |
| 86 return (PIX *)ERROR_PTR("pixs undefined or not 1 bpp", __func__, NULL); | |
| 87 | |
| 88 pixGetDimensions(pixs, &ws, &hs, NULL); | |
| 89 if (hs <= 1) | |
| 90 return (PIX *)ERROR_PTR("hs must be at least 2", __func__, NULL); | |
| 91 wpls = pixGetWpl(pixs); | |
| 92 datas = pixGetData(pixs); | |
| 93 pixSetPadBits(pixs, 0); | |
| 94 | |
| 95 if ((pixd = pixCreate(ws / 2, hs / 2, 1)) == NULL) | |
| 96 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 97 pixCopyResolution(pixd, pixs); | |
| 98 pixScaleResolution(pixd, 0.5, 0.5); | |
| 99 wpld = pixGetWpl(pixd); | |
| 100 datad = pixGetData(pixd); | |
| 101 | |
| 102 tab = (intab) ? intab : makeSubsampleTab2x(); | |
| 103 if (!tab) { | |
| 104 pixDestroy(&pixd); | |
| 105 return (PIX *)ERROR_PTR("tab not made", __func__, NULL); | |
| 106 } | |
| 107 | |
| 108 /* e.g., if ws = 65: wd = 32, wpls = 3, wpld = 1 --> trouble */ | |
| 109 wplsi = L_MIN(wpls, 2 * wpld); /* iterate over this number of words */ | |
| 110 | |
| 111 for (i = 0, id = 0; i < hs - 1; i += 2, id++) { | |
| 112 lines = datas + i * wpls; | |
| 113 lined = datad + id * wpld; | |
| 114 for (j = 0; j < wplsi; j++) { | |
| 115 word = *(lines + j); | |
| 116 word = word & 0xaaaaaaaa; /* mask */ | |
| 117 word = word | (word << 7); /* fold; data in bytes 0 & 2 */ | |
| 118 byte0 = word >> 24; | |
| 119 byte1 = (word >> 8) & 0xff; | |
| 120 shortd = (tab[byte0] << 8) | tab[byte1]; | |
| 121 SET_DATA_TWO_BYTES(lined, j, shortd); | |
| 122 } | |
| 123 } | |
| 124 | |
| 125 if (!intab) LEPT_FREE(tab); | |
| 126 return pixd; | |
| 127 } | |
| 128 | |
| 129 | |
| 130 /*------------------------------------------------------------------* | |
| 131 * Rank filtered binary reductions * | |
| 132 *------------------------------------------------------------------*/ | |
| 133 /*! | |
| 134 * \brief pixReduceRankBinaryCascade() | |
| 135 * | |
| 136 * \param[in] pixs 1 bpp | |
| 137 * \param[in] level1 threshold, in the set {0, 1, 2, 3, 4} | |
| 138 * \param[in] level2 threshold, in the set {0, 1, 2, 3, 4} | |
| 139 * \param[in] level3 threshold, in the set {0, 1, 2, 3, 4} | |
| 140 * \param[in] level4 threshold, in the set {0, 1, 2, 3, 4} | |
| 141 * \return pixd, or NULL on error | |
| 142 * | |
| 143 * <pre> | |
| 144 * Notes: | |
| 145 * (1) This performs up to four cascaded 2x rank reductions. | |
| 146 * (2) Use level = 0 to truncate the cascade. | |
| 147 * </pre> | |
| 148 */ | |
| 149 PIX * | |
| 150 pixReduceRankBinaryCascade(PIX *pixs, | |
| 151 l_int32 level1, | |
| 152 l_int32 level2, | |
| 153 l_int32 level3, | |
| 154 l_int32 level4) | |
| 155 { | |
| 156 PIX *pix1, *pix2, *pix3, *pix4; | |
| 157 l_uint8 *tab; | |
| 158 | |
| 159 if (!pixs) | |
| 160 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 161 if (pixGetDepth(pixs) != 1) | |
| 162 return (PIX *)ERROR_PTR("pixs must be binary", __func__, NULL); | |
| 163 if (level1 > 4 || level2 > 4 || level3 > 4 || level4 > 4) | |
| 164 return (PIX *)ERROR_PTR("levels must not exceed 4", __func__, NULL); | |
| 165 | |
| 166 if (level1 <= 0) { | |
| 167 L_WARNING("no reduction because level1 not > 0\n", __func__); | |
| 168 return pixCopy(NULL, pixs); | |
| 169 } | |
| 170 | |
| 171 if ((tab = makeSubsampleTab2x()) == NULL) | |
| 172 return (PIX *)ERROR_PTR("tab not made", __func__, NULL); | |
| 173 | |
| 174 pix1 = pixReduceRankBinary2(pixs, level1, tab); | |
| 175 if (level2 <= 0) { | |
| 176 LEPT_FREE(tab); | |
| 177 return pix1; | |
| 178 } | |
| 179 | |
| 180 pix2 = pixReduceRankBinary2(pix1, level2, tab); | |
| 181 pixDestroy(&pix1); | |
| 182 if (level3 <= 0) { | |
| 183 LEPT_FREE(tab); | |
| 184 return pix2; | |
| 185 } | |
| 186 | |
| 187 pix3 = pixReduceRankBinary2(pix2, level3, tab); | |
| 188 pixDestroy(&pix2); | |
| 189 if (level4 <= 0) { | |
| 190 LEPT_FREE(tab); | |
| 191 return pix3; | |
| 192 } | |
| 193 | |
| 194 pix4 = pixReduceRankBinary2(pix3, level4, tab); | |
| 195 pixDestroy(&pix3); | |
| 196 LEPT_FREE(tab); | |
| 197 return pix4; | |
| 198 } | |
| 199 | |
| 200 | |
| 201 /*! | |
| 202 * \brief pixReduceRankBinary2() | |
| 203 * | |
| 204 * \param[in] pixs 1 bpp | |
| 205 * \param[in] level rank threshold: 1, 2, 3, 4 | |
| 206 * \param[in] intab [optional]; if null, a table is made here | |
| 207 * and destroyed before exit | |
| 208 * \return pixd 1 bpp, 2x rank threshold reduced, or NULL on error | |
| 209 * | |
| 210 * <pre> | |
| 211 * Notes: | |
| 212 * (1) pixd is downscaled by 2x from pixs. | |
| 213 * (2) The rank threshold specifies the minimum number of ON | |
| 214 * pixels in each 2x2 region of pixs that are required to | |
| 215 * set the corresponding pixel ON in pixd. | |
| 216 * (3) Rank filtering is done to the UL corner of each 2x2 pixel block, | |
| 217 * using only logical operations. Then these pixels are chosen | |
| 218 * in the 2x subsampling process, subsampled, as described | |
| 219 * above in pixReduceBinary2(). | |
| 220 * </pre> | |
| 221 */ | |
| 222 PIX * | |
| 223 pixReduceRankBinary2(PIX *pixs, | |
| 224 l_int32 level, | |
| 225 l_uint8 *intab) | |
| 226 { | |
| 227 l_uint8 byte0, byte1; | |
| 228 l_uint8 *tab; | |
| 229 l_uint16 shortd; | |
| 230 l_int32 i, id, j, ws, hs, wpls, wpld, wplsi; | |
| 231 l_uint32 word1, word2, word3, word4; | |
| 232 l_uint32 *datas, *datad, *lines, *lined; | |
| 233 PIX *pixd; | |
| 234 | |
| 235 if (!pixs) | |
| 236 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 237 | |
| 238 if (pixGetDepth(pixs) != 1) | |
| 239 return (PIX *)ERROR_PTR("pixs not binary", __func__, NULL); | |
| 240 if (level < 1 || level > 4) | |
| 241 return (PIX *)ERROR_PTR("level must be in set {1,2,3,4}", | |
| 242 __func__, NULL); | |
| 243 | |
| 244 pixGetDimensions(pixs, &ws, &hs, NULL); | |
| 245 if (hs <= 1) | |
| 246 return (PIX *)ERROR_PTR("hs must be at least 2", __func__, NULL); | |
| 247 wpls = pixGetWpl(pixs); | |
| 248 datas = pixGetData(pixs); | |
| 249 pixSetPadBits(pixs, 0); | |
| 250 | |
| 251 if ((pixd = pixCreate(ws / 2, hs / 2, 1)) == NULL) | |
| 252 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 253 pixCopyResolution(pixd, pixs); | |
| 254 pixScaleResolution(pixd, 0.5, 0.5); | |
| 255 wpld = pixGetWpl(pixd); | |
| 256 datad = pixGetData(pixd); | |
| 257 | |
| 258 tab = (intab) ? intab : makeSubsampleTab2x(); | |
| 259 if (!tab) { | |
| 260 pixDestroy(&pixd); | |
| 261 return (PIX *)ERROR_PTR("tab not made", __func__, NULL); | |
| 262 } | |
| 263 | |
| 264 /* e.g., if ws = 65: wd = 32, wpls = 3, wpld = 1 --> trouble */ | |
| 265 wplsi = L_MIN(wpls, 2 * wpld); /* iterate over this number of words */ | |
| 266 | |
| 267 switch (level) | |
| 268 { | |
| 269 | |
| 270 case 1: | |
| 271 for (i = 0, id = 0; i < hs - 1; i += 2, id++) { | |
| 272 lines = datas + i * wpls; | |
| 273 lined = datad + id * wpld; | |
| 274 for (j = 0; j < wplsi; j++) { | |
| 275 word1 = *(lines + j); | |
| 276 word2 = *(lines + wpls + j); | |
| 277 | |
| 278 /* OR/OR */ | |
| 279 word2 = word1 | word2; | |
| 280 word2 = word2 | (word2 << 1); | |
| 281 | |
| 282 word2 = word2 & 0xaaaaaaaa; /* mask */ | |
| 283 word1 = word2 | (word2 << 7); /* fold; data in bytes 0 & 2 */ | |
| 284 byte0 = word1 >> 24; | |
| 285 byte1 = (word1 >> 8) & 0xff; | |
| 286 shortd = (tab[byte0] << 8) | tab[byte1]; | |
| 287 SET_DATA_TWO_BYTES(lined, j, shortd); | |
| 288 } | |
| 289 } | |
| 290 break; | |
| 291 | |
| 292 case 2: | |
| 293 for (i = 0, id = 0; i < hs - 1; i += 2, id++) { | |
| 294 lines = datas + i * wpls; | |
| 295 lined = datad + id * wpld; | |
| 296 for (j = 0; j < wplsi; j++) { | |
| 297 word1 = *(lines + j); | |
| 298 word2 = *(lines + wpls + j); | |
| 299 | |
| 300 /* (AND/OR) OR (OR/AND) */ | |
| 301 word3 = word1 & word2; | |
| 302 word3 = word3 | (word3 << 1); | |
| 303 word4 = word1 | word2; | |
| 304 word4 = word4 & (word4 << 1); | |
| 305 word2 = word3 | word4; | |
| 306 | |
| 307 word2 = word2 & 0xaaaaaaaa; /* mask */ | |
| 308 word1 = word2 | (word2 << 7); /* fold; data in bytes 0 & 2 */ | |
| 309 byte0 = word1 >> 24; | |
| 310 byte1 = (word1 >> 8) & 0xff; | |
| 311 shortd = (tab[byte0] << 8) | tab[byte1]; | |
| 312 SET_DATA_TWO_BYTES(lined, j, shortd); | |
| 313 } | |
| 314 } | |
| 315 break; | |
| 316 | |
| 317 case 3: | |
| 318 for (i = 0, id = 0; i < hs - 1; i += 2, id++) { | |
| 319 lines = datas + i * wpls; | |
| 320 lined = datad + id * wpld; | |
| 321 for (j = 0; j < wplsi; j++) { | |
| 322 word1 = *(lines + j); | |
| 323 word2 = *(lines + wpls + j); | |
| 324 | |
| 325 /* (AND/OR) AND (OR/AND) */ | |
| 326 word3 = word1 & word2; | |
| 327 word3 = word3 | (word3 << 1); | |
| 328 word4 = word1 | word2; | |
| 329 word4 = word4 & (word4 << 1); | |
| 330 word2 = word3 & word4; | |
| 331 | |
| 332 word2 = word2 & 0xaaaaaaaa; /* mask */ | |
| 333 word1 = word2 | (word2 << 7); /* fold; data in bytes 0 & 2 */ | |
| 334 byte0 = word1 >> 24; | |
| 335 byte1 = (word1 >> 8) & 0xff; | |
| 336 shortd = (tab[byte0] << 8) | tab[byte1]; | |
| 337 SET_DATA_TWO_BYTES(lined, j, shortd); | |
| 338 } | |
| 339 } | |
| 340 break; | |
| 341 | |
| 342 case 4: | |
| 343 for (i = 0, id = 0; i < hs - 1; i += 2, id++) { | |
| 344 lines = datas + i * wpls; | |
| 345 lined = datad + id * wpld; | |
| 346 for (j = 0; j < wplsi; j++) { | |
| 347 word1 = *(lines + j); | |
| 348 word2 = *(lines + wpls + j); | |
| 349 | |
| 350 /* AND/AND */ | |
| 351 word2 = word1 & word2; | |
| 352 word2 = word2 & (word2 << 1); | |
| 353 | |
| 354 word2 = word2 & 0xaaaaaaaa; /* mask */ | |
| 355 word1 = word2 | (word2 << 7); /* fold; data in bytes 0 & 2 */ | |
| 356 byte0 = word1 >> 24; | |
| 357 byte1 = (word1 >> 8) & 0xff; | |
| 358 shortd = (tab[byte0] << 8) | tab[byte1]; | |
| 359 SET_DATA_TWO_BYTES(lined, j, shortd); | |
| 360 } | |
| 361 } | |
| 362 break; | |
| 363 } | |
| 364 | |
| 365 if (!intab) LEPT_FREE(tab); | |
| 366 return pixd; | |
| 367 } | |
| 368 | |
| 369 | |
| 370 /*! | |
| 371 * \brief makeSubsampleTab2x() | |
| 372 * | |
| 373 * \return tab table of 256 permutations, or NULL on error | |
| 374 * | |
| 375 * <pre> | |
| 376 * Notes: | |
| 377 * Permutation table for 2x rank binary reduction | |
| 378 * This table permutes the bits in a byte, from | |
| 379 * 0 4 1 5 2 6 3 7 | |
| 380 * to | |
| 381 * 0 1 2 3 4 5 6 7 | |
| 382 * </pre> | |
| 383 */ | |
| 384 l_uint8 * | |
| 385 makeSubsampleTab2x(void) | |
| 386 { | |
| 387 l_uint8 *tab; | |
| 388 l_int32 i; | |
| 389 | |
| 390 tab = (l_uint8 *) LEPT_CALLOC(256, sizeof(l_uint8)); | |
| 391 for (i = 0; i < 256; i++) { | |
| 392 tab[i] = ((i & 0x01) ) | /* 7 */ | |
| 393 ((i & 0x04) >> 1) | /* 6 */ | |
| 394 ((i & 0x10) >> 2) | /* 5 */ | |
| 395 ((i & 0x40) >> 3) | /* 4 */ | |
| 396 ((i & 0x02) << 3) | /* 3 */ | |
| 397 ((i & 0x08) << 2) | /* 2 */ | |
| 398 ((i & 0x20) << 1) | /* 1 */ | |
| 399 ((i & 0x80) ); /* 0 */ | |
| 400 } | |
| 401 return tab; | |
| 402 } |
