Mercurial > hgrepos > Python2 > PyMuPDF
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mupdf-source/thirdparty/leptonica/src/binreduce.c Mon Sep 15 11:43:07 2025 +0200 @@ -0,0 +1,402 @@ +/*====================================================================* + - 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 binreduce.c + * <pre> + * + * Subsampled 2x reduction + * PIX *pixReduceBinary2() + * + * Rank filtered 2x reductions + * PIX *pixReduceRankBinaryCascade() + * PIX *pixReduceRankBinary2() + * + * Permutation table for 2x rank binary reduction + * l_uint8 *makeSubsampleTab2x(void) + * </pre> + */ + +#ifdef HAVE_CONFIG_H +#include <config_auto.h> +#endif /* HAVE_CONFIG_H */ + +#include <string.h> +#include "allheaders.h" + +/*------------------------------------------------------------------* + * Subsampled reduction * + *------------------------------------------------------------------*/ +/*! + * \brief pixReduceBinary2() + * + * \param[in] pixs + * \param[in] intab [optional]; if null, a table is made here + * and destroyed before exit + * \return pixd 2x subsampled, or NULL on error + * + * <pre> + * Notes: + * (1) After folding, the data is in bytes 0 and 2 of the word, + * and the bits in each byte are in the following order + * (with 0 being the leftmost originating pair and 7 being + * the rightmost originating pair): + * 0 4 1 5 2 6 3 7 + * These need to be permuted to + * 0 1 2 3 4 5 6 7 + * which is done with an 8-bit table generated by makeSubsampleTab2x(). + * </pre> + */ +PIX * +pixReduceBinary2(PIX *pixs, + l_uint8 *intab) +{ +l_uint8 byte0, byte1; +l_uint8 *tab; +l_uint16 shortd; +l_int32 i, id, j, ws, hs, wpls, wpld, wplsi; +l_uint32 word; +l_uint32 *datas, *datad, *lines, *lined; +PIX *pixd; + + if (!pixs || pixGetDepth(pixs) != 1) + return (PIX *)ERROR_PTR("pixs undefined or not 1 bpp", __func__, NULL); + + pixGetDimensions(pixs, &ws, &hs, NULL); + if (hs <= 1) + return (PIX *)ERROR_PTR("hs must be at least 2", __func__, NULL); + wpls = pixGetWpl(pixs); + datas = pixGetData(pixs); + pixSetPadBits(pixs, 0); + + if ((pixd = pixCreate(ws / 2, hs / 2, 1)) == NULL) + return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); + pixCopyResolution(pixd, pixs); + pixScaleResolution(pixd, 0.5, 0.5); + wpld = pixGetWpl(pixd); + datad = pixGetData(pixd); + + tab = (intab) ? intab : makeSubsampleTab2x(); + if (!tab) { + pixDestroy(&pixd); + return (PIX *)ERROR_PTR("tab not made", __func__, NULL); + } + + /* e.g., if ws = 65: wd = 32, wpls = 3, wpld = 1 --> trouble */ + wplsi = L_MIN(wpls, 2 * wpld); /* iterate over this number of words */ + + for (i = 0, id = 0; i < hs - 1; i += 2, id++) { + lines = datas + i * wpls; + lined = datad + id * wpld; + for (j = 0; j < wplsi; j++) { + word = *(lines + j); + word = word & 0xaaaaaaaa; /* mask */ + word = word | (word << 7); /* fold; data in bytes 0 & 2 */ + byte0 = word >> 24; + byte1 = (word >> 8) & 0xff; + shortd = (tab[byte0] << 8) | tab[byte1]; + SET_DATA_TWO_BYTES(lined, j, shortd); + } + } + + if (!intab) LEPT_FREE(tab); + return pixd; +} + + +/*------------------------------------------------------------------* + * Rank filtered binary reductions * + *------------------------------------------------------------------*/ +/*! + * \brief pixReduceRankBinaryCascade() + * + * \param[in] pixs 1 bpp + * \param[in] level1 threshold, in the set {0, 1, 2, 3, 4} + * \param[in] level2 threshold, in the set {0, 1, 2, 3, 4} + * \param[in] level3 threshold, in the set {0, 1, 2, 3, 4} + * \param[in] level4 threshold, in the set {0, 1, 2, 3, 4} + * \return pixd, or NULL on error + * + * <pre> + * Notes: + * (1) This performs up to four cascaded 2x rank reductions. + * (2) Use level = 0 to truncate the cascade. + * </pre> + */ +PIX * +pixReduceRankBinaryCascade(PIX *pixs, + l_int32 level1, + l_int32 level2, + l_int32 level3, + l_int32 level4) +{ +PIX *pix1, *pix2, *pix3, *pix4; +l_uint8 *tab; + + if (!pixs) + return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); + if (pixGetDepth(pixs) != 1) + return (PIX *)ERROR_PTR("pixs must be binary", __func__, NULL); + if (level1 > 4 || level2 > 4 || level3 > 4 || level4 > 4) + return (PIX *)ERROR_PTR("levels must not exceed 4", __func__, NULL); + + if (level1 <= 0) { + L_WARNING("no reduction because level1 not > 0\n", __func__); + return pixCopy(NULL, pixs); + } + + if ((tab = makeSubsampleTab2x()) == NULL) + return (PIX *)ERROR_PTR("tab not made", __func__, NULL); + + pix1 = pixReduceRankBinary2(pixs, level1, tab); + if (level2 <= 0) { + LEPT_FREE(tab); + return pix1; + } + + pix2 = pixReduceRankBinary2(pix1, level2, tab); + pixDestroy(&pix1); + if (level3 <= 0) { + LEPT_FREE(tab); + return pix2; + } + + pix3 = pixReduceRankBinary2(pix2, level3, tab); + pixDestroy(&pix2); + if (level4 <= 0) { + LEPT_FREE(tab); + return pix3; + } + + pix4 = pixReduceRankBinary2(pix3, level4, tab); + pixDestroy(&pix3); + LEPT_FREE(tab); + return pix4; +} + + +/*! + * \brief pixReduceRankBinary2() + * + * \param[in] pixs 1 bpp + * \param[in] level rank threshold: 1, 2, 3, 4 + * \param[in] intab [optional]; if null, a table is made here + * and destroyed before exit + * \return pixd 1 bpp, 2x rank threshold reduced, or NULL on error + * + * <pre> + * Notes: + * (1) pixd is downscaled by 2x from pixs. + * (2) The rank threshold specifies the minimum number of ON + * pixels in each 2x2 region of pixs that are required to + * set the corresponding pixel ON in pixd. + * (3) Rank filtering is done to the UL corner of each 2x2 pixel block, + * using only logical operations. Then these pixels are chosen + * in the 2x subsampling process, subsampled, as described + * above in pixReduceBinary2(). + * </pre> + */ +PIX * +pixReduceRankBinary2(PIX *pixs, + l_int32 level, + l_uint8 *intab) +{ +l_uint8 byte0, byte1; +l_uint8 *tab; +l_uint16 shortd; +l_int32 i, id, j, ws, hs, wpls, wpld, wplsi; +l_uint32 word1, word2, word3, word4; +l_uint32 *datas, *datad, *lines, *lined; +PIX *pixd; + + if (!pixs) + return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); + + if (pixGetDepth(pixs) != 1) + return (PIX *)ERROR_PTR("pixs not binary", __func__, NULL); + if (level < 1 || level > 4) + return (PIX *)ERROR_PTR("level must be in set {1,2,3,4}", + __func__, NULL); + + pixGetDimensions(pixs, &ws, &hs, NULL); + if (hs <= 1) + return (PIX *)ERROR_PTR("hs must be at least 2", __func__, NULL); + wpls = pixGetWpl(pixs); + datas = pixGetData(pixs); + pixSetPadBits(pixs, 0); + + if ((pixd = pixCreate(ws / 2, hs / 2, 1)) == NULL) + return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); + pixCopyResolution(pixd, pixs); + pixScaleResolution(pixd, 0.5, 0.5); + wpld = pixGetWpl(pixd); + datad = pixGetData(pixd); + + tab = (intab) ? intab : makeSubsampleTab2x(); + if (!tab) { + pixDestroy(&pixd); + return (PIX *)ERROR_PTR("tab not made", __func__, NULL); + } + + /* e.g., if ws = 65: wd = 32, wpls = 3, wpld = 1 --> trouble */ + wplsi = L_MIN(wpls, 2 * wpld); /* iterate over this number of words */ + + switch (level) + { + + case 1: + for (i = 0, id = 0; i < hs - 1; i += 2, id++) { + lines = datas + i * wpls; + lined = datad + id * wpld; + for (j = 0; j < wplsi; j++) { + word1 = *(lines + j); + word2 = *(lines + wpls + j); + + /* OR/OR */ + word2 = word1 | word2; + word2 = word2 | (word2 << 1); + + word2 = word2 & 0xaaaaaaaa; /* mask */ + word1 = word2 | (word2 << 7); /* fold; data in bytes 0 & 2 */ + byte0 = word1 >> 24; + byte1 = (word1 >> 8) & 0xff; + shortd = (tab[byte0] << 8) | tab[byte1]; + SET_DATA_TWO_BYTES(lined, j, shortd); + } + } + break; + + case 2: + for (i = 0, id = 0; i < hs - 1; i += 2, id++) { + lines = datas + i * wpls; + lined = datad + id * wpld; + for (j = 0; j < wplsi; j++) { + word1 = *(lines + j); + word2 = *(lines + wpls + j); + + /* (AND/OR) OR (OR/AND) */ + word3 = word1 & word2; + word3 = word3 | (word3 << 1); + word4 = word1 | word2; + word4 = word4 & (word4 << 1); + word2 = word3 | word4; + + word2 = word2 & 0xaaaaaaaa; /* mask */ + word1 = word2 | (word2 << 7); /* fold; data in bytes 0 & 2 */ + byte0 = word1 >> 24; + byte1 = (word1 >> 8) & 0xff; + shortd = (tab[byte0] << 8) | tab[byte1]; + SET_DATA_TWO_BYTES(lined, j, shortd); + } + } + break; + + case 3: + for (i = 0, id = 0; i < hs - 1; i += 2, id++) { + lines = datas + i * wpls; + lined = datad + id * wpld; + for (j = 0; j < wplsi; j++) { + word1 = *(lines + j); + word2 = *(lines + wpls + j); + + /* (AND/OR) AND (OR/AND) */ + word3 = word1 & word2; + word3 = word3 | (word3 << 1); + word4 = word1 | word2; + word4 = word4 & (word4 << 1); + word2 = word3 & word4; + + word2 = word2 & 0xaaaaaaaa; /* mask */ + word1 = word2 | (word2 << 7); /* fold; data in bytes 0 & 2 */ + byte0 = word1 >> 24; + byte1 = (word1 >> 8) & 0xff; + shortd = (tab[byte0] << 8) | tab[byte1]; + SET_DATA_TWO_BYTES(lined, j, shortd); + } + } + break; + + case 4: + for (i = 0, id = 0; i < hs - 1; i += 2, id++) { + lines = datas + i * wpls; + lined = datad + id * wpld; + for (j = 0; j < wplsi; j++) { + word1 = *(lines + j); + word2 = *(lines + wpls + j); + + /* AND/AND */ + word2 = word1 & word2; + word2 = word2 & (word2 << 1); + + word2 = word2 & 0xaaaaaaaa; /* mask */ + word1 = word2 | (word2 << 7); /* fold; data in bytes 0 & 2 */ + byte0 = word1 >> 24; + byte1 = (word1 >> 8) & 0xff; + shortd = (tab[byte0] << 8) | tab[byte1]; + SET_DATA_TWO_BYTES(lined, j, shortd); + } + } + break; + } + + if (!intab) LEPT_FREE(tab); + return pixd; +} + + +/*! + * \brief makeSubsampleTab2x() + * + * \return tab table of 256 permutations, or NULL on error + * + * <pre> + * Notes: + * Permutation table for 2x rank binary reduction + * This table permutes the bits in a byte, from + * 0 4 1 5 2 6 3 7 + * to + * 0 1 2 3 4 5 6 7 + * </pre> + */ +l_uint8 * +makeSubsampleTab2x(void) +{ +l_uint8 *tab; +l_int32 i; + + tab = (l_uint8 *) LEPT_CALLOC(256, sizeof(l_uint8)); + for (i = 0; i < 256; i++) { + tab[i] = ((i & 0x01) ) | /* 7 */ + ((i & 0x04) >> 1) | /* 6 */ + ((i & 0x10) >> 2) | /* 5 */ + ((i & 0x40) >> 3) | /* 4 */ + ((i & 0x02) << 3) | /* 3 */ + ((i & 0x08) << 2) | /* 2 */ + ((i & 0x20) << 1) | /* 1 */ + ((i & 0x80) ); /* 0 */ + } + return tab; +}
