diff mupdf-source/thirdparty/leptonica/src/flipdetectdwa.c.notused @ 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/flipdetectdwa.c.notused	Mon Sep 15 11:43:07 2025 +0200
@@ -0,0 +1,660 @@
+/*====================================================================*
+ -  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 flipdetectdwa.c.notused
+ * <pre>
+ *
+ *                                  NOTE
+ *      ==============================================================
+ *      This code has been retired from the library.  It is faster than
+ *      the rasterop implementation, but not by a large amount.  On a
+ *      standard 8 Mpixel page image, the timings are:
+ *         Rasterop: 0.37 sec
+ *         DWA:      0.21 sec.
+ *      It is preserved here to show how the dwa code can be generated
+ *      and then used in an application.
+ *      ==============================================================
+ *
+ *      DWA page orientation detection (pure rotation by 90 degree increments):
+ *          l_int32      pixOrientDetectDwa()
+ *          l_int32      pixUpDownDetectDwa()
+ *
+ *      DWA mirror detection (flip 180 degrees about line in plane of image):
+ *          l_int32      pixMirrorDetectDwa()
+ *
+ *      Low-level auto-generated DWA implementation of hit-miss transforms.
+ *      This code (rearranged) was generated by prog/flipselgen.c.
+ *          static PIX  *pixFlipFHMTGen()
+ *          --> static l_int32   flipfhmtgen_low()  -- dispatcher
+ *              --> static void      fhmt_1_0()
+ *              --> static void      fhmt_1_1()
+ *              --> static void      fhmt_1_2()
+ *              --> static void      fhmt_1_3()
+ *
+ *      The four Sels used are defined in prog/flipselgen.c.
+ *      They are the same as those in flipdetect.c.
+ * </pre>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config_auto.h>
+#endif  /* HAVE_CONFIG_H */
+
+#include <math.h>
+#include <string.h>
+#include "allheaders.h"
+
+    /* Parameters for determining orientation */
+static const l_int32  DefaultMinUpDownCount = 70;
+static const l_float32  DefaultMinUpDownConf = 8.0;
+
+    /* Parameters for determining mirror flip */
+static const l_int32  DefaultMinMirrorFlipCount = 100;
+static const l_float32  DefaultMinMirrorFlipConf = 5.0;
+
+static l_int32   NUM_SELS_GENERATED = 4;
+static char  SEL_NAMES[][10] = {"flipsel1",
+                                "flipsel2",
+                                "flipsel3",
+                                "flipsel4"};
+
+static l_int32 flipfhmtgen_low(l_uint32 *, l_int32, l_int32, l_int32,
+                               l_uint32 *, l_int32, l_int32);
+
+static void  fhmt_1_0(l_uint32 *, l_int32, l_int32, l_int32, l_uint32 *,
+                      l_int32);
+static void  fhmt_1_1(l_uint32 *, l_int32, l_int32, l_int32, l_uint32 *,
+                      l_int32);
+static void  fhmt_1_2(l_uint32 *, l_int32, l_int32, l_int32, l_uint32 *,
+                      l_int32);
+static void  fhmt_1_3(l_uint32 *, l_int32, l_int32, l_int32, l_uint32 *,
+                      l_int32);
+
+/*----------------------------------------------------------------*
+ *        High-level interface for orientation detection          *
+ *        (four 90 degree angles)                                 * 
+ *----------------------------------------------------------------*/
+/*!
+ * \brief   pixOrientDetectDwa()
+ *
+ * \param[in]    pixs        1 bpp, deskewed, English text
+ * \param[out]   pupconf     [optional] ; may be NULL
+ * \param[out]   pleftconf   [optional] ; may be NULL
+ * \param[in]    mincount    min number of up + down; use 0 for default
+ * \param[in]    debug       1 for debug output; 0 otherwise
+ * \return  0 if OK, 1 on error
+ *
+ * <pre>
+ * Notes:
+ *      (1) Same interface as for pixOrientDetect().  See notes
+ *          there for usage.
+ *      (2) Uses auto-gen'd code for the Sels defined at the
+ *          top of this file, with some renaming of functions.
+ *          The auto-gen'd code is in fliphmtgen.c, and can
+ *          be generated by a simple executable; see prog/flipselgen.c.
+ *      (3) This runs about 1.5 times faster than the pixOrientDetect().
+ * </pre>
+ */
+l_ok
+pixOrientDetectDwa(PIX        *pixs,
+                   l_float32  *pupconf,
+                   l_float32  *pleftconf,
+                   l_int32     mincount,
+                   l_int32     debug)
+{
+PIX  *pix1;
+
+    if (!pixs || pixGetDepth(pixs) != 1)
+        return ERROR_INT("pixs not defined or not 1 bpp", __func__, 1);
+    if (!pupconf && !pleftconf)
+        return ERROR_INT("nothing to do", __func__, 1);
+    if (mincount == 0)
+        mincount = DefaultMinUpDownCount;
+
+    if (pupconf)
+        pixUpDownDetectDwa(pixs, pupconf, mincount, 0, debug);
+    if (pleftconf) {
+        pix1 = pixRotate90(pixs, 1);
+        pixUpDownDetectDwa(pix1, pleftconf, mincount, 0, debug);
+        pixDestroy(&pix1);
+    }
+
+    return 0;
+}
+
+
+/*!
+ * \brief   pixUpDownDetectDwa()
+ *
+ * \param[in]    pixs       1 bpp, deskewed, English text, 150 - 300 ppi
+ * \param[out]   pconf      confidence that text is rightside-up
+ * \param[in]    mincount   min number of up + down; use 0 for default
+ * \param[in]    npixels    number of pixels removed from each side of word box
+ * \param[in]    debug      1 for debug output; 0 otherwise
+ * \return  0 if OK, 1 on error
+ *
+ * <pre>
+ * Notes:
+ *      (1) Faster (DWA) version of pixUpDownDetect().
+ *      (2) If npixels == 0, the pixels identified through the HMT
+ *          (hit-miss transform) are not clipped by a truncated word
+ *          mask pixm.  See pixUpDownDetect() for usage and other details.
+ *      (3) The returned confidence is the normalized difference
+ *          between the number of detected up and down ascenders,
+ *          assuming that the text is either rightside-up or upside-down
+ *          and not rotated at a 90 degree angle.
+ * </pre>
+ */
+l_ok
+pixUpDownDetectDwa(PIX        *pixs,
+                   l_float32  *pconf,
+                   l_int32     mincount,
+                   l_int32     npixels,
+                   l_int32     debug)
+{
+char       flipsel1[] = "flipsel1";
+char       flipsel2[] = "flipsel2";
+char       flipsel3[] = "flipsel3";
+char       flipsel4[] = "flipsel4";
+l_int32    countup, countdown, nmax;
+l_float32  nup, ndown;
+PIX       *pixt, *pix0, *pix1, *pix2, *pix3, *pixm;
+
+    if (!pconf)
+        return ERROR_INT("&conf not defined", __func__, 1);
+    *pconf = 0.0;
+    if (!pixs || pixGetDepth(pixs) != 1)
+        return ERROR_INT("pixs not defined or not 1 bpp", __func__, 1);
+    if (mincount == 0)
+        mincount = DefaultMinUpDownCount;
+    if (npixels < 0)
+        npixels = 0;
+
+        /* One of many reasonable pre-filtering sequences: (1, 8) and (30, 1).
+         * This closes holes in x-height characters and joins them at
+         * the x-height.  There is more noise in the descender detection
+         * from this, but it works fairly well. */
+    pixt = pixMorphSequenceDwa(pixs, "c1.8 + c30.1", 0);
+
+        /* Be sure to add the border before the flip DWA operations! */
+    pix0 = pixAddBorderGeneral(pixt, ADDED_BORDER, ADDED_BORDER,
+                                ADDED_BORDER, ADDED_BORDER, 0);
+    pixDestroy(&pixt);
+
+        /* Optionally, make a mask of the word bounding boxes, shortening
+         * each of them by a fixed amount at each end. */
+    pixm = NULL;
+    if (npixels > 0) {
+        l_int32  i, nbox, x, y, w, h;
+        BOX   *box;
+        BOXA  *boxa;
+        pix1 = pixMorphSequenceDwa(pix0, "o10.1", 0);
+        boxa = pixConnComp(pix1, NULL, 8);
+        pixm = pixCreateTemplate(pix1);
+        pixDestroy(&pix1);
+        nbox = boxaGetCount(boxa);
+        for (i = 0; i < nbox; i++) {
+            box = boxaGetBox(boxa, i, L_CLONE);
+            boxGetGeometry(box, &x, &y, &w, &h);
+            if (w > 2 * npixels)
+                pixRasterop(pixm, x + npixels, y - 6, w - 2 * npixels, h + 13,
+                            PIX_SET, NULL, 0, 0);
+            boxDestroy(&box);
+        }
+        boxaDestroy(&boxa);
+    }
+
+        /* Find the ascenders and optionally filter with pixm.
+         * For an explanation of the procedure used for counting the result
+         * of the HMT, see comments in pixUpDownDetect().  */
+    pix1 = pixFlipFHMTGen(NULL, pix0, flipsel1);
+    pix2 = pixFlipFHMTGen(NULL, pix0, flipsel2);
+    pixOr(pix1, pix1, pix2);
+    if (pixm)
+        pixAnd(pix1, pix1, pixm);
+    pix3 = pixReduceRankBinaryCascade(pix1, 1, 1, 0, 0);
+    pixCountPixels(pix3, &countup, NULL);
+    pixDestroy(&pix1);
+    pixDestroy(&pix2);
+    pixDestroy(&pix3);
+
+        /* Find the ascenders and optionally filter with pixm. */
+    pix1 = pixFlipFHMTGen(NULL, pix0, flipsel3);
+    pix2 = pixFlipFHMTGen(NULL, pix0, flipsel4);
+    pixOr(pix1, pix1, pix2);
+    if (pixm)
+        pixAnd(pix1, pix1, pixm);
+    pix3 = pixReduceRankBinaryCascade(pix1, 1, 1, 0, 0);
+    pixCountPixels(pix3, &countdown, NULL);
+    pixDestroy(&pix1);
+    pixDestroy(&pix2);
+    pixDestroy(&pix3);
+
+        /* Evaluate statistically, generating a confidence that is
+         * related to the probability with a gaussian distribution. */
+    nup = (l_float32)(countup);
+    ndown = (l_float32)(countdown);
+    nmax = L_MAX(countup, countdown);
+    if (nmax > mincount)
+        *pconf = 2. * ((nup - ndown) / sqrt(nup + ndown));
+
+    if (debug) {
+        if (pixm) {
+            lept_mkdir("lept/orient");
+            pixWriteDebug("/tmp/lept/orient/pixm2.png", pixm, IFF_PNG);
+        }
+        lept_stderr("nup = %7.3f, ndown = %7.3f, conf = %7.3f\n",
+                nup, ndown, *pconf);
+        if (*pconf > DefaultMinUpDownConf)
+            lept_stderr("Text is rightside-up\n");
+        if (*pconf < -DefaultMinUpDownConf)
+            lept_stderr("Text is upside-down\n");
+    }
+
+    pixDestroy(&pix0);
+    pixDestroy(&pixm);
+    return 0;
+}
+
+
+/*----------------------------------------------------------------*
+ *                     Left-right mirror detection                *
+ *                          DWA implementation                    *
+ *----------------------------------------------------------------*/
+/*!
+ * \brief   pixMirrorDetectDwa()
+ *
+ * \param[in]    pixs       1 bpp, deskewed, English text
+ * \param[out]   pconf      confidence that text is not LR mirror reversed
+ * \param[in]    mincount   min number of left + right; use 0 for default
+ * \param[in]    debug      1 for debug output; 0 otherwise
+ * \return  0 if OK, 1 on error
+ *
+ * <pre>
+ * Notes:
+ *      (1) We assume the text is horizontally oriented, with
+ *          ascenders going up.
+ *      (2) See notes in pixMirrorDetect().
+ * </pre>
+ */
+l_ok
+pixMirrorDetectDwa(PIX        *pixs,
+                   l_float32  *pconf,
+                   l_int32     mincount,
+                   l_int32     debug)
+{
+char       flipsel1[] = "flipsel1";
+char       flipsel2[] = "flipsel2";
+l_int32    count1, count2, nmax;
+l_float32  nleft, nright;
+PIX       *pix0, *pix1, *pix2, *pix3;
+
+    if (!pconf)
+        return ERROR_INT("&conf not defined", __func__, 1);
+    *pconf = 0.0;
+    if (!pixs || pixGetDepth(pixs) != 1)
+        return ERROR_INT("pixs not defined or not 1 bpp", __func__, 1);
+    if (mincount == 0)
+        mincount = DefaultMinMirrorFlipCount;
+
+        /* Fill x-height characters but not space between them, sort of. */
+    pix3 = pixMorphSequenceDwa(pixs, "d1.30", 0);
+    pixXor(pix3, pix3, pixs);
+    pix0 = pixMorphSequenceDwa(pixs, "c15.1", 0);
+    pixXor(pix0, pix0, pixs);
+    pixAnd(pix0, pix0, pix3);
+    pixOr(pix3, pix0, pixs);
+    pixDestroy(&pix0);
+    pix0 = pixAddBorderGeneral(pix3, ADDED_BORDER, ADDED_BORDER,
+                                ADDED_BORDER, ADDED_BORDER, 0);
+    pixDestroy(&pix3);
+
+        /* Filter the right-facing characters. */
+    pix1 = pixFlipFHMTGen(NULL, pix0, flipsel1);
+    pix3 = pixReduceRankBinaryCascade(pix1, 1, 1, 0, 0);
+    pixCountPixels(pix3, &count1, NULL);
+    pixDestroy(&pix1);
+    pixDestroy(&pix3);
+
+        /* Filter the left-facing characters. */
+    pix2 = pixFlipFHMTGen(NULL, pix0, flipsel2);
+    pix3 = pixReduceRankBinaryCascade(pix2, 1, 1, 0, 0);
+    pixCountPixels(pix3, &count2, NULL);
+    pixDestroy(&pix2);
+    pixDestroy(&pix3);
+
+    pixDestroy(&pix0);
+    nright = (l_float32)count1;
+    nleft = (l_float32)count2;
+    nmax = L_MAX(count1, count2);
+
+    if (nmax > mincount)
+        *pconf = 2. * ((nright - nleft) / sqrt(nright + nleft));
+
+    if (debug) {
+        lept_stderr("nright = %f, nleft = %f\n", nright, nleft);
+        if (*pconf > DefaultMinMirrorFlipConf)
+            lept_stderr("Text is not mirror reversed\n");
+        if (*pconf < -DefaultMinMirrorFlipConf)
+            lept_stderr("Text is mirror reversed\n");
+    }
+
+    return 0;
+}
+
+
+/*---------------------------------------------------------------------*
+ *                         Auto-generated hmt code                     *
+ *---------------------------------------------------------------------*/
+/*
+ *  pixFlipFHMTGen()
+ *
+ *      Input:  pixd (usual 3 choices: null, == pixs, != pixs)
+ *              pixs
+ *              sel name (one of four defined in SEL_NAMES[])
+ *      Return: pixd
+ *
+ *  Notes:
+ *     Action: hit-miss transform on pixs by the sel
+ *     N.B.: the sel must have at least one hit, and it
+ *           can have any number of misses.
+ */
+PIX *
+pixFlipFHMTGen(PIX         *pixd,
+               PIX         *pixs,
+               const char  *selname)
+{
+l_int32    i, index, found, w, h, wpls, wpld;
+l_uint32  *datad, *datas, *datat;
+PIX       *pixt;
+
+    if (!pixs)
+        return (PIX *)ERROR_PTR("pixs not defined", __func__, pixd);
+    if (pixGetDepth(pixs) != 1)
+        return (PIX *)ERROR_PTR("pixs must be 1 bpp", __func__, pixd);
+
+    found = FALSE;
+    for (i = 0; i < NUM_SELS_GENERATED; i++) {
+        if (strcmp(selname, SEL_NAMES[i]) == 0) {
+            found = TRUE;
+            index = i;
+            break;
+        }
+    }
+    if (found == FALSE)
+        return (PIX *)ERROR_PTR("sel index not found", __func__, pixd);
+
+    if (pixd) {
+        if (!pixSizesEqual(pixs, pixd))
+            return (PIX *)ERROR_PTR("sizes not equal", __func__, pixd);
+    } else {
+        if ((pixd = pixCreateTemplate(pixs)) == NULL)
+            return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
+    }
+
+    wpls = pixGetWpl(pixs);
+    wpld = pixGetWpl(pixd);
+
+        /*  The images must be surrounded with ADDED_BORDER white pixels,
+         *  that we'll read from.  We fabricate a "proper"
+         *  image as the subimage within the border, having the
+         *  following parameters:  */
+    w = pixGetWidth(pixs) - 2 * ADDED_BORDER;
+    h = pixGetHeight(pixs) - 2 * ADDED_BORDER;
+    datas = pixGetData(pixs) + ADDED_BORDER * wpls + ADDED_BORDER / 32;
+    datad = pixGetData(pixd) + ADDED_BORDER * wpld + ADDED_BORDER / 32;
+
+    if (pixd == pixs) {  /* need temp image if in-place */
+        if ((pixt = pixCopy(NULL, pixs)) == NULL)
+            return (PIX *)ERROR_PTR("pixt not made", __func__, pixd);
+        datat = pixGetData(pixt) + ADDED_BORDER * wpls + ADDED_BORDER / 32;
+        flipfhmtgen_low(datad, w, h, wpld, datat, wpls, index);
+        pixDestroy(&pixt);
+    } else {  /* simple and not in-place */
+        flipfhmtgen_low(datad, w, h, wpld, datas, wpls, index);
+    }
+
+    return pixd;
+}
+
+
+/*---------------------------------------------------------------------*
+ *                           Fast hmt dispatcher                       *
+ *---------------------------------------------------------------------*/
+/*
+ *  flipfhmtgen_low()
+ *
+ *       A dispatcher to appropriate low-level code for flip hmt ops
+ */
+static l_int32
+flipfhmtgen_low(l_uint32  *datad,
+                l_int32    w,
+                l_int32    h,
+                l_int32    wpld,
+                l_uint32  *datas,
+                l_int32    wpls,
+                l_int32    index)
+{
+
+    switch (index)
+    {
+    case 0:
+        fhmt_1_0(datad, w, h, wpld, datas, wpls);
+        break;
+    case 1:
+        fhmt_1_1(datad, w, h, wpld, datas, wpls);
+        break;
+    case 2:
+        fhmt_1_2(datad, w, h, wpld, datas, wpls);
+        break;
+    case 3:
+        fhmt_1_3(datad, w, h, wpld, datas, wpls);
+        break;
+    }
+
+    return 0;
+}
+
+
+/*--------------------------------------------------------------------------*
+ *                  Low-level auto-generated hmt routines                   *
+ *--------------------------------------------------------------------------*/
+/*
+ *  N.B.  in all the low-level routines, the part of the image
+ *        that is accessed has been clipped by ADDED_BORDER pixels
+ *        on all four sides.  This is done in the higher level
+ *        code by redefining w and h smaller and by moving the
+ *        start-of-image pointers up to the beginning of this
+ *        interior rectangle.
+ */
+
+static void
+fhmt_1_0(l_uint32  *datad,
+         l_int32    w,
+         l_int32    h,
+         l_int32    wpld,
+         l_uint32  *datas,
+         l_int32    wpls)
+{
+l_int32    i;
+l_int32    j, pwpls;
+l_uint32  *sptr, *dptr;
+l_int32    wpls2, wpls3;
+
+    wpls2 = 2 * wpls;
+    wpls3 = 3 * wpls;
+    pwpls = (l_uint32)(w + 31) / 32;  /* proper wpl of src */
+
+    for (i = 0; i < h; i++) {
+        sptr = datas + i * wpls;
+        dptr = datad + i * wpld;
+        for (j = 0; j < pwpls; j++, sptr++, dptr++) {
+            *dptr = ((*(sptr - wpls) >> 3) | (*(sptr - wpls - 1) << 29)) &
+                    (~*(sptr - wpls)) &
+                    ((~*(sptr - wpls) << 1) | (~*(sptr - wpls + 1) >> 31)) &
+                    ((*(sptr) >> 3) | (*(sptr - 1) << 29)) &
+                    ((~*(sptr) >> 1) | (~*(sptr - 1) << 31)) &
+                    (~*sptr) &
+                    ((~*(sptr) << 1) | (~*(sptr + 1) >> 31)) &
+                    ((*(sptr + wpls) >> 3) | (*(sptr + wpls - 1) << 29)) &
+                    (~*(sptr + wpls)) &
+                    ((*(sptr + wpls2) >> 3) | (*(sptr + wpls2 - 1) << 29)) &
+                    ((*(sptr + wpls3) >> 3) | (*(sptr + wpls3 - 1) << 29)) &
+                    ((*(sptr + wpls3) >> 2) | (*(sptr + wpls3 - 1) << 30)) &
+                    ((*(sptr + wpls3) >> 1) | (*(sptr + wpls3 - 1) << 31)) &
+                    (*(sptr + wpls3)) &
+                    ((*(sptr + wpls3) << 1) | (*(sptr + wpls3 + 1) >> 31)) &
+                    ((*(sptr + wpls3) << 2) | (*(sptr + wpls3 + 1) >> 30));
+        }
+    }
+}
+
+
+static void
+fhmt_1_1(l_uint32  *datad,
+         l_int32    w,
+         l_int32    h,
+         l_int32    wpld,
+         l_uint32  *datas,
+         l_int32    wpls)
+{
+l_int32    i;
+l_int32    j, pwpls;
+l_uint32  *sptr, *dptr;
+l_int32    wpls2, wpls3;
+
+    wpls2 = 2 * wpls;
+    wpls3 = 3 * wpls;
+    pwpls = (l_uint32)(w + 31) / 32;  /* proper wpl of src */
+
+    for (i = 0; i < h; i++) {
+        sptr = datas + i * wpls;
+        dptr = datad + i * wpld;
+        for (j = 0; j < pwpls; j++, sptr++, dptr++) {
+            *dptr = ((~*(sptr - wpls) >> 1) | (~*(sptr - wpls - 1) << 31)) &
+                    (~*(sptr - wpls)) &
+                    ((*(sptr - wpls) << 3) | (*(sptr - wpls + 1) >> 29)) &
+                    ((~*(sptr) >> 1) | (~*(sptr - 1) << 31)) &
+                    (~*sptr) &
+                    ((~*(sptr) << 1) | (~*(sptr + 1) >> 31)) &
+                    ((*(sptr) << 3) | (*(sptr + 1) >> 29)) &
+                    (~*(sptr + wpls)) &
+                    ((*(sptr + wpls) << 3) | (*(sptr + wpls + 1) >> 29)) &
+                    ((*(sptr + wpls2) << 3) | (*(sptr + wpls2 + 1) >> 29)) &
+                    ((*(sptr + wpls3) >> 2) | (*(sptr + wpls3 - 1) << 30)) &
+                    ((*(sptr + wpls3) >> 1) | (*(sptr + wpls3 - 1) << 31)) &
+                    (*(sptr + wpls3)) &
+                    ((*(sptr + wpls3) << 1) | (*(sptr + wpls3 + 1) >> 31)) &
+                    ((*(sptr + wpls3) << 2) | (*(sptr + wpls3 + 1) >> 30)) &
+                    ((*(sptr + wpls3) << 3) | (*(sptr + wpls3 + 1) >> 29));
+        }
+    }
+}
+
+
+static void
+fhmt_1_2(l_uint32  *datad,
+         l_int32    w,
+         l_int32    h,
+         l_int32    wpld,
+         l_uint32  *datas,
+         l_int32    wpls)
+{
+l_int32    i;
+l_int32    j, pwpls;
+l_uint32  *sptr, *dptr;
+l_int32    wpls2, wpls3;
+
+    wpls2 = 2 * wpls;
+    wpls3 = 3 * wpls;
+    pwpls = (l_uint32)(w + 31) / 32;  /* proper wpl of src */
+
+    for (i = 0; i < h; i++) {
+        sptr = datas + i * wpls;
+        dptr = datad + i * wpld;
+        for (j = 0; j < pwpls; j++, sptr++, dptr++) {
+            *dptr = ((*(sptr - wpls3) >> 3) | (*(sptr - wpls3 - 1) << 29)) &
+                    ((*(sptr - wpls3) >> 2) | (*(sptr - wpls3 - 1) << 30)) &
+                    ((*(sptr - wpls3) >> 1) | (*(sptr - wpls3 - 1) << 31)) &
+                    (*(sptr - wpls3)) &
+                    ((*(sptr - wpls3) << 1) | (*(sptr - wpls3 + 1) >> 31)) &
+                    ((*(sptr - wpls3) << 2) | (*(sptr - wpls3 + 1) >> 30)) &
+                    ((*(sptr - wpls2) >> 3) | (*(sptr - wpls2 - 1) << 29)) &
+                    ((*(sptr - wpls) >> 3) | (*(sptr - wpls - 1) << 29)) &
+                    (~*(sptr - wpls)) &
+                    ((*(sptr) >> 3) | (*(sptr - 1) << 29)) &
+                    ((~*(sptr) >> 1) | (~*(sptr - 1) << 31)) &
+                    (~*sptr) &
+                    ((~*(sptr) << 1) | (~*(sptr + 1) >> 31)) &
+                    ((*(sptr + wpls) >> 3) | (*(sptr + wpls - 1) << 29)) &
+                    (~*(sptr + wpls)) &
+                    ((~*(sptr + wpls) << 1) | (~*(sptr + wpls + 1) >> 31));
+        }
+    }
+}
+
+
+static void
+fhmt_1_3(l_uint32  *datad,
+         l_int32    w,
+         l_int32    h,
+         l_int32    wpld,
+         l_uint32  *datas,
+         l_int32    wpls)
+{
+l_int32    i;
+l_int32    j, pwpls;
+l_uint32  *sptr, *dptr;
+l_int32    wpls2, wpls3;
+
+    wpls2 = 2 * wpls;
+    wpls3 = 3 * wpls;
+    pwpls = (l_uint32)(w + 31) / 32;  /* proper wpl of src */
+
+    for (i = 0; i < h; i++) {
+        sptr = datas + i * wpls;
+        dptr = datad + i * wpld;
+        for (j = 0; j < pwpls; j++, sptr++, dptr++) {
+            *dptr = ((*(sptr - wpls3) >> 2) | (*(sptr - wpls3 - 1) << 30)) &
+                    ((*(sptr - wpls3) >> 1) | (*(sptr - wpls3 - 1) << 31)) &
+                    (*(sptr - wpls3)) &
+                    ((*(sptr - wpls3) << 1) | (*(sptr - wpls3 + 1) >> 31)) &
+                    ((*(sptr - wpls3) << 2) | (*(sptr - wpls3 + 1) >> 30)) &
+                    ((*(sptr - wpls3) << 3) | (*(sptr - wpls3 + 1) >> 29)) &
+                    ((*(sptr - wpls2) << 3) | (*(sptr - wpls2 + 1) >> 29)) &
+                    (~*(sptr - wpls)) &
+                    ((*(sptr - wpls) << 3) | (*(sptr - wpls + 1) >> 29)) &
+                    ((~*(sptr) >> 1) | (~*(sptr - 1) << 31)) &
+                    (~*sptr) &
+                    ((~*(sptr) << 1) | (~*(sptr + 1) >> 31)) &
+                    ((*(sptr) << 3) | (*(sptr + 1) >> 29)) &
+                    ((~*(sptr + wpls) >> 1) | (~*(sptr + wpls - 1) << 31)) &
+                    (~*(sptr + wpls)) &
+                    ((*(sptr + wpls) << 3) | (*(sptr + wpls + 1) >> 29));
+        }
+    }
+}