Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/leptonica/src/scale2.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 scale2.c | |
| 29 * <pre> | |
| 30 * Scale-to-gray (1 bpp --> 8 bpp; arbitrary downscaling) | |
| 31 * PIX *pixScaleToGray() | |
| 32 * PIX *pixScaleToGrayFast() | |
| 33 * | |
| 34 * Scale-to-gray (1 bpp --> 8 bpp; integer downscaling) | |
| 35 * PIX *pixScaleToGray2() | |
| 36 * PIX *pixScaleToGray3() | |
| 37 * PIX *pixScaleToGray4() | |
| 38 * PIX *pixScaleToGray6() | |
| 39 * PIX *pixScaleToGray8() | |
| 40 * PIX *pixScaleToGray16() | |
| 41 * | |
| 42 * Scale-to-gray by mipmap(1 bpp --> 8 bpp, arbitrary reduction) | |
| 43 * PIX *pixScaleToGrayMipmap() | |
| 44 * | |
| 45 * Grayscale scaling using mipmap | |
| 46 * PIX *pixScaleMipmap() | |
| 47 * | |
| 48 * Replicated (integer) expansion (all depths) | |
| 49 * PIX *pixExpandReplicate() | |
| 50 * | |
| 51 * Grayscale downscaling using min and max | |
| 52 * PIX *pixScaleGrayMinMax() | |
| 53 * PIX *pixScaleGrayMinMax2() | |
| 54 * | |
| 55 * Grayscale downscaling using rank value | |
| 56 * PIX *pixScaleGrayRankCascade() | |
| 57 * PIX *pixScaleGrayRank2() | |
| 58 * | |
| 59 * Helper function for transferring alpha with scaling | |
| 60 * l_int32 pixScaleAndTransferAlpha() | |
| 61 * | |
| 62 * RGB scaling including alpha (blend) component | |
| 63 * PIX *pixScaleWithAlpha() | |
| 64 * | |
| 65 * Low-level static functions: | |
| 66 * | |
| 67 * Scale-to-gray 2x | |
| 68 * static void scaleToGray2Low() | |
| 69 * static l_uint32 *makeSumTabSG2() | |
| 70 * static l_uint8 *makeValTabSG2() | |
| 71 * | |
| 72 * Scale-to-gray 3x | |
| 73 * static void scaleToGray3Low() | |
| 74 * static l_uint32 *makeSumTabSG3() | |
| 75 * static l_uint8 *makeValTabSG3() | |
| 76 * | |
| 77 * Scale-to-gray 4x | |
| 78 * static void scaleToGray4Low() | |
| 79 * static l_uint32 *makeSumTabSG4() | |
| 80 * static l_uint8 *makeValTabSG4() | |
| 81 * | |
| 82 * Scale-to-gray 6x | |
| 83 * static void scaleToGray6Low() | |
| 84 * static l_uint8 *makeValTabSG6() | |
| 85 * | |
| 86 * Scale-to-gray 8x | |
| 87 * static void scaleToGray8Low() | |
| 88 * static l_uint8 *makeValTabSG8() | |
| 89 * | |
| 90 * Scale-to-gray 16x | |
| 91 * static void scaleToGray16Low() | |
| 92 * | |
| 93 * Grayscale mipmap | |
| 94 * static l_int32 scaleMipmapLow() | |
| 95 * </pre> | |
| 96 */ | |
| 97 | |
| 98 #ifdef HAVE_CONFIG_H | |
| 99 #include <config_auto.h> | |
| 100 #endif /* HAVE_CONFIG_H */ | |
| 101 | |
| 102 #include <string.h> | |
| 103 #include "allheaders.h" | |
| 104 | |
| 105 static void scaleToGray2Low(l_uint32 *datad, l_int32 wd, l_int32 hd, | |
| 106 l_int32 wpld, l_uint32 *datas, l_int32 wpls, | |
| 107 l_uint32 *sumtab, l_uint8 *valtab); | |
| 108 static l_uint32 *makeSumTabSG2(void); | |
| 109 static l_uint8 *makeValTabSG2(void); | |
| 110 static void scaleToGray3Low(l_uint32 *datad, l_int32 wd, l_int32 hd, | |
| 111 l_int32 wpld, l_uint32 *datas, l_int32 wpls, | |
| 112 l_uint32 *sumtab, l_uint8 *valtab); | |
| 113 static l_uint32 *makeSumTabSG3(void); | |
| 114 static l_uint8 *makeValTabSG3(void); | |
| 115 static void scaleToGray4Low(l_uint32 *datad, l_int32 wd, l_int32 hd, | |
| 116 l_int32 wpld, l_uint32 *datas, l_int32 wpls, | |
| 117 l_uint32 *sumtab, l_uint8 *valtab); | |
| 118 static l_uint32 *makeSumTabSG4(void); | |
| 119 static l_uint8 *makeValTabSG4(void); | |
| 120 static void scaleToGray6Low(l_uint32 *datad, l_int32 wd, l_int32 hd, | |
| 121 l_int32 wpld, l_uint32 *datas, l_int32 wpls, | |
| 122 l_int32 *tab8, l_uint8 *valtab); | |
| 123 static l_uint8 *makeValTabSG6(void); | |
| 124 static void scaleToGray8Low(l_uint32 *datad, l_int32 wd, l_int32 hd, | |
| 125 l_int32 wpld, l_uint32 *datas, l_int32 wpls, | |
| 126 l_int32 *tab8, l_uint8 *valtab); | |
| 127 static l_uint8 *makeValTabSG8(void); | |
| 128 static void scaleToGray16Low(l_uint32 *datad, l_int32 wd, l_int32 hd, | |
| 129 l_int32 wpld, l_uint32 *datas, l_int32 wpls, | |
| 130 l_int32 *tab8); | |
| 131 static l_int32 scaleMipmapLow(l_uint32 *datad, l_int32 wd, l_int32 hd, | |
| 132 l_int32 wpld, l_uint32 *datas1, l_int32 wpls1, | |
| 133 l_uint32 *datas2, l_int32 wpls2, l_float32 red); | |
| 134 | |
| 135 extern l_float32 AlphaMaskBorderVals[2]; | |
| 136 | |
| 137 | |
| 138 /*------------------------------------------------------------------* | |
| 139 * Scale-to-gray (1 bpp --> 8 bpp; arbitrary downscaling) * | |
| 140 *------------------------------------------------------------------*/ | |
| 141 /*! | |
| 142 * \brief pixScaleToGray() | |
| 143 * | |
| 144 * \param[in] pixs 1 bpp | |
| 145 * \param[in] scalefactor reduction: must be > 0.0 and < 1.0 | |
| 146 * \return pixd 8 bpp, scaled down by scalefactor in each direction, | |
| 147 * or NULL on error. | |
| 148 * | |
| 149 * <pre> | |
| 150 * Notes: | |
| 151 * | |
| 152 * For faster scaling in the range of scalefactors from 0.0625 to 0.5, | |
| 153 * with very little difference in quality, use pixScaleToGrayFast(). | |
| 154 * | |
| 155 * Binary images have sharp edges, so they intrinsically have very | |
| 156 * high frequency content. To avoid aliasing, they must be low-pass | |
| 157 * filtered, which tends to blur the edges. How can we keep relatively | |
| 158 * crisp edges without aliasing? The trick is to do binary upscaling | |
| 159 * followed by a power-of-2 scaleToGray. For large reductions, where | |
| 160 * you don't end up with much detail, some corners can be cut. | |
| 161 * | |
| 162 * The intent here is to get high quality reduced grayscale | |
| 163 * images with relatively little computation. We do binary | |
| 164 * pre-scaling followed by scaleToGrayN() for best results, | |
| 165 * esp. to avoid excess blur when the scale factor is near | |
| 166 * an inverse power of 2. Where a low-pass filter is required, | |
| 167 * we use simple convolution kernels: either the hat filter for | |
| 168 * linear interpolation or a flat filter for larger downscaling. | |
| 169 * Other choices, such as a perfect bandpass filter with infinite extent | |
| 170 * (the sinc) or various approximations to it (e.g., lanczos), are | |
| 171 * unnecessarily expensive. | |
| 172 * | |
| 173 * The choices made are as follows: | |
| 174 * (1) Do binary upscaling before scaleToGrayN() for scalefactors > 1/8 | |
| 175 * (2) Do binary downscaling before scaleToGray8() for scalefactors | |
| 176 * between 1/16 and 1/8. | |
| 177 * (3) Use scaleToGray16() before grayscale downscaling for | |
| 178 * scalefactors less than 1/16 | |
| 179 * Another reasonable choice would be to start binary downscaling | |
| 180 * for scalefactors below 1/4, rather than below 1/8 as we do here. | |
| 181 * | |
| 182 * The general scaling rules, not all of which are used here, go as follows: | |
| 183 * (1) For grayscale upscaling, use pixScaleGrayLI(). However, | |
| 184 * note that edges will be visibly blurred for scalefactors | |
| 185 * near (but above) 1.0. Replication will avoid edge blur, | |
| 186 * and should be considered for factors very near 1.0. | |
| 187 * (2) For grayscale downscaling with a scale factor larger than | |
| 188 * about 0.7, use pixScaleGrayLI(). For scalefactors near | |
| 189 * (but below) 1.0, you tread between Scylla and Charybdis. | |
| 190 * pixScaleGrayLI() again gives edge blurring, but | |
| 191 * pixScaleBySampling() gives visible aliasing. | |
| 192 * (3) For grayscale downscaling with a scale factor smaller than | |
| 193 * about 0.7, use pixScaleSmooth() | |
| 194 * (4) For binary input images, do as much scale to gray as possible | |
| 195 * using the special integer functions (2, 3, 4, 8 and 16). | |
| 196 * (5) It is better to upscale in binary, followed by scaleToGrayN() | |
| 197 * than to do scaleToGrayN() followed by an upscale using either | |
| 198 * LI or oversampling. | |
| 199 * (6) It may be better to downscale in binary, followed by | |
| 200 * scaleToGrayN() than to first use scaleToGrayN() followed by | |
| 201 * downscaling. For downscaling between 8x and 16x, this is | |
| 202 * a reasonable option. | |
| 203 * (7) For reductions greater than 16x, it's reasonable to use | |
| 204 * scaleToGray16() followed by further grayscale downscaling. | |
| 205 * </pre> | |
| 206 */ | |
| 207 PIX * | |
| 208 pixScaleToGray(PIX *pixs, | |
| 209 l_float32 scalefactor) | |
| 210 { | |
| 211 l_int32 w, h, minsrc, mindest; | |
| 212 l_float32 mag, red; | |
| 213 PIX *pixt, *pixd; | |
| 214 | |
| 215 if (!pixs) | |
| 216 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 217 if (pixGetDepth(pixs) != 1) | |
| 218 return (PIX *)ERROR_PTR("pixs not 1 bpp", __func__, NULL); | |
| 219 if (scalefactor <= 0.0f) | |
| 220 return (PIX *)ERROR_PTR("scalefactor <= 0.0", __func__, NULL); | |
| 221 if (scalefactor >= 1.0f) | |
| 222 return (PIX *)ERROR_PTR("scalefactor >= 1.0", __func__, NULL); | |
| 223 pixGetDimensions(pixs, &w, &h, NULL); | |
| 224 minsrc = L_MIN(w, h); | |
| 225 mindest = (l_int32)((l_float32)minsrc * scalefactor); | |
| 226 if (mindest < 2) | |
| 227 return (PIX *)ERROR_PTR("scalefactor too small", __func__, NULL); | |
| 228 | |
| 229 if (scalefactor > 0.5f) { /* see note (5) */ | |
| 230 mag = 2.0f * scalefactor; /* will be < 2.0 */ | |
| 231 /* lept_stderr("2x with mag %7.3f\n", mag); */ | |
| 232 if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL) | |
| 233 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL); | |
| 234 pixd = pixScaleToGray2(pixt); | |
| 235 } else if (scalefactor == 0.5f) { | |
| 236 return pixd = pixScaleToGray2(pixs); | |
| 237 } else if (scalefactor > 0.33333f) { /* see note (5) */ | |
| 238 mag = 3.0f * scalefactor; /* will be < 1.5 */ | |
| 239 /* lept_stderr("3x with mag %7.3f\n", mag); */ | |
| 240 if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL) | |
| 241 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL); | |
| 242 pixd = pixScaleToGray3(pixt); | |
| 243 } else if (scalefactor > 0.25f) { /* see note (5) */ | |
| 244 mag = 4.0f * scalefactor; /* will be < 1.3333 */ | |
| 245 /* lept_stderr("4x with mag %7.3f\n", mag); */ | |
| 246 if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL) | |
| 247 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL); | |
| 248 pixd = pixScaleToGray4(pixt); | |
| 249 } else if (scalefactor == 0.25f) { | |
| 250 return pixd = pixScaleToGray4(pixs); | |
| 251 } else if (scalefactor > 0.16667f) { /* see note (5) */ | |
| 252 mag = 6.0f * scalefactor; /* will be < 1.5 */ | |
| 253 /* lept_stderr("6x with mag %7.3f\n", mag); */ | |
| 254 if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL) | |
| 255 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL); | |
| 256 pixd = pixScaleToGray6(pixt); | |
| 257 } else if (scalefactor == 0.16667f) { | |
| 258 return pixd = pixScaleToGray6(pixs); | |
| 259 } else if (scalefactor > 0.125f) { /* see note (5) */ | |
| 260 mag = 8.0f * scalefactor; /* will be < 1.3333 */ | |
| 261 /* lept_stderr("8x with mag %7.3f\n", mag); */ | |
| 262 if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL) | |
| 263 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL); | |
| 264 pixd = pixScaleToGray8(pixt); | |
| 265 } else if (scalefactor == 0.125f) { | |
| 266 return pixd = pixScaleToGray8(pixs); | |
| 267 } else if (scalefactor > 0.0625f) { /* see note (6) */ | |
| 268 red = 8.0f * scalefactor; /* will be > 0.5 */ | |
| 269 /* lept_stderr("8x with red %7.3f\n", red); */ | |
| 270 if ((pixt = pixScaleBinary(pixs, red, red)) == NULL) | |
| 271 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL); | |
| 272 pixd = pixScaleToGray8(pixt); | |
| 273 } else if (scalefactor == 0.0625f) { | |
| 274 return pixd = pixScaleToGray16(pixs); | |
| 275 } else { /* see note (7) */ | |
| 276 red = 16.0f * scalefactor; /* will be <= 1.0 */ | |
| 277 /* lept_stderr("16x with red %7.3f\n", red); */ | |
| 278 if ((pixt = pixScaleToGray16(pixs)) == NULL) | |
| 279 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL); | |
| 280 if (red < 0.7f) | |
| 281 pixd = pixScaleSmooth(pixt, red, red); /* see note (3) */ | |
| 282 else | |
| 283 pixd = pixScaleGrayLI(pixt, red, red); /* see note (2) */ | |
| 284 } | |
| 285 | |
| 286 pixDestroy(&pixt); | |
| 287 if (!pixd) | |
| 288 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 289 pixCopyInputFormat(pixd, pixs); | |
| 290 return pixd; | |
| 291 } | |
| 292 | |
| 293 | |
| 294 /*! | |
| 295 * \brief pixScaleToGrayFast() | |
| 296 * | |
| 297 * \param[in] pixs 1 bpp | |
| 298 * \param[in] scalefactor reduction: must be > 0.0 and < 1.0 | |
| 299 * \return pixd 8 bpp, scaled down by scalefactor in each direction, | |
| 300 * or NULL on error. | |
| 301 * | |
| 302 * <pre> | |
| 303 * Notes: | |
| 304 * (1) See notes in pixScaleToGray() for the basic approach. | |
| 305 * (2) This function is considerably less expensive than pixScaleToGray() | |
| 306 * for scalefactor in the range (0.0625 ... 0.5), and the | |
| 307 * quality is nearly as good. | |
| 308 * (3) Unlike pixScaleToGray(), which does binary upscaling before | |
| 309 * downscaling for scale factors >= 0.0625, pixScaleToGrayFast() | |
| 310 * first downscales in binary for all scale factors < 0.5, and | |
| 311 * then does a 2x scale-to-gray as the final step. For | |
| 312 * scale factors < 0.0625, both do a 16x scale-to-gray, followed | |
| 313 * by further grayscale reduction. | |
| 314 * </pre> | |
| 315 */ | |
| 316 PIX * | |
| 317 pixScaleToGrayFast(PIX *pixs, | |
| 318 l_float32 scalefactor) | |
| 319 { | |
| 320 l_int32 w, h, minsrc, mindest; | |
| 321 l_float32 eps, factor; | |
| 322 PIX *pixt, *pixd; | |
| 323 | |
| 324 if (!pixs) | |
| 325 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 326 if (pixGetDepth(pixs) != 1) | |
| 327 return (PIX *)ERROR_PTR("pixs not 1 bpp", __func__, NULL); | |
| 328 if (scalefactor <= 0.0f) | |
| 329 return (PIX *)ERROR_PTR("scalefactor <= 0.0", __func__, NULL); | |
| 330 if (scalefactor >= 1.0f) | |
| 331 return (PIX *)ERROR_PTR("scalefactor >= 1.0", __func__, NULL); | |
| 332 pixGetDimensions(pixs, &w, &h, NULL); | |
| 333 minsrc = L_MIN(w, h); | |
| 334 mindest = (l_int32)((l_float32)minsrc * scalefactor); | |
| 335 if (mindest < 2) | |
| 336 return (PIX *)ERROR_PTR("scalefactor too small", __func__, NULL); | |
| 337 eps = 0.0001f; | |
| 338 | |
| 339 /* Handle the special cases */ | |
| 340 if (scalefactor > 0.5f - eps && scalefactor < 0.5f + eps) | |
| 341 return pixScaleToGray2(pixs); | |
| 342 else if (scalefactor > 0.33333f - eps && scalefactor < 0.33333f + eps) | |
| 343 return pixScaleToGray3(pixs); | |
| 344 else if (scalefactor > 0.25f - eps && scalefactor < 0.25f + eps) | |
| 345 return pixScaleToGray4(pixs); | |
| 346 else if (scalefactor > 0.16666f - eps && scalefactor < 0.16666f + eps) | |
| 347 return pixScaleToGray6(pixs); | |
| 348 else if (scalefactor > 0.125f - eps && scalefactor < 0.125f + eps) | |
| 349 return pixScaleToGray8(pixs); | |
| 350 else if (scalefactor > 0.0625f - eps && scalefactor < 0.0625f + eps) | |
| 351 return pixScaleToGray16(pixs); | |
| 352 | |
| 353 if (scalefactor > 0.0625f) { /* scale binary first */ | |
| 354 factor = 2.0f * scalefactor; | |
| 355 if ((pixt = pixScaleBinary(pixs, factor, factor)) == NULL) | |
| 356 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL); | |
| 357 pixd = pixScaleToGray2(pixt); | |
| 358 } else { /* scalefactor < 0.0625; scale-to-gray first */ | |
| 359 factor = 16.0f * scalefactor; /* will be < 1.0 */ | |
| 360 if ((pixt = pixScaleToGray16(pixs)) == NULL) | |
| 361 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL); | |
| 362 if (factor < 0.7f) | |
| 363 pixd = pixScaleSmooth(pixt, factor, factor); | |
| 364 else | |
| 365 pixd = pixScaleGrayLI(pixt, factor, factor); | |
| 366 } | |
| 367 pixDestroy(&pixt); | |
| 368 if (!pixd) | |
| 369 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 370 pixCopyInputFormat(pixd, pixs); | |
| 371 return pixd; | |
| 372 } | |
| 373 | |
| 374 | |
| 375 /*-----------------------------------------------------------------------* | |
| 376 * Scale-to-gray (1 bpp --> 8 bpp; integer downscaling) * | |
| 377 *-----------------------------------------------------------------------*/ | |
| 378 /*! | |
| 379 * \brief pixScaleToGray2() | |
| 380 * | |
| 381 * \param[in] pixs 1 bpp | |
| 382 * \return pixd 8 bpp, scaled down by 2x in each direction, | |
| 383 * or NULL on error. | |
| 384 */ | |
| 385 PIX * | |
| 386 pixScaleToGray2(PIX *pixs) | |
| 387 { | |
| 388 l_uint8 *valtab; | |
| 389 l_int32 ws, hs, wd, hd; | |
| 390 l_int32 wpld, wpls; | |
| 391 l_uint32 *sumtab; | |
| 392 l_uint32 *datas, *datad; | |
| 393 PIX *pixd; | |
| 394 | |
| 395 if (!pixs) | |
| 396 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 397 if (pixGetDepth(pixs) != 1) | |
| 398 return (PIX *)ERROR_PTR("pixs must be 1 bpp", __func__, NULL); | |
| 399 | |
| 400 pixGetDimensions(pixs, &ws, &hs, NULL); | |
| 401 wd = ws / 2; | |
| 402 hd = hs / 2; | |
| 403 if (wd == 0 || hd == 0) | |
| 404 return (PIX *)ERROR_PTR("pixs too small", __func__, NULL); | |
| 405 | |
| 406 if ((pixd = pixCreate(wd, hd, 8)) == NULL) | |
| 407 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 408 pixSetPadBits(pixs, 0); | |
| 409 pixCopyInputFormat(pixd, pixs); | |
| 410 pixCopyResolution(pixd, pixs); | |
| 411 pixScaleResolution(pixd, 0.5, 0.5); | |
| 412 datas = pixGetData(pixs); | |
| 413 datad = pixGetData(pixd); | |
| 414 wpls = pixGetWpl(pixs); | |
| 415 wpld = pixGetWpl(pixd); | |
| 416 | |
| 417 sumtab = makeSumTabSG2(); | |
| 418 valtab = makeValTabSG2(); | |
| 419 scaleToGray2Low(datad, wd, hd, wpld, datas, wpls, sumtab, valtab); | |
| 420 LEPT_FREE(sumtab); | |
| 421 LEPT_FREE(valtab); | |
| 422 return pixd; | |
| 423 } | |
| 424 | |
| 425 | |
| 426 /*! | |
| 427 * \brief pixScaleToGray3() | |
| 428 * | |
| 429 * \param[in] pixs 1 bpp | |
| 430 * \return pixd 8 bpp, scaled down by 3x in each direction, | |
| 431 * or NULL on error. | |
| 432 * | |
| 433 * <pre> | |
| 434 * Notes: | |
| 435 * (1) Speed is about 100 x 10^6 src-pixels/sec/GHz. | |
| 436 * Another way to express this is it processes 1 src pixel | |
| 437 * in about 10 cycles. | |
| 438 * (2) The width of pixd is truncated is truncated to a factor of 8. | |
| 439 * </pre> | |
| 440 */ | |
| 441 PIX * | |
| 442 pixScaleToGray3(PIX *pixs) | |
| 443 { | |
| 444 l_uint8 *valtab; | |
| 445 l_int32 ws, hs, wd, hd; | |
| 446 l_int32 wpld, wpls; | |
| 447 l_uint32 *sumtab; | |
| 448 l_uint32 *datas, *datad; | |
| 449 PIX *pixd; | |
| 450 | |
| 451 if (!pixs) | |
| 452 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 453 if (pixGetDepth(pixs) != 1) | |
| 454 return (PIX *)ERROR_PTR("pixs not 1 bpp", __func__, NULL); | |
| 455 | |
| 456 pixGetDimensions(pixs, &ws, &hs, NULL); | |
| 457 wd = (ws / 3) & 0xfffffff8; /* truncate to factor of 8 */ | |
| 458 hd = hs / 3; | |
| 459 if (wd == 0 || hd == 0) | |
| 460 return (PIX *)ERROR_PTR("pixs too small", __func__, NULL); | |
| 461 | |
| 462 if ((pixd = pixCreate(wd, hd, 8)) == NULL) | |
| 463 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 464 pixCopyInputFormat(pixd, pixs); | |
| 465 pixCopyResolution(pixd, pixs); | |
| 466 pixScaleResolution(pixd, 0.33333f, 0.33333f); | |
| 467 datas = pixGetData(pixs); | |
| 468 datad = pixGetData(pixd); | |
| 469 wpls = pixGetWpl(pixs); | |
| 470 wpld = pixGetWpl(pixd); | |
| 471 | |
| 472 sumtab = makeSumTabSG3(); | |
| 473 valtab = makeValTabSG3(); | |
| 474 scaleToGray3Low(datad, wd, hd, wpld, datas, wpls, sumtab, valtab); | |
| 475 LEPT_FREE(sumtab); | |
| 476 LEPT_FREE(valtab); | |
| 477 return pixd; | |
| 478 } | |
| 479 | |
| 480 | |
| 481 /*! | |
| 482 * \brief pixScaleToGray4() | |
| 483 * | |
| 484 * \param[in] pixs 1 bpp | |
| 485 * \return pixd 8 bpp, scaled down by 4x in each direction, | |
| 486 * or NULL on error. | |
| 487 * | |
| 488 * <pre> | |
| 489 * Notes: | |
| 490 * (1) The width of pixd is truncated is truncated to a factor of 2. | |
| 491 * </pre> | |
| 492 */ | |
| 493 PIX * | |
| 494 pixScaleToGray4(PIX *pixs) | |
| 495 { | |
| 496 l_uint8 *valtab; | |
| 497 l_int32 ws, hs, wd, hd; | |
| 498 l_int32 wpld, wpls; | |
| 499 l_uint32 *sumtab; | |
| 500 l_uint32 *datas, *datad; | |
| 501 PIX *pixd; | |
| 502 | |
| 503 if (!pixs) | |
| 504 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 505 if (pixGetDepth(pixs) != 1) | |
| 506 return (PIX *)ERROR_PTR("pixs must be 1 bpp", __func__, NULL); | |
| 507 | |
| 508 pixGetDimensions(pixs, &ws, &hs, NULL); | |
| 509 wd = (ws / 4) & 0xfffffffe; /* truncate to factor of 2 */ | |
| 510 hd = hs / 4; | |
| 511 if (wd == 0 || hd == 0) | |
| 512 return (PIX *)ERROR_PTR("pixs too small", __func__, NULL); | |
| 513 | |
| 514 if ((pixd = pixCreate(wd, hd, 8)) == NULL) | |
| 515 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 516 pixCopyInputFormat(pixd, pixs); | |
| 517 pixCopyResolution(pixd, pixs); | |
| 518 pixScaleResolution(pixd, 0.25, 0.25); | |
| 519 datas = pixGetData(pixs); | |
| 520 datad = pixGetData(pixd); | |
| 521 wpls = pixGetWpl(pixs); | |
| 522 wpld = pixGetWpl(pixd); | |
| 523 | |
| 524 sumtab = makeSumTabSG4(); | |
| 525 valtab = makeValTabSG4(); | |
| 526 scaleToGray4Low(datad, wd, hd, wpld, datas, wpls, sumtab, valtab); | |
| 527 LEPT_FREE(sumtab); | |
| 528 LEPT_FREE(valtab); | |
| 529 return pixd; | |
| 530 } | |
| 531 | |
| 532 | |
| 533 | |
| 534 /*! | |
| 535 * \brief pixScaleToGray6() | |
| 536 * | |
| 537 * \param[in] pixs 1 bpp | |
| 538 * \return pixd 8 bpp, scaled down by 6x in each direction, | |
| 539 * or NULL on error. | |
| 540 * | |
| 541 * <pre> | |
| 542 * Notes: | |
| 543 * (1) The width of pixd is truncated is truncated to a factor of 8. | |
| 544 * </pre> | |
| 545 */ | |
| 546 PIX * | |
| 547 pixScaleToGray6(PIX *pixs) | |
| 548 { | |
| 549 l_uint8 *valtab; | |
| 550 l_int32 ws, hs, wd, hd, wpld, wpls; | |
| 551 l_int32 *tab8; | |
| 552 l_uint32 *datas, *datad; | |
| 553 PIX *pixd; | |
| 554 | |
| 555 if (!pixs) | |
| 556 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 557 if (pixGetDepth(pixs) != 1) | |
| 558 return (PIX *)ERROR_PTR("pixs not 1 bpp", __func__, NULL); | |
| 559 | |
| 560 pixGetDimensions(pixs, &ws, &hs, NULL); | |
| 561 wd = (ws / 6) & 0xfffffff8; /* truncate to factor of 8 */ | |
| 562 hd = hs / 6; | |
| 563 if (wd == 0 || hd == 0) | |
| 564 return (PIX *)ERROR_PTR("pixs too small", __func__, NULL); | |
| 565 | |
| 566 if ((pixd = pixCreate(wd, hd, 8)) == NULL) | |
| 567 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 568 pixCopyInputFormat(pixd, pixs); | |
| 569 pixCopyResolution(pixd, pixs); | |
| 570 pixScaleResolution(pixd, 0.16667f, 0.16667f); | |
| 571 datas = pixGetData(pixs); | |
| 572 datad = pixGetData(pixd); | |
| 573 wpls = pixGetWpl(pixs); | |
| 574 wpld = pixGetWpl(pixd); | |
| 575 | |
| 576 tab8 = makePixelSumTab8(); | |
| 577 valtab = makeValTabSG6(); | |
| 578 scaleToGray6Low(datad, wd, hd, wpld, datas, wpls, tab8, valtab); | |
| 579 LEPT_FREE(tab8); | |
| 580 LEPT_FREE(valtab); | |
| 581 return pixd; | |
| 582 } | |
| 583 | |
| 584 | |
| 585 /*! | |
| 586 * \brief pixScaleToGray8() | |
| 587 * | |
| 588 * \param[in] pixs 1 bpp | |
| 589 * \return pixd 8 bpp, scaled down by 8x in each direction, | |
| 590 * or NULL on error | |
| 591 */ | |
| 592 PIX * | |
| 593 pixScaleToGray8(PIX *pixs) | |
| 594 { | |
| 595 l_uint8 *valtab; | |
| 596 l_int32 ws, hs, wd, hd; | |
| 597 l_int32 wpld, wpls; | |
| 598 l_int32 *tab8; | |
| 599 l_uint32 *datas, *datad; | |
| 600 PIX *pixd; | |
| 601 | |
| 602 if (!pixs) | |
| 603 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 604 if (pixGetDepth(pixs) != 1) | |
| 605 return (PIX *)ERROR_PTR("pixs must be 1 bpp", __func__, NULL); | |
| 606 | |
| 607 pixGetDimensions(pixs, &ws, &hs, NULL); | |
| 608 wd = ws / 8; /* truncate to nearest dest byte */ | |
| 609 hd = hs / 8; | |
| 610 if (wd == 0 || hd == 0) | |
| 611 return (PIX *)ERROR_PTR("pixs too small", __func__, NULL); | |
| 612 | |
| 613 if ((pixd = pixCreate(wd, hd, 8)) == NULL) | |
| 614 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 615 pixCopyInputFormat(pixd, pixs); | |
| 616 pixCopyResolution(pixd, pixs); | |
| 617 pixScaleResolution(pixd, 0.125, 0.125); | |
| 618 datas = pixGetData(pixs); | |
| 619 datad = pixGetData(pixd); | |
| 620 wpls = pixGetWpl(pixs); | |
| 621 wpld = pixGetWpl(pixd); | |
| 622 | |
| 623 tab8 = makePixelSumTab8(); | |
| 624 valtab = makeValTabSG8(); | |
| 625 scaleToGray8Low(datad, wd, hd, wpld, datas, wpls, tab8, valtab); | |
| 626 LEPT_FREE(tab8); | |
| 627 LEPT_FREE(valtab); | |
| 628 return pixd; | |
| 629 } | |
| 630 | |
| 631 | |
| 632 /*! | |
| 633 * \brief pixScaleToGray16() | |
| 634 * | |
| 635 * \param[in] pixs 1 bpp | |
| 636 * \return pixd 8 bpp, scaled down by 16x in each direction, | |
| 637 * or NULL on error. | |
| 638 */ | |
| 639 PIX * | |
| 640 pixScaleToGray16(PIX *pixs) | |
| 641 { | |
| 642 l_int32 ws, hs, wd, hd; | |
| 643 l_int32 wpld, wpls; | |
| 644 l_int32 *tab8; | |
| 645 l_uint32 *datas, *datad; | |
| 646 PIX *pixd; | |
| 647 | |
| 648 if (!pixs) | |
| 649 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 650 if (pixGetDepth(pixs) != 1) | |
| 651 return (PIX *)ERROR_PTR("pixs must be 1 bpp", __func__, NULL); | |
| 652 | |
| 653 pixGetDimensions(pixs, &ws, &hs, NULL); | |
| 654 wd = ws / 16; | |
| 655 hd = hs / 16; | |
| 656 if (wd == 0 || hd == 0) | |
| 657 return (PIX *)ERROR_PTR("pixs too small", __func__, NULL); | |
| 658 | |
| 659 if ((pixd = pixCreate(wd, hd, 8)) == NULL) | |
| 660 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 661 pixCopyInputFormat(pixd, pixs); | |
| 662 pixCopyResolution(pixd, pixs); | |
| 663 pixScaleResolution(pixd, 0.0625, 0.0625); | |
| 664 datas = pixGetData(pixs); | |
| 665 datad = pixGetData(pixd); | |
| 666 wpls = pixGetWpl(pixs); | |
| 667 wpld = pixGetWpl(pixd); | |
| 668 | |
| 669 tab8 = makePixelSumTab8(); | |
| 670 scaleToGray16Low(datad, wd, hd, wpld, datas, wpls, tab8); | |
| 671 LEPT_FREE(tab8); | |
| 672 return pixd; | |
| 673 } | |
| 674 | |
| 675 | |
| 676 /*------------------------------------------------------------------* | |
| 677 * Scale-to-gray mipmap(1 bpp --> 8 bpp, arbitrary reduction) * | |
| 678 *------------------------------------------------------------------*/ | |
| 679 /*! | |
| 680 * \brief pixScaleToGrayMipmap() | |
| 681 * | |
| 682 * \param[in] pixs 1 bpp | |
| 683 * \param[in] scalefactor reduction: must be > 0.0 and < 1.0 | |
| 684 * \return pixd 8 bpp, scaled down by scalefactor in each direction, | |
| 685 * or NULL on error. | |
| 686 * | |
| 687 * <pre> | |
| 688 * Notes: | |
| 689 * | |
| 690 * This function is here mainly for pedagogical reasons. | |
| 691 * Mip-mapping is widely used in graphics for texture mapping, because | |
| 692 * the texture changes smoothly with scale. This is accomplished by | |
| 693 * constructing a multiresolution pyramid and, for each pixel, | |
| 694 * doing a linear interpolation between corresponding pixels in | |
| 695 * the two planes of the pyramid that bracket the desired resolution. | |
| 696 * The computation is very efficient, and is implemented in hardware | |
| 697 * in high-end graphics cards. | |
| 698 * | |
| 699 * We can use mip-mapping for scale-to-gray by using two scale-to-gray | |
| 700 * reduced images (we don't need the entire pyramid) selected from | |
| 701 * the set {2x, 4x, ... 16x}, and interpolating. However, we get | |
| 702 * severe aliasing, probably because we are subsampling from the | |
| 703 * higher resolution image. The method is very fast, but the result | |
| 704 * is very poor. In fact, the results don't look any better than | |
| 705 * either subsampling off the higher-res grayscale image or oversampling | |
| 706 * on the lower-res image. Consequently, this method should NOT be used | |
| 707 * for generating reduced images, scale-to-gray or otherwise. | |
| 708 * </pre> | |
| 709 */ | |
| 710 PIX * | |
| 711 pixScaleToGrayMipmap(PIX *pixs, | |
| 712 l_float32 scalefactor) | |
| 713 { | |
| 714 l_int32 w, h, minsrc, mindest; | |
| 715 l_float32 red; | |
| 716 PIX *pixs1, *pixs2, *pixt, *pixd; | |
| 717 | |
| 718 if (!pixs) | |
| 719 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 720 if (pixGetDepth(pixs) != 1) | |
| 721 return (PIX *)ERROR_PTR("pixs not 1 bpp", __func__, NULL); | |
| 722 if (scalefactor <= 0.0) | |
| 723 return (PIX *)ERROR_PTR("scalefactor <= 0.0", __func__, NULL); | |
| 724 if (scalefactor >= 1.0) | |
| 725 return (PIX *)ERROR_PTR("scalefactor >= 1.0", __func__, NULL); | |
| 726 pixGetDimensions(pixs, &w, &h, NULL); | |
| 727 minsrc = L_MIN(w, h); | |
| 728 mindest = (l_int32)((l_float32)minsrc * scalefactor); | |
| 729 if (mindest < 2) | |
| 730 return (PIX *)ERROR_PTR("scalefactor too small", __func__, NULL); | |
| 731 | |
| 732 if (scalefactor > 0.5) { | |
| 733 pixs1 = pixConvert1To8(NULL, pixs, 255, 0); | |
| 734 pixs2 = pixScaleToGray2(pixs); | |
| 735 red = scalefactor; | |
| 736 } else if (scalefactor == 0.5) { | |
| 737 return pixScaleToGray2(pixs); | |
| 738 } else if (scalefactor > 0.25) { | |
| 739 pixs1 = pixScaleToGray2(pixs); | |
| 740 pixs2 = pixScaleToGray4(pixs); | |
| 741 red = 2.f * scalefactor; | |
| 742 } else if (scalefactor == 0.25) { | |
| 743 return pixScaleToGray4(pixs); | |
| 744 } else if (scalefactor > 0.125) { | |
| 745 pixs1 = pixScaleToGray4(pixs); | |
| 746 pixs2 = pixScaleToGray8(pixs); | |
| 747 red = 4.f * scalefactor; | |
| 748 } else if (scalefactor == 0.125) { | |
| 749 return pixScaleToGray8(pixs); | |
| 750 } else if (scalefactor > 0.0625) { | |
| 751 pixs1 = pixScaleToGray8(pixs); | |
| 752 pixs2 = pixScaleToGray16(pixs); | |
| 753 red = 8.f * scalefactor; | |
| 754 } else if (scalefactor == 0.0625) { | |
| 755 return pixScaleToGray16(pixs); | |
| 756 } else { /* end of the pyramid; just do it */ | |
| 757 red = 16.0f * scalefactor; /* will be <= 1.0 */ | |
| 758 if ((pixt = pixScaleToGray16(pixs)) == NULL) | |
| 759 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL); | |
| 760 if (red < 0.7) | |
| 761 pixd = pixScaleSmooth(pixt, red, red); | |
| 762 else | |
| 763 pixd = pixScaleGrayLI(pixt, red, red); | |
| 764 pixDestroy(&pixt); | |
| 765 return pixd; | |
| 766 } | |
| 767 | |
| 768 pixd = pixScaleMipmap(pixs1, pixs2, red); | |
| 769 pixCopyInputFormat(pixd, pixs); | |
| 770 | |
| 771 pixDestroy(&pixs1); | |
| 772 pixDestroy(&pixs2); | |
| 773 return pixd; | |
| 774 } | |
| 775 | |
| 776 | |
| 777 /*------------------------------------------------------------------* | |
| 778 * Grayscale scaling using mipmap * | |
| 779 *------------------------------------------------------------------*/ | |
| 780 /*! | |
| 781 * \brief pixScaleMipmap() | |
| 782 * | |
| 783 * \param[in] pixs1 high res 8 bpp, no cmap | |
| 784 * \param[in] pixs2 low res -- 2x reduced -- 8 bpp, no cmap | |
| 785 * \param[in] scale reduction with respect to high res image, > 0.5 | |
| 786 * \return 8 bpp pix, scaled down by reduction in each direction, | |
| 787 * or NULL on error. | |
| 788 * | |
| 789 * <pre> | |
| 790 * Notes: | |
| 791 * (1) See notes in pixScaleToGrayMipmap(). | |
| 792 * (2) This function suffers from aliasing effects that are | |
| 793 * easily seen in document images. | |
| 794 * </pre> | |
| 795 */ | |
| 796 PIX * | |
| 797 pixScaleMipmap(PIX *pixs1, | |
| 798 PIX *pixs2, | |
| 799 l_float32 scale) | |
| 800 { | |
| 801 l_int32 ws1, hs1, ws2, hs2, wd, hd, wpls1, wpls2, wpld; | |
| 802 l_uint32 *datas1, *datas2, *datad; | |
| 803 PIX *pixd; | |
| 804 | |
| 805 if (!pixs1 || pixGetDepth(pixs1) != 8 || pixGetColormap(pixs1)) | |
| 806 return (PIX *)ERROR_PTR("pixs1 underdefined, not 8 bpp, or cmapped", | |
| 807 __func__, NULL); | |
| 808 if (!pixs2 || pixGetDepth(pixs2) != 8 || pixGetColormap(pixs2)) | |
| 809 return (PIX *)ERROR_PTR("pixs2 underdefined, not 8 bpp, or cmapped", | |
| 810 __func__, NULL); | |
| 811 pixGetDimensions(pixs1, &ws1, &hs1, NULL); | |
| 812 pixGetDimensions(pixs2, &ws2, &hs2, NULL); | |
| 813 if (scale > 1.0 || scale < 0.5) | |
| 814 return (PIX *)ERROR_PTR("scale not in [0.5, 1.0]", __func__, NULL); | |
| 815 if (ws1 < 2 * ws2) | |
| 816 return (PIX *)ERROR_PTR("invalid width ratio", __func__, NULL); | |
| 817 if (hs1 < 2 * hs2) | |
| 818 return (PIX *)ERROR_PTR("invalid height ratio", __func__, NULL); | |
| 819 | |
| 820 /* Generate wd and hd from the lower resolution dimensions, | |
| 821 * to guarantee staying within both src images */ | |
| 822 datas1 = pixGetData(pixs1); | |
| 823 wpls1 = pixGetWpl(pixs1); | |
| 824 datas2 = pixGetData(pixs2); | |
| 825 wpls2 = pixGetWpl(pixs2); | |
| 826 wd = (l_int32)(2. * scale * pixGetWidth(pixs2)); | |
| 827 hd = (l_int32)(2. * scale * pixGetHeight(pixs2)); | |
| 828 if ((pixd = pixCreate(wd, hd, 8)) == NULL) | |
| 829 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 830 pixCopyInputFormat(pixd, pixs1); | |
| 831 pixCopyResolution(pixd, pixs1); | |
| 832 pixScaleResolution(pixd, scale, scale); | |
| 833 datad = pixGetData(pixd); | |
| 834 wpld = pixGetWpl(pixd); | |
| 835 | |
| 836 scaleMipmapLow(datad, wd, hd, wpld, datas1, wpls1, datas2, wpls2, scale); | |
| 837 return pixd; | |
| 838 } | |
| 839 | |
| 840 | |
| 841 /*------------------------------------------------------------------* | |
| 842 * Replicated (integer) expansion * | |
| 843 *------------------------------------------------------------------*/ | |
| 844 /*! | |
| 845 * \brief pixExpandReplicate() | |
| 846 * | |
| 847 * \param[in] pixs 1, 2, 4, 8, 16, 32 bpp | |
| 848 * \param[in] factor integer scale factor for replicative expansion | |
| 849 * \return pixd scaled up, or NULL on error. | |
| 850 */ | |
| 851 PIX * | |
| 852 pixExpandReplicate(PIX *pixs, | |
| 853 l_int32 factor) | |
| 854 { | |
| 855 l_int32 w, h, d, wd, hd, wpls, wpld, start, i, j, k; | |
| 856 l_uint8 sval; | |
| 857 l_uint16 sval16; | |
| 858 l_uint32 sval32; | |
| 859 l_uint32 *lines, *datas, *lined, *datad; | |
| 860 PIX *pixd; | |
| 861 | |
| 862 if (!pixs) | |
| 863 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 864 pixGetDimensions(pixs, &w, &h, &d); | |
| 865 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32) | |
| 866 return (PIX *)ERROR_PTR("depth not in {1,2,4,8,16,32}", __func__, NULL); | |
| 867 if (factor <= 0) | |
| 868 return (PIX *)ERROR_PTR("factor <= 0; invalid", __func__, NULL); | |
| 869 if (factor == 1) | |
| 870 return pixCopy(NULL, pixs); | |
| 871 | |
| 872 if (d == 1) | |
| 873 return pixExpandBinaryReplicate(pixs, factor, factor); | |
| 874 | |
| 875 wd = factor * w; | |
| 876 hd = factor * h; | |
| 877 if ((pixd = pixCreate(wd, hd, d)) == NULL) | |
| 878 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 879 pixCopyColormap(pixd, pixs); | |
| 880 pixCopyInputFormat(pixd, pixs); | |
| 881 pixCopyResolution(pixd, pixs); | |
| 882 pixScaleResolution(pixd, (l_float32)factor, (l_float32)factor); | |
| 883 datas = pixGetData(pixs); | |
| 884 wpls = pixGetWpl(pixs); | |
| 885 datad = pixGetData(pixd); | |
| 886 wpld = pixGetWpl(pixd); | |
| 887 | |
| 888 switch (d) { | |
| 889 case 2: | |
| 890 for (i = 0; i < h; i++) { | |
| 891 lines = datas + i * wpls; | |
| 892 lined = datad + factor * i * wpld; | |
| 893 for (j = 0; j < w; j++) { | |
| 894 sval = GET_DATA_DIBIT(lines, j); | |
| 895 start = factor * j; | |
| 896 for (k = 0; k < factor; k++) | |
| 897 SET_DATA_DIBIT(lined, start + k, sval); | |
| 898 } | |
| 899 for (k = 1; k < factor; k++) | |
| 900 memcpy(lined + k * wpld, lined, 4 * wpld); | |
| 901 } | |
| 902 break; | |
| 903 case 4: | |
| 904 for (i = 0; i < h; i++) { | |
| 905 lines = datas + i * wpls; | |
| 906 lined = datad + factor * i * wpld; | |
| 907 for (j = 0; j < w; j++) { | |
| 908 sval = GET_DATA_QBIT(lines, j); | |
| 909 start = factor * j; | |
| 910 for (k = 0; k < factor; k++) | |
| 911 SET_DATA_QBIT(lined, start + k, sval); | |
| 912 } | |
| 913 for (k = 1; k < factor; k++) | |
| 914 memcpy(lined + k * wpld, lined, 4 * wpld); | |
| 915 } | |
| 916 break; | |
| 917 case 8: | |
| 918 for (i = 0; i < h; i++) { | |
| 919 lines = datas + i * wpls; | |
| 920 lined = datad + factor * i * wpld; | |
| 921 for (j = 0; j < w; j++) { | |
| 922 sval = GET_DATA_BYTE(lines, j); | |
| 923 start = factor * j; | |
| 924 for (k = 0; k < factor; k++) | |
| 925 SET_DATA_BYTE(lined, start + k, sval); | |
| 926 } | |
| 927 for (k = 1; k < factor; k++) | |
| 928 memcpy(lined + k * wpld, lined, 4 * wpld); | |
| 929 } | |
| 930 break; | |
| 931 case 16: | |
| 932 for (i = 0; i < h; i++) { | |
| 933 lines = datas + i * wpls; | |
| 934 lined = datad + factor * i * wpld; | |
| 935 for (j = 0; j < w; j++) { | |
| 936 sval16 = GET_DATA_TWO_BYTES(lines, j); | |
| 937 start = factor * j; | |
| 938 for (k = 0; k < factor; k++) | |
| 939 SET_DATA_TWO_BYTES(lined, start + k, sval16); | |
| 940 } | |
| 941 for (k = 1; k < factor; k++) | |
| 942 memcpy(lined + k * wpld, lined, 4 * wpld); | |
| 943 } | |
| 944 break; | |
| 945 case 32: | |
| 946 for (i = 0; i < h; i++) { | |
| 947 lines = datas + i * wpls; | |
| 948 lined = datad + factor * i * wpld; | |
| 949 for (j = 0; j < w; j++) { | |
| 950 sval32 = *(lines + j); | |
| 951 start = factor * j; | |
| 952 for (k = 0; k < factor; k++) | |
| 953 *(lined + start + k) = sval32; | |
| 954 } | |
| 955 for (k = 1; k < factor; k++) | |
| 956 memcpy(lined + k * wpld, lined, 4 * wpld); | |
| 957 } | |
| 958 break; | |
| 959 default: | |
| 960 lept_stderr("invalid depth\n"); | |
| 961 } | |
| 962 | |
| 963 if (d == 32 && pixGetSpp(pixs) == 4) | |
| 964 pixScaleAndTransferAlpha(pixd, pixs, (l_float32)factor, | |
| 965 (l_float32)factor); | |
| 966 return pixd; | |
| 967 } | |
| 968 | |
| 969 | |
| 970 /*-----------------------------------------------------------------------* | |
| 971 * Downscaling using min or max * | |
| 972 *-----------------------------------------------------------------------*/ | |
| 973 /*! | |
| 974 * \brief pixScaleGrayMinMax() | |
| 975 * | |
| 976 * \param[in] pixs 8 bpp, not cmapped | |
| 977 * \param[in] xfact x downscaling factor; integer | |
| 978 * \param[in] yfact y downscaling factor; integer | |
| 979 * \param[in] type L_CHOOSE_MIN, L_CHOOSE_MAX, L_CHOOSE_MAXDIFF | |
| 980 * \return pixd 8 bpp | |
| 981 * | |
| 982 * <pre> | |
| 983 * Notes: | |
| 984 * (1) The downscaled pixels in pixd are the min, max or (max - min) | |
| 985 * of the corresponding set of xfact * yfact pixels in pixs. | |
| 986 * (2) Using L_CHOOSE_MIN is equivalent to a grayscale erosion, | |
| 987 * using a brick Sel of size (xfact * yfact), followed by | |
| 988 * subsampling within each (xfact * yfact) cell. Using | |
| 989 * L_CHOOSE_MAX is equivalent to the corresponding dilation. | |
| 990 * (3) Using L_CHOOSE_MAXDIFF finds the difference between max | |
| 991 * and min values in each cell. | |
| 992 * (4) For the special case of downscaling by 2x in both directions, | |
| 993 * pixScaleGrayMinMax2() is about 2x more efficient. | |
| 994 * </pre> | |
| 995 */ | |
| 996 PIX * | |
| 997 pixScaleGrayMinMax(PIX *pixs, | |
| 998 l_int32 xfact, | |
| 999 l_int32 yfact, | |
| 1000 l_int32 type) | |
| 1001 { | |
| 1002 l_int32 ws, hs, wd, hd, wpls, wpld, i, j, k, m; | |
| 1003 l_int32 minval, maxval, val; | |
| 1004 l_uint32 *datas, *datad, *lines, *lined; | |
| 1005 PIX *pixd; | |
| 1006 | |
| 1007 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs)) | |
| 1008 return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped", | |
| 1009 __func__, NULL); | |
| 1010 pixGetDimensions(pixs, &ws, &hs, NULL); | |
| 1011 if (type != L_CHOOSE_MIN && type != L_CHOOSE_MAX && | |
| 1012 type != L_CHOOSE_MAXDIFF) | |
| 1013 return (PIX *)ERROR_PTR("invalid type", __func__, NULL); | |
| 1014 if (xfact < 1 || yfact < 1) | |
| 1015 return (PIX *)ERROR_PTR("xfact and yfact must be >= 1", __func__, NULL); | |
| 1016 | |
| 1017 if (xfact == 2 && yfact == 2) | |
| 1018 return pixScaleGrayMinMax2(pixs, type); | |
| 1019 | |
| 1020 wd = ws / xfact; | |
| 1021 if (wd == 0) { /* single tile */ | |
| 1022 wd = 1; | |
| 1023 xfact = ws; | |
| 1024 } | |
| 1025 hd = hs / yfact; | |
| 1026 if (hd == 0) { /* single tile */ | |
| 1027 hd = 1; | |
| 1028 yfact = hs; | |
| 1029 } | |
| 1030 if ((pixd = pixCreate(wd, hd, 8)) == NULL) | |
| 1031 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 1032 pixCopyInputFormat(pixd, pixs); | |
| 1033 datas = pixGetData(pixs); | |
| 1034 datad = pixGetData(pixd); | |
| 1035 wpls = pixGetWpl(pixs); | |
| 1036 wpld = pixGetWpl(pixd); | |
| 1037 for (i = 0; i < hd; i++) { | |
| 1038 lined = datad + i * wpld; | |
| 1039 for (j = 0; j < wd; j++) { | |
| 1040 if (type == L_CHOOSE_MIN || type == L_CHOOSE_MAXDIFF) { | |
| 1041 minval = 255; | |
| 1042 for (k = 0; k < yfact; k++) { | |
| 1043 lines = datas + (yfact * i + k) * wpls; | |
| 1044 for (m = 0; m < xfact; m++) { | |
| 1045 val = GET_DATA_BYTE(lines, xfact * j + m); | |
| 1046 if (val < minval) | |
| 1047 minval = val; | |
| 1048 } | |
| 1049 } | |
| 1050 } | |
| 1051 if (type == L_CHOOSE_MAX || type == L_CHOOSE_MAXDIFF) { | |
| 1052 maxval = 0; | |
| 1053 for (k = 0; k < yfact; k++) { | |
| 1054 lines = datas + (yfact * i + k) * wpls; | |
| 1055 for (m = 0; m < xfact; m++) { | |
| 1056 val = GET_DATA_BYTE(lines, xfact * j + m); | |
| 1057 if (val > maxval) | |
| 1058 maxval = val; | |
| 1059 } | |
| 1060 } | |
| 1061 } | |
| 1062 if (type == L_CHOOSE_MIN) | |
| 1063 SET_DATA_BYTE(lined, j, minval); | |
| 1064 else if (type == L_CHOOSE_MAX) | |
| 1065 SET_DATA_BYTE(lined, j, maxval); | |
| 1066 else /* type == L_CHOOSE_MAXDIFF */ | |
| 1067 SET_DATA_BYTE(lined, j, maxval - minval); | |
| 1068 } | |
| 1069 } | |
| 1070 | |
| 1071 return pixd; | |
| 1072 } | |
| 1073 | |
| 1074 | |
| 1075 /*! | |
| 1076 * \brief pixScaleGrayMinMax2() | |
| 1077 * | |
| 1078 * \param[in] pixs 8 bpp, not cmapped | |
| 1079 * \param[in] type L_CHOOSE_MIN, L_CHOOSE_MAX, L_CHOOSE_MAXDIFF | |
| 1080 * \return pixd 8 bpp downscaled by 2x | |
| 1081 * | |
| 1082 * <pre> | |
| 1083 * Notes: | |
| 1084 * (1) Special version for 2x reduction. The downscaled pixels | |
| 1085 * in pixd are the min, max or (max - min) of the corresponding | |
| 1086 * set of 4 pixels in pixs. | |
| 1087 * (2) The max and min operations are a special case (for levels 1 | |
| 1088 * and 4) of grayscale analog to the binary rank scaling operation | |
| 1089 * pixReduceRankBinary2(). Note, however, that because of | |
| 1090 * the photometric definition that higher gray values are | |
| 1091 * lighter, the erosion-like L_CHOOSE_MIN will darken | |
| 1092 * the resulting image, corresponding to a threshold level 1 | |
| 1093 * in the binary case. Likewise, L_CHOOSE_MAX will lighten | |
| 1094 * the pixd, corresponding to a threshold level of 4. | |
| 1095 * (3) To choose any of the four rank levels in a 2x grayscale | |
| 1096 * reduction, use pixScaleGrayRank2(). | |
| 1097 * (4) This runs at about 70 MPix/sec/GHz of source data for | |
| 1098 * erosion and dilation. | |
| 1099 * </pre> | |
| 1100 */ | |
| 1101 PIX * | |
| 1102 pixScaleGrayMinMax2(PIX *pixs, | |
| 1103 l_int32 type) | |
| 1104 { | |
| 1105 l_int32 ws, hs, wd, hd, wpls, wpld, i, j, k; | |
| 1106 l_int32 minval, maxval; | |
| 1107 l_int32 val[4]; | |
| 1108 l_uint32 *datas, *datad, *lines, *lined; | |
| 1109 PIX *pixd; | |
| 1110 | |
| 1111 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs)) | |
| 1112 return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped", | |
| 1113 __func__, NULL); | |
| 1114 pixGetDimensions(pixs, &ws, &hs, NULL); | |
| 1115 if (ws < 2 || hs < 2) | |
| 1116 return (PIX *)ERROR_PTR("too small: ws < 2 or hs < 2", __func__, NULL); | |
| 1117 if (type != L_CHOOSE_MIN && type != L_CHOOSE_MAX && | |
| 1118 type != L_CHOOSE_MAXDIFF) | |
| 1119 return (PIX *)ERROR_PTR("invalid type", __func__, NULL); | |
| 1120 | |
| 1121 wd = ws / 2; | |
| 1122 hd = hs / 2; | |
| 1123 if ((pixd = pixCreate(wd, hd, 8)) == NULL) | |
| 1124 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 1125 pixCopyInputFormat(pixd, pixs); | |
| 1126 datas = pixGetData(pixs); | |
| 1127 datad = pixGetData(pixd); | |
| 1128 wpls = pixGetWpl(pixs); | |
| 1129 wpld = pixGetWpl(pixd); | |
| 1130 for (i = 0; i < hd; i++) { | |
| 1131 lines = datas + 2 * i * wpls; | |
| 1132 lined = datad + i * wpld; | |
| 1133 for (j = 0; j < wd; j++) { | |
| 1134 val[0] = GET_DATA_BYTE(lines, 2 * j); | |
| 1135 val[1] = GET_DATA_BYTE(lines, 2 * j + 1); | |
| 1136 val[2] = GET_DATA_BYTE(lines + wpls, 2 * j); | |
| 1137 val[3] = GET_DATA_BYTE(lines + wpls, 2 * j + 1); | |
| 1138 if (type == L_CHOOSE_MIN || type == L_CHOOSE_MAXDIFF) { | |
| 1139 minval = 255; | |
| 1140 for (k = 0; k < 4; k++) { | |
| 1141 if (val[k] < minval) | |
| 1142 minval = val[k]; | |
| 1143 } | |
| 1144 } | |
| 1145 if (type == L_CHOOSE_MAX || type == L_CHOOSE_MAXDIFF) { | |
| 1146 maxval = 0; | |
| 1147 for (k = 0; k < 4; k++) { | |
| 1148 if (val[k] > maxval) | |
| 1149 maxval = val[k]; | |
| 1150 } | |
| 1151 } | |
| 1152 if (type == L_CHOOSE_MIN) | |
| 1153 SET_DATA_BYTE(lined, j, minval); | |
| 1154 else if (type == L_CHOOSE_MAX) | |
| 1155 SET_DATA_BYTE(lined, j, maxval); | |
| 1156 else /* type == L_CHOOSE_MAXDIFF */ | |
| 1157 SET_DATA_BYTE(lined, j, maxval - minval); | |
| 1158 } | |
| 1159 } | |
| 1160 | |
| 1161 return pixd; | |
| 1162 } | |
| 1163 | |
| 1164 | |
| 1165 /*-----------------------------------------------------------------------* | |
| 1166 * Grayscale downscaling using rank value * | |
| 1167 *-----------------------------------------------------------------------*/ | |
| 1168 /*! | |
| 1169 * \brief pixScaleGrayRankCascade() | |
| 1170 * | |
| 1171 * \param[in] pixs 8 bpp, not cmapped | |
| 1172 * \param[in] level1, level2 ... | |
| 1173 * \param[in] level3, level4 rank thresholds, in set {0, 1, 2, 3, 4} | |
| 1174 * \return pixd 8 bpp, downscaled by up to 16x | |
| 1175 * | |
| 1176 * <pre> | |
| 1177 * Notes: | |
| 1178 * (1) This performs up to four cascaded 2x rank reductions. | |
| 1179 * (2) Use level = 0 to truncate the cascade. | |
| 1180 * </pre> | |
| 1181 */ | |
| 1182 PIX * | |
| 1183 pixScaleGrayRankCascade(PIX *pixs, | |
| 1184 l_int32 level1, | |
| 1185 l_int32 level2, | |
| 1186 l_int32 level3, | |
| 1187 l_int32 level4) | |
| 1188 { | |
| 1189 PIX *pixt1, *pixt2, *pixt3, *pixt4; | |
| 1190 | |
| 1191 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs)) | |
| 1192 return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped", | |
| 1193 __func__, NULL); | |
| 1194 if (level1 > 4 || level2 > 4 || level3 > 4 || level4 > 4) | |
| 1195 return (PIX *)ERROR_PTR("levels must not exceed 4", __func__, NULL); | |
| 1196 | |
| 1197 if (level1 <= 0) { | |
| 1198 L_WARNING("no reduction because level1 not > 0\n", __func__); | |
| 1199 return pixCopy(NULL, pixs); | |
| 1200 } | |
| 1201 | |
| 1202 pixt1 = pixScaleGrayRank2(pixs, level1); | |
| 1203 if (level2 <= 0) | |
| 1204 return pixt1; | |
| 1205 | |
| 1206 pixt2 = pixScaleGrayRank2(pixt1, level2); | |
| 1207 pixDestroy(&pixt1); | |
| 1208 if (level3 <= 0) | |
| 1209 return pixt2; | |
| 1210 | |
| 1211 pixt3 = pixScaleGrayRank2(pixt2, level3); | |
| 1212 pixDestroy(&pixt2); | |
| 1213 if (level4 <= 0) | |
| 1214 return pixt3; | |
| 1215 | |
| 1216 pixt4 = pixScaleGrayRank2(pixt3, level4); | |
| 1217 pixDestroy(&pixt3); | |
| 1218 return pixt4; | |
| 1219 } | |
| 1220 | |
| 1221 | |
| 1222 /*! | |
| 1223 * \brief pixScaleGrayRank2() | |
| 1224 * | |
| 1225 * \param[in] pixs 8 bpp, no cmap | |
| 1226 * \param[in] rank 1 (darkest), 2, 3, 4 (lightest) | |
| 1227 * \return pixd 8 bpp, downscaled by 2x | |
| 1228 * | |
| 1229 * <pre> | |
| 1230 * Notes: | |
| 1231 * (1) Rank 2x reduction. If rank == 1(4), the downscaled pixels | |
| 1232 * in pixd are the min(max) of the corresponding set of | |
| 1233 * 4 pixels in pixs. Values 2 and 3 are intermediate. | |
| 1234 * (2) This is the grayscale analog to the binary rank scaling operation | |
| 1235 * pixReduceRankBinary2(). Here, because of the photometric | |
| 1236 * definition that higher gray values are lighter, rank 1 gives | |
| 1237 * the darkest pixel, whereas rank 4 gives the lightest pixel. | |
| 1238 * This is opposite to the binary rank operation. | |
| 1239 * (3) For rank = 1 and 4, this calls pixScaleGrayMinMax2(), | |
| 1240 * which runs at about 70 MPix/sec/GHz of source data. | |
| 1241 * For rank 2 and 3, this runs 3x slower, at about 25 MPix/sec/GHz. | |
| 1242 * </pre> | |
| 1243 */ | |
| 1244 PIX * | |
| 1245 pixScaleGrayRank2(PIX *pixs, | |
| 1246 l_int32 rank) | |
| 1247 { | |
| 1248 l_int32 ws, hs, wd, hd, wpls, wpld, i, j, k, m; | |
| 1249 l_int32 minval, maxval, rankval, minindex, maxindex; | |
| 1250 l_int32 val[4]; | |
| 1251 l_int32 midval[4]; /* should only use 2 of these */ | |
| 1252 l_uint32 *datas, *datad, *lines, *lined; | |
| 1253 PIX *pixd; | |
| 1254 | |
| 1255 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs)) | |
| 1256 return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped", | |
| 1257 __func__, NULL); | |
| 1258 if (rank < 1 || rank > 4) | |
| 1259 return (PIX *)ERROR_PTR("invalid rank", __func__, NULL); | |
| 1260 | |
| 1261 if (rank == 1) | |
| 1262 return pixScaleGrayMinMax2(pixs, L_CHOOSE_MIN); | |
| 1263 if (rank == 4) | |
| 1264 return pixScaleGrayMinMax2(pixs, L_CHOOSE_MAX); | |
| 1265 | |
| 1266 pixGetDimensions(pixs, &ws, &hs, NULL); | |
| 1267 wd = ws / 2; | |
| 1268 hd = hs / 2; | |
| 1269 if ((pixd = pixCreate(wd, hd, 8)) == NULL) | |
| 1270 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 1271 pixCopyInputFormat(pixd, pixs); | |
| 1272 datas = pixGetData(pixs); | |
| 1273 datad = pixGetData(pixd); | |
| 1274 wpls = pixGetWpl(pixs); | |
| 1275 wpld = pixGetWpl(pixd); | |
| 1276 for (i = 0; i < hd; i++) { | |
| 1277 lines = datas + 2 * i * wpls; | |
| 1278 lined = datad + i * wpld; | |
| 1279 for (j = 0; j < wd; j++) { | |
| 1280 val[0] = GET_DATA_BYTE(lines, 2 * j); | |
| 1281 val[1] = GET_DATA_BYTE(lines, 2 * j + 1); | |
| 1282 val[2] = GET_DATA_BYTE(lines + wpls, 2 * j); | |
| 1283 val[3] = GET_DATA_BYTE(lines + wpls, 2 * j + 1); | |
| 1284 minval = maxval = val[0]; | |
| 1285 minindex = maxindex = 0; | |
| 1286 for (k = 1; k < 4; k++) { | |
| 1287 if (val[k] < minval) { | |
| 1288 minval = val[k]; | |
| 1289 minindex = k; | |
| 1290 continue; | |
| 1291 } | |
| 1292 if (val[k] > maxval) { | |
| 1293 maxval = val[k]; | |
| 1294 maxindex = k; | |
| 1295 } | |
| 1296 } | |
| 1297 for (k = 0, m = 0; k < 4; k++) { | |
| 1298 if (k == minindex || k == maxindex) | |
| 1299 continue; | |
| 1300 midval[m++] = val[k]; | |
| 1301 } | |
| 1302 if (m > 2) /* minval == maxval; all val[k] are the same */ | |
| 1303 rankval = minval; | |
| 1304 else if (rank == 2) | |
| 1305 rankval = L_MIN(midval[0], midval[1]); | |
| 1306 else /* rank == 3 */ | |
| 1307 rankval = L_MAX(midval[0], midval[1]); | |
| 1308 SET_DATA_BYTE(lined, j, rankval); | |
| 1309 } | |
| 1310 } | |
| 1311 | |
| 1312 return pixd; | |
| 1313 } | |
| 1314 | |
| 1315 | |
| 1316 /*------------------------------------------------------------------------* | |
| 1317 * Helper function for transferring alpha with scaling * | |
| 1318 *------------------------------------------------------------------------*/ | |
| 1319 /*! | |
| 1320 * \brief pixScaleAndTransferAlpha() | |
| 1321 * | |
| 1322 * \param[in] pixd 32 bpp, scaled image | |
| 1323 * \param[in] pixs 32 bpp, original unscaled image | |
| 1324 * \param[in] scalex must be > 0.0 | |
| 1325 * \param[in] scaley must be > 0.0 | |
| 1326 * \return 0 if OK; 1 on error | |
| 1327 * | |
| 1328 * <pre> | |
| 1329 * Notes: | |
| 1330 * (1) This scales the alpha component of pixs and inserts into pixd. | |
| 1331 * </pre> | |
| 1332 */ | |
| 1333 l_ok | |
| 1334 pixScaleAndTransferAlpha(PIX *pixd, | |
| 1335 PIX *pixs, | |
| 1336 l_float32 scalex, | |
| 1337 l_float32 scaley) | |
| 1338 { | |
| 1339 PIX *pix1, *pix2; | |
| 1340 | |
| 1341 if (!pixs || !pixd) | |
| 1342 return ERROR_INT("pixs and pixd not both defined", __func__, 1); | |
| 1343 if (pixGetDepth(pixs) != 32 || pixGetSpp(pixs) != 4) | |
| 1344 return ERROR_INT("pixs not 32 bpp and 4 spp", __func__, 1); | |
| 1345 if (pixGetDepth(pixd) != 32) | |
| 1346 return ERROR_INT("pixd not 32 bpp", __func__, 1); | |
| 1347 | |
| 1348 if (scalex == 1.0 && scaley == 1.0) { | |
| 1349 pixCopyRGBComponent(pixd, pixs, L_ALPHA_CHANNEL); | |
| 1350 return 0; | |
| 1351 } | |
| 1352 | |
| 1353 pix1 = pixGetRGBComponent(pixs, L_ALPHA_CHANNEL); | |
| 1354 pix2 = pixScale(pix1, scalex, scaley); | |
| 1355 pixSetRGBComponent(pixd, pix2, L_ALPHA_CHANNEL); | |
| 1356 pixDestroy(&pix1); | |
| 1357 pixDestroy(&pix2); | |
| 1358 return 0; | |
| 1359 } | |
| 1360 | |
| 1361 | |
| 1362 /*------------------------------------------------------------------------* | |
| 1363 * RGB scaling including alpha (blend) component and gamma transform * | |
| 1364 *------------------------------------------------------------------------*/ | |
| 1365 /*! | |
| 1366 * \brief pixScaleWithAlpha() | |
| 1367 * | |
| 1368 * \param[in] pixs 32 bpp rgb or cmapped | |
| 1369 * \param[in] scalex must be > 0.0 | |
| 1370 * \param[in] scaley must be > 0.0 | |
| 1371 * \param[in] pixg [optional] 8 bpp, can be null | |
| 1372 * \param[in] fract between 0.0 and 1.0, with 0.0 fully transparent | |
| 1373 * and 1.0 fully opaque | |
| 1374 * \return pixd 32 bpp rgba, or NULL on error | |
| 1375 * | |
| 1376 * <pre> | |
| 1377 * Notes: | |
| 1378 * (1) The alpha channel is transformed separately from pixs, | |
| 1379 * and aligns with it, being fully transparent outside the | |
| 1380 * boundary of the transformed pixs. For pixels that are fully | |
| 1381 * transparent, a blending function like pixBlendWithGrayMask() | |
| 1382 * will give zero weight to corresponding pixels in pixs. | |
| 1383 * (2) Scaling is done with area mapping or linear interpolation, | |
| 1384 * depending on the scale factors. Default sharpening is done. | |
| 1385 * (3) If pixg is NULL, it is generated as an alpha layer that is | |
| 1386 * partially opaque, using %fract. Otherwise, it is cropped | |
| 1387 * to pixs if required, and %fract is ignored. The alpha | |
| 1388 * channel in pixs is never used. | |
| 1389 * (4) Colormaps are removed to 32 bpp. | |
| 1390 * (5) The default setting for the border values in the alpha channel | |
| 1391 * is 0 (transparent) for the outermost ring of pixels and | |
| 1392 * (0.5 * fract * 255) for the second ring. When blended over | |
| 1393 * a second image, this | |
| 1394 * (a) shrinks the visible image to make a clean overlap edge | |
| 1395 * with an image below, and | |
| 1396 * (b) softens the edges by weakening the aliasing there. | |
| 1397 * Use l_setAlphaMaskBorder() to change these values. | |
| 1398 * (6) A subtle use of gamma correction is to remove gamma correction | |
| 1399 * before scaling and restore it afterwards. This is done | |
| 1400 * by sandwiching this function between a gamma/inverse-gamma | |
| 1401 * photometric transform: | |
| 1402 * pixt = pixGammaTRCWithAlpha(NULL, pixs, 1.0 / gamma, 0, 255); | |
| 1403 * pixd = pixScaleWithAlpha(pixt, scalex, scaley, NULL, fract); | |
| 1404 * pixGammaTRCWithAlpha(pixd, pixd, gamma, 0, 255); | |
| 1405 * pixDestroy(&pixt); | |
| 1406 * This has the side-effect of producing artifacts in the very | |
| 1407 * dark regions. | |
| 1408 * </pre> | |
| 1409 */ | |
| 1410 PIX * | |
| 1411 pixScaleWithAlpha(PIX *pixs, | |
| 1412 l_float32 scalex, | |
| 1413 l_float32 scaley, | |
| 1414 PIX *pixg, | |
| 1415 l_float32 fract) | |
| 1416 { | |
| 1417 l_int32 ws, hs, d, spp; | |
| 1418 PIX *pixd, *pix32, *pixg2, *pixgs; | |
| 1419 | |
| 1420 if (!pixs) | |
| 1421 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 1422 pixGetDimensions(pixs, &ws, &hs, &d); | |
| 1423 if (d != 32 && !pixGetColormap(pixs)) | |
| 1424 return (PIX *)ERROR_PTR("pixs not cmapped or 32 bpp", __func__, NULL); | |
| 1425 if (scalex <= 0.0 || scaley <= 0.0) | |
| 1426 return (PIX *)ERROR_PTR("scale factor <= 0.0", __func__, NULL); | |
| 1427 if (pixg && pixGetDepth(pixg) != 8) { | |
| 1428 L_WARNING("pixg not 8 bpp; using 'fract' transparent alpha\n", | |
| 1429 __func__); | |
| 1430 pixg = NULL; | |
| 1431 } | |
| 1432 if (!pixg && (fract < 0.0 || fract > 1.0)) { | |
| 1433 L_WARNING("invalid fract; using fully opaque\n", __func__); | |
| 1434 fract = 1.0; | |
| 1435 } | |
| 1436 if (!pixg && fract == 0.0) | |
| 1437 L_WARNING("transparent alpha; image will not be blended\n", __func__); | |
| 1438 | |
| 1439 /* Make sure input to scaling is 32 bpp rgb, and scale it */ | |
| 1440 if (d != 32) | |
| 1441 pix32 = pixConvertTo32(pixs); | |
| 1442 else | |
| 1443 pix32 = pixClone(pixs); | |
| 1444 spp = pixGetSpp(pix32); | |
| 1445 pixSetSpp(pix32, 3); /* ignore the alpha channel for scaling */ | |
| 1446 pixd = pixScale(pix32, scalex, scaley); | |
| 1447 pixSetSpp(pix32, spp); /* restore initial value in case it's a clone */ | |
| 1448 pixDestroy(&pix32); | |
| 1449 | |
| 1450 /* Set up alpha layer with a fading border and scale it */ | |
| 1451 if (!pixg) { | |
| 1452 pixg2 = pixCreate(ws, hs, 8); | |
| 1453 if (fract == 1.0) | |
| 1454 pixSetAll(pixg2); | |
| 1455 else if (fract > 0.0) | |
| 1456 pixSetAllArbitrary(pixg2, (l_int32)(255.0 * fract)); | |
| 1457 } else { | |
| 1458 pixg2 = pixResizeToMatch(pixg, NULL, ws, hs); | |
| 1459 } | |
| 1460 if (ws > 10 && hs > 10) { /* see note 4 */ | |
| 1461 pixSetBorderRingVal(pixg2, 1, | |
| 1462 (l_int32)(255.0 * fract * AlphaMaskBorderVals[0])); | |
| 1463 pixSetBorderRingVal(pixg2, 2, | |
| 1464 (l_int32)(255.0 * fract * AlphaMaskBorderVals[1])); | |
| 1465 } | |
| 1466 pixgs = pixScaleGeneral(pixg2, scalex, scaley, 0.0, 0); | |
| 1467 | |
| 1468 /* Combine into a 4 spp result */ | |
| 1469 pixSetRGBComponent(pixd, pixgs, L_ALPHA_CHANNEL); | |
| 1470 pixCopyInputFormat(pixd, pixs); | |
| 1471 | |
| 1472 pixDestroy(&pixg2); | |
| 1473 pixDestroy(&pixgs); | |
| 1474 return pixd; | |
| 1475 } | |
| 1476 | |
| 1477 | |
| 1478 /* ================================================================ * | |
| 1479 * Low level static functions * | |
| 1480 * ================================================================ */ | |
| 1481 | |
| 1482 /*------------------------------------------------------------------* | |
| 1483 * Scale-to-gray 2x * | |
| 1484 *------------------------------------------------------------------*/ | |
| 1485 /*! | |
| 1486 * \brief scaleToGray2Low() | |
| 1487 * | |
| 1488 * \param[in] datad dest data | |
| 1489 * \param[in] wd, hd dest width, height | |
| 1490 * \param[in] wpld dest words/line | |
| 1491 * \param[in] datas src data | |
| 1492 * \param[in] wpls src words/line | |
| 1493 * \param[in] sumtab made from makeSumTabSG2() | |
| 1494 * \param[in] valtab made from makeValTabSG2() | |
| 1495 * \return 0 if OK; 1 on error. | |
| 1496 * | |
| 1497 * <pre> | |
| 1498 * Notes: | |
| 1499 * (1) The output is processed in sets of 4 output bytes on a row, | |
| 1500 * corresponding to 4 2x2 bit-blocks in the input image. | |
| 1501 * Two lookup tables are used. The first, sumtab, gets the | |
| 1502 * sum of ON pixels in 4 sets of two adjacent bits, | |
| 1503 * storing the result in 4 adjacent bytes. After sums from | |
| 1504 * two rows have been added, the second table, valtab, | |
| 1505 * converts from the sum of ON pixels in the 2x2 block to | |
| 1506 * an 8 bpp grayscale value between 0 for 4 bits ON | |
| 1507 * and 255 for 0 bits ON. | |
| 1508 * </pre> | |
| 1509 */ | |
| 1510 static void | |
| 1511 scaleToGray2Low(l_uint32 *datad, | |
| 1512 l_int32 wd, | |
| 1513 l_int32 hd, | |
| 1514 l_int32 wpld, | |
| 1515 l_uint32 *datas, | |
| 1516 l_int32 wpls, | |
| 1517 l_uint32 *sumtab, | |
| 1518 l_uint8 *valtab) | |
| 1519 { | |
| 1520 l_int32 i, j, l, k, m, wd4, extra; | |
| 1521 l_uint32 sbyte1, sbyte2, sum; | |
| 1522 l_uint32 *lines, *lined; | |
| 1523 | |
| 1524 /* i indexes the dest lines | |
| 1525 * l indexes the source lines | |
| 1526 * j indexes the dest bytes | |
| 1527 * k indexes the source bytes | |
| 1528 * We take two bytes from the source (in 2 lines of 8 pixels | |
| 1529 * each) and convert them into four 8 bpp bytes of the dest. */ | |
| 1530 wd4 = wd & 0xfffffffc; | |
| 1531 extra = wd - wd4; | |
| 1532 for (i = 0, l = 0; i < hd; i++, l += 2) { | |
| 1533 lines = datas + l * wpls; | |
| 1534 lined = datad + i * wpld; | |
| 1535 for (j = 0, k = 0; j < wd4; j += 4, k++) { | |
| 1536 sbyte1 = GET_DATA_BYTE(lines, k); | |
| 1537 sbyte2 = GET_DATA_BYTE(lines + wpls, k); | |
| 1538 sum = sumtab[sbyte1] + sumtab[sbyte2]; | |
| 1539 SET_DATA_BYTE(lined, j, valtab[sum >> 24]); | |
| 1540 SET_DATA_BYTE(lined, j + 1, valtab[(sum >> 16) & 0xff]); | |
| 1541 SET_DATA_BYTE(lined, j + 2, valtab[(sum >> 8) & 0xff]); | |
| 1542 SET_DATA_BYTE(lined, j + 3, valtab[sum & 0xff]); | |
| 1543 } | |
| 1544 if (extra > 0) { | |
| 1545 sbyte1 = GET_DATA_BYTE(lines, k); | |
| 1546 sbyte2 = GET_DATA_BYTE(lines + wpls, k); | |
| 1547 sum = sumtab[sbyte1] + sumtab[sbyte2]; | |
| 1548 for (m = 0; m < extra; m++) { | |
| 1549 SET_DATA_BYTE(lined, j + m, | |
| 1550 valtab[((sum >> (24 - 8 * m)) & 0xff)]); | |
| 1551 } | |
| 1552 } | |
| 1553 | |
| 1554 } | |
| 1555 } | |
| 1556 | |
| 1557 | |
| 1558 /*! | |
| 1559 * \brief makeSumTabSG2() | |
| 1560 * | |
| 1561 * <pre> | |
| 1562 * Notes: | |
| 1563 * (1) Returns a table of 256 l_uint32s, giving the four output | |
| 1564 * 8-bit grayscale sums corresponding to 8 input bits of a binary | |
| 1565 * image, for a 2x scale-to-gray op. The sums from two | |
| 1566 * adjacent scanlines are then added and transformed to | |
| 1567 * output four 8 bpp pixel values, using makeValTabSG2(). | |
| 1568 * </pre> | |
| 1569 */ | |
| 1570 static l_uint32 * | |
| 1571 makeSumTabSG2(void) | |
| 1572 { | |
| 1573 l_int32 i; | |
| 1574 l_int32 sum[] = {0, 1, 1, 2}; | |
| 1575 l_uint32 *tab; | |
| 1576 | |
| 1577 /* Pack the four sums separately in four bytes */ | |
| 1578 tab = (l_uint32 *)LEPT_CALLOC(256, sizeof(l_uint32)); | |
| 1579 for (i = 0; i < 256; i++) { | |
| 1580 tab[i] = (sum[i & 0x3] | sum[(i >> 2) & 0x3] << 8 | | |
| 1581 sum[(i >> 4) & 0x3] << 16 | sum[(i >> 6) & 0x3] << 24); | |
| 1582 } | |
| 1583 return tab; | |
| 1584 } | |
| 1585 | |
| 1586 | |
| 1587 /*! | |
| 1588 * \brief makeValTabSG2() | |
| 1589 * | |
| 1590 * <pre> | |
| 1591 * Notes: | |
| 1592 * (1) Returns an 8 bit value for the sum of ON pixels | |
| 1593 * in a 2x2 square, according to | |
| 1594 * val = 255 - (255 * sum)/4 | |
| 1595 * where sum is in set {0,1,2,3,4} | |
| 1596 * </pre> | |
| 1597 */ | |
| 1598 static l_uint8 * | |
| 1599 makeValTabSG2(void) | |
| 1600 { | |
| 1601 l_int32 i; | |
| 1602 l_uint8 *tab; | |
| 1603 | |
| 1604 tab = (l_uint8 *)LEPT_CALLOC(5, sizeof(l_uint8)); | |
| 1605 for (i = 0; i < 5; i++) | |
| 1606 tab[i] = 255 - (i * 255) / 4; | |
| 1607 return tab; | |
| 1608 } | |
| 1609 | |
| 1610 | |
| 1611 /*------------------------------------------------------------------* | |
| 1612 * Scale-to-gray 3x * | |
| 1613 *------------------------------------------------------------------*/ | |
| 1614 /*! | |
| 1615 * \brief scaleToGray3Low() | |
| 1616 * | |
| 1617 * \param[in] datad dest data | |
| 1618 * \param[in] wd, hd dest width, height | |
| 1619 * \param[in] wpld dest words/line | |
| 1620 * \param[in] datas src data | |
| 1621 * \param[in] wpls src words/line | |
| 1622 * \param[in] sumtab made from makeSumTabSG3() | |
| 1623 * \param[in] valtab made from makeValTabSG3() | |
| 1624 * \return 0 if OK; 1 on error | |
| 1625 * | |
| 1626 * <pre> | |
| 1627 * Notes: | |
| 1628 * (1) Each set of 8 3x3 bit-blocks in the source image, which | |
| 1629 * consist of 72 pixels arranged 24 pixels wide by 3 scanlines, | |
| 1630 * is converted to a row of 8 8-bit pixels in the dest image. | |
| 1631 * These 72 pixels of the input image are runs of 24 pixels | |
| 1632 * in three adjacent scanlines. Each run of 24 pixels is | |
| 1633 * stored in the 24 LSbits of a 32-bit word. We use 2 LUTs. | |
| 1634 * The first, sumtab, takes 6 of these bits and stores | |
| 1635 * sum, taken 3 bits at a time, in two bytes. (See | |
| 1636 * makeSumTabSG3). This is done for each of the 3 scanlines, | |
| 1637 * and the results are added. We now have the sum of ON pixels | |
| 1638 * in the first two 3x3 blocks in two bytes. The valtab LUT | |
| 1639 * then converts these values (which go from 0 to 9) to | |
| 1640 * grayscale values between between 255 and 0. (See makeValTabSG3). | |
| 1641 * This process is repeated for each of the other 3 sets of | |
| 1642 * 6x3 input pixels, giving 8 output pixels in total. | |
| 1643 * (2) Note: because the input image is processed in groups of | |
| 1644 * 24 x 3 pixels, the process clips the input height to | |
| 1645 * (h - h % 3) and the input width to (w - w % 24). | |
| 1646 * </pre> | |
| 1647 */ | |
| 1648 static void | |
| 1649 scaleToGray3Low(l_uint32 *datad, | |
| 1650 l_int32 wd, | |
| 1651 l_int32 hd, | |
| 1652 l_int32 wpld, | |
| 1653 l_uint32 *datas, | |
| 1654 l_int32 wpls, | |
| 1655 l_uint32 *sumtab, | |
| 1656 l_uint8 *valtab) | |
| 1657 { | |
| 1658 l_int32 i, j, l, k; | |
| 1659 l_uint32 threebytes1, threebytes2, threebytes3, sum; | |
| 1660 l_uint32 *lines, *lined; | |
| 1661 | |
| 1662 /* i indexes the dest lines | |
| 1663 * l indexes the source lines | |
| 1664 * j indexes the dest bytes | |
| 1665 * k indexes the source bytes | |
| 1666 * We take 9 bytes from the source (72 binary pixels | |
| 1667 * in three lines of 24 pixels each) and convert it | |
| 1668 * into 8 bytes of the dest (8 8bpp pixels in one line) */ | |
| 1669 for (i = 0, l = 0; i < hd; i++, l += 3) { | |
| 1670 lines = datas + l * wpls; | |
| 1671 lined = datad + i * wpld; | |
| 1672 for (j = 0, k = 0; j < wd; j += 8, k += 3) { | |
| 1673 threebytes1 = (GET_DATA_BYTE(lines, k) << 16) | | |
| 1674 (GET_DATA_BYTE(lines, k + 1) << 8) | | |
| 1675 GET_DATA_BYTE(lines, k + 2); | |
| 1676 threebytes2 = (GET_DATA_BYTE(lines + wpls, k) << 16) | | |
| 1677 (GET_DATA_BYTE(lines + wpls, k + 1) << 8) | | |
| 1678 GET_DATA_BYTE(lines + wpls, k + 2); | |
| 1679 threebytes3 = (GET_DATA_BYTE(lines + 2 * wpls, k) << 16) | | |
| 1680 (GET_DATA_BYTE(lines + 2 * wpls, k + 1) << 8) | | |
| 1681 GET_DATA_BYTE(lines + 2 * wpls, k + 2); | |
| 1682 | |
| 1683 sum = sumtab[(threebytes1 >> 18)] + | |
| 1684 sumtab[(threebytes2 >> 18)] + | |
| 1685 sumtab[(threebytes3 >> 18)]; | |
| 1686 SET_DATA_BYTE(lined, j, valtab[GET_DATA_BYTE(&sum, 2)]); | |
| 1687 SET_DATA_BYTE(lined, j + 1, valtab[GET_DATA_BYTE(&sum, 3)]); | |
| 1688 | |
| 1689 sum = sumtab[((threebytes1 >> 12) & 0x3f)] + | |
| 1690 sumtab[((threebytes2 >> 12) & 0x3f)] + | |
| 1691 sumtab[((threebytes3 >> 12) & 0x3f)]; | |
| 1692 SET_DATA_BYTE(lined, j + 2, valtab[GET_DATA_BYTE(&sum, 2)]); | |
| 1693 SET_DATA_BYTE(lined, j + 3, valtab[GET_DATA_BYTE(&sum, 3)]); | |
| 1694 | |
| 1695 sum = sumtab[((threebytes1 >> 6) & 0x3f)] + | |
| 1696 sumtab[((threebytes2 >> 6) & 0x3f)] + | |
| 1697 sumtab[((threebytes3 >> 6) & 0x3f)]; | |
| 1698 SET_DATA_BYTE(lined, j + 4, valtab[GET_DATA_BYTE(&sum, 2)]); | |
| 1699 SET_DATA_BYTE(lined, j + 5, valtab[GET_DATA_BYTE(&sum, 3)]); | |
| 1700 | |
| 1701 sum = sumtab[(threebytes1 & 0x3f)] + | |
| 1702 sumtab[(threebytes2 & 0x3f)] + | |
| 1703 sumtab[(threebytes3 & 0x3f)]; | |
| 1704 SET_DATA_BYTE(lined, j + 6, valtab[GET_DATA_BYTE(&sum, 2)]); | |
| 1705 SET_DATA_BYTE(lined, j + 7, valtab[GET_DATA_BYTE(&sum, 3)]); | |
| 1706 } | |
| 1707 } | |
| 1708 } | |
| 1709 | |
| 1710 | |
| 1711 | |
| 1712 /*! | |
| 1713 * \brief makeSumTabSG3() | |
| 1714 * | |
| 1715 * <pre> | |
| 1716 * Notes: | |
| 1717 * (1) Returns a table of 64 l_uint32s, giving the two output | |
| 1718 * 8-bit grayscale sums corresponding to 6 input bits of a binary | |
| 1719 * image, for a 3x scale-to-gray op. In practice, this would | |
| 1720 * be used three times (on adjacent scanlines), and the sums would | |
| 1721 * be added and then transformed to output 8 bpp pixel values, | |
| 1722 * using makeValTabSG3(). | |
| 1723 * </pre> | |
| 1724 */ | |
| 1725 static l_uint32 * | |
| 1726 makeSumTabSG3(void) | |
| 1727 { | |
| 1728 l_int32 i; | |
| 1729 l_int32 sum[] = {0, 1, 1, 2, 1, 2, 2, 3}; | |
| 1730 l_uint32 *tab; | |
| 1731 | |
| 1732 /* Pack the two sums separately in two bytes */ | |
| 1733 tab = (l_uint32 *)LEPT_CALLOC(64, sizeof(l_uint32)); | |
| 1734 for (i = 0; i < 64; i++) { | |
| 1735 tab[i] = (sum[i & 0x07]) | (sum[(i >> 3) & 0x07] << 8); | |
| 1736 } | |
| 1737 return tab; | |
| 1738 } | |
| 1739 | |
| 1740 | |
| 1741 /*! | |
| 1742 * \brief makeValTabSG3() | |
| 1743 * | |
| 1744 * <pre> | |
| 1745 * Notes: | |
| 1746 * (1) Returns an 8 bit value for the sum of ON pixels | |
| 1747 * in a 3x3 square, according to | |
| 1748 * val = 255 - (255 * sum)/9 | |
| 1749 * where sum is in [0,...,9] | |
| 1750 * </pre> | |
| 1751 */ | |
| 1752 static l_uint8 * | |
| 1753 makeValTabSG3(void) | |
| 1754 { | |
| 1755 l_int32 i; | |
| 1756 l_uint8 *tab; | |
| 1757 | |
| 1758 tab = (l_uint8 *)LEPT_CALLOC(10, sizeof(l_uint8)); | |
| 1759 for (i = 0; i < 10; i++) | |
| 1760 tab[i] = 0xff - (i * 255) / 9; | |
| 1761 return tab; | |
| 1762 } | |
| 1763 | |
| 1764 | |
| 1765 /*------------------------------------------------------------------* | |
| 1766 * Scale-to-gray 4x * | |
| 1767 *------------------------------------------------------------------*/ | |
| 1768 /*! | |
| 1769 * \brief scaleToGray4Low() | |
| 1770 * | |
| 1771 * \param[in] datad dest data | |
| 1772 * \param[in] wd, hd dest width, height | |
| 1773 * \param[in] wpld dest words/line | |
| 1774 * \param[in] datas src data | |
| 1775 * \param[in] wpls src words/line | |
| 1776 * \param[in] sumtab made from makeSumTabSG4() | |
| 1777 * \param[in] valtab made from makeValTabSG4() | |
| 1778 * \return 0 if OK; 1 on error. | |
| 1779 * | |
| 1780 * <pre> | |
| 1781 * Notes: | |
| 1782 * (1) The output is processed in sets of 2 output bytes on a row, | |
| 1783 * corresponding to 2 4x4 bit-blocks in the input image. | |
| 1784 * Two lookup tables are used. The first, sumtab, gets the | |
| 1785 * sum of ON pixels in two sets of four adjacent bits, | |
| 1786 * storing the result in 2 adjacent bytes. After sums from | |
| 1787 * four rows have been added, the second table, valtab, | |
| 1788 * converts from the sum of ON pixels in the 4x4 block to | |
| 1789 * an 8 bpp grayscale value between 0 for 16 bits ON | |
| 1790 * and 255 for 0 bits ON. | |
| 1791 * </pre> | |
| 1792 */ | |
| 1793 static void | |
| 1794 scaleToGray4Low(l_uint32 *datad, | |
| 1795 l_int32 wd, | |
| 1796 l_int32 hd, | |
| 1797 l_int32 wpld, | |
| 1798 l_uint32 *datas, | |
| 1799 l_int32 wpls, | |
| 1800 l_uint32 *sumtab, | |
| 1801 l_uint8 *valtab) | |
| 1802 { | |
| 1803 l_int32 i, j, l, k; | |
| 1804 l_uint32 sbyte1, sbyte2, sbyte3, sbyte4, sum; | |
| 1805 l_uint32 *lines, *lined; | |
| 1806 | |
| 1807 /* i indexes the dest lines | |
| 1808 * l indexes the source lines | |
| 1809 * j indexes the dest bytes | |
| 1810 * k indexes the source bytes | |
| 1811 * We take four bytes from the source (in 4 lines of 8 pixels | |
| 1812 * each) and convert it into two 8 bpp bytes of the dest. */ | |
| 1813 for (i = 0, l = 0; i < hd; i++, l += 4) { | |
| 1814 lines = datas + l * wpls; | |
| 1815 lined = datad + i * wpld; | |
| 1816 for (j = 0, k = 0; j < wd; j += 2, k++) { | |
| 1817 sbyte1 = GET_DATA_BYTE(lines, k); | |
| 1818 sbyte2 = GET_DATA_BYTE(lines + wpls, k); | |
| 1819 sbyte3 = GET_DATA_BYTE(lines + 2 * wpls, k); | |
| 1820 sbyte4 = GET_DATA_BYTE(lines + 3 * wpls, k); | |
| 1821 sum = sumtab[sbyte1] + sumtab[sbyte2] + | |
| 1822 sumtab[sbyte3] + sumtab[sbyte4]; | |
| 1823 SET_DATA_BYTE(lined, j, valtab[GET_DATA_BYTE(&sum, 2)]); | |
| 1824 SET_DATA_BYTE(lined, j + 1, valtab[GET_DATA_BYTE(&sum, 3)]); | |
| 1825 } | |
| 1826 } | |
| 1827 } | |
| 1828 | |
| 1829 | |
| 1830 /*! | |
| 1831 * \brief makeSumTabSG4() | |
| 1832 * | |
| 1833 * <pre> | |
| 1834 * Notes: | |
| 1835 * (1) Returns a table of 256 l_uint32s, giving the two output | |
| 1836 * 8-bit grayscale sums corresponding to 8 input bits of a | |
| 1837 * binary image, for a 4x scale-to-gray op. The sums from | |
| 1838 * four adjacent scanlines are then added and transformed to | |
| 1839 * output 8 bpp pixel values, using makeValTabSG4(). | |
| 1840 * </pre> | |
| 1841 */ | |
| 1842 static l_uint32 * | |
| 1843 makeSumTabSG4(void) | |
| 1844 { | |
| 1845 l_int32 i; | |
| 1846 l_int32 sum[] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4}; | |
| 1847 l_uint32 *tab; | |
| 1848 | |
| 1849 /* Pack the two sums separately in two bytes */ | |
| 1850 tab = (l_uint32 *)LEPT_CALLOC(256, sizeof(l_uint32)); | |
| 1851 for (i = 0; i < 256; i++) { | |
| 1852 tab[i] = (sum[i & 0xf]) | (sum[(i >> 4) & 0xf] << 8); | |
| 1853 } | |
| 1854 return tab; | |
| 1855 } | |
| 1856 | |
| 1857 | |
| 1858 /*! | |
| 1859 * \brief makeValTabSG4() | |
| 1860 * | |
| 1861 * <pre> | |
| 1862 * Notes: | |
| 1863 * (1) Returns an 8 bit value for the sum of ON pixels | |
| 1864 * in a 4x4 square, according to | |
| 1865 * val = 255 - (255 * sum)/16 | |
| 1866 * where sum is in [0,...,16] | |
| 1867 * </pre> | |
| 1868 */ | |
| 1869 static l_uint8 * | |
| 1870 makeValTabSG4(void) | |
| 1871 { | |
| 1872 l_int32 i; | |
| 1873 l_uint8 *tab; | |
| 1874 | |
| 1875 tab = (l_uint8 *)LEPT_CALLOC(17, sizeof(l_uint8)); | |
| 1876 for (i = 0; i < 17; i++) | |
| 1877 tab[i] = 0xff - (i * 255) / 16; | |
| 1878 return tab; | |
| 1879 } | |
| 1880 | |
| 1881 | |
| 1882 /*------------------------------------------------------------------* | |
| 1883 * Scale-to-gray 6x * | |
| 1884 *------------------------------------------------------------------*/ | |
| 1885 /*! | |
| 1886 * \brief scaleToGray6Low() | |
| 1887 * | |
| 1888 * \param[in] datad dest data | |
| 1889 * \param[in] wd, hd dest width, height | |
| 1890 * \param[in] wpld dest words/line | |
| 1891 * \param[in] datas src data | |
| 1892 * \param[in] wpls src words/line | |
| 1893 * \param[in] tab8 made from makePixelSumTab8() | |
| 1894 * \param[in] valtab made from makeValTabSG6() | |
| 1895 * \return 0 if OK; 1 on error | |
| 1896 * | |
| 1897 * <pre> | |
| 1898 * Notes: | |
| 1899 * (1) Each set of 4 6x6 bit-blocks in the source image, which | |
| 1900 * consist of 144 pixels arranged 24 pixels wide by 6 scanlines, | |
| 1901 * is converted to a row of 4 8-bit pixels in the dest image. | |
| 1902 * These 144 pixels of the input image are runs of 24 pixels | |
| 1903 * in six adjacent scanlines. Each run of 24 pixels is | |
| 1904 * stored in the 24 LSbits of a 32-bit word. We use 2 LUTs. | |
| 1905 * The first, tab8, takes 6 of these bits and stores | |
| 1906 * sum in one byte. This is done for each of the 6 scanlines, | |
| 1907 * and the results are added. | |
| 1908 * We now have the sum of ON pixels in the first 6x6 block. The | |
| 1909 * valtab LUT then converts these values (which go from 0 to 36) to | |
| 1910 * grayscale values between between 255 and 0. (See makeValTabSG6). | |
| 1911 * This process is repeated for each of the other 3 sets of | |
| 1912 * 6x6 input pixels, giving 4 output pixels in total. | |
| 1913 * (2) Note: because the input image is processed in groups of | |
| 1914 * 24 x 6 pixels, the process clips the input height to | |
| 1915 * (h - h % 6) and the input width to (w - w % 24). | |
| 1916 * </pre> | |
| 1917 */ | |
| 1918 static void | |
| 1919 scaleToGray6Low(l_uint32 *datad, | |
| 1920 l_int32 wd, | |
| 1921 l_int32 hd, | |
| 1922 l_int32 wpld, | |
| 1923 l_uint32 *datas, | |
| 1924 l_int32 wpls, | |
| 1925 l_int32 *tab8, | |
| 1926 l_uint8 *valtab) | |
| 1927 { | |
| 1928 l_int32 i, j, l, k; | |
| 1929 l_uint32 threebytes1, threebytes2, threebytes3; | |
| 1930 l_uint32 threebytes4, threebytes5, threebytes6, sum; | |
| 1931 l_uint32 *lines, *lined; | |
| 1932 | |
| 1933 /* i indexes the dest lines | |
| 1934 * l indexes the source lines | |
| 1935 * j indexes the dest bytes | |
| 1936 * k indexes the source bytes | |
| 1937 * We take 18 bytes from the source (144 binary pixels | |
| 1938 * in six lines of 24 pixels each) and convert it | |
| 1939 * into 4 bytes of the dest (four 8 bpp pixels in one line) */ | |
| 1940 for (i = 0, l = 0; i < hd; i++, l += 6) { | |
| 1941 lines = datas + l * wpls; | |
| 1942 lined = datad + i * wpld; | |
| 1943 for (j = 0, k = 0; j < wd; j += 4, k += 3) { | |
| 1944 /* First grab the 18 bytes, 3 at a time, and put each set | |
| 1945 * of 3 bytes into the LS bytes of a 32-bit word. */ | |
| 1946 threebytes1 = (GET_DATA_BYTE(lines, k) << 16) | | |
| 1947 (GET_DATA_BYTE(lines, k + 1) << 8) | | |
| 1948 GET_DATA_BYTE(lines, k + 2); | |
| 1949 threebytes2 = (GET_DATA_BYTE(lines + wpls, k) << 16) | | |
| 1950 (GET_DATA_BYTE(lines + wpls, k + 1) << 8) | | |
| 1951 GET_DATA_BYTE(lines + wpls, k + 2); | |
| 1952 threebytes3 = (GET_DATA_BYTE(lines + 2 * wpls, k) << 16) | | |
| 1953 (GET_DATA_BYTE(lines + 2 * wpls, k + 1) << 8) | | |
| 1954 GET_DATA_BYTE(lines + 2 * wpls, k + 2); | |
| 1955 threebytes4 = (GET_DATA_BYTE(lines + 3 * wpls, k) << 16) | | |
| 1956 (GET_DATA_BYTE(lines + 3 * wpls, k + 1) << 8) | | |
| 1957 GET_DATA_BYTE(lines + 3 * wpls, k + 2); | |
| 1958 threebytes5 = (GET_DATA_BYTE(lines + 4 * wpls, k) << 16) | | |
| 1959 (GET_DATA_BYTE(lines + 4 * wpls, k + 1) << 8) | | |
| 1960 GET_DATA_BYTE(lines + 4 * wpls, k + 2); | |
| 1961 threebytes6 = (GET_DATA_BYTE(lines + 5 * wpls, k) << 16) | | |
| 1962 (GET_DATA_BYTE(lines + 5 * wpls, k + 1) << 8) | | |
| 1963 GET_DATA_BYTE(lines + 5 * wpls, k + 2); | |
| 1964 | |
| 1965 /* Sum first set of 36 bits and convert to 0-255 */ | |
| 1966 sum = tab8[(threebytes1 >> 18)] + | |
| 1967 tab8[(threebytes2 >> 18)] + | |
| 1968 tab8[(threebytes3 >> 18)] + | |
| 1969 tab8[(threebytes4 >> 18)] + | |
| 1970 tab8[(threebytes5 >> 18)] + | |
| 1971 tab8[(threebytes6 >> 18)]; | |
| 1972 SET_DATA_BYTE(lined, j, valtab[GET_DATA_BYTE(&sum, 3)]); | |
| 1973 | |
| 1974 /* Ditto for second set */ | |
| 1975 sum = tab8[((threebytes1 >> 12) & 0x3f)] + | |
| 1976 tab8[((threebytes2 >> 12) & 0x3f)] + | |
| 1977 tab8[((threebytes3 >> 12) & 0x3f)] + | |
| 1978 tab8[((threebytes4 >> 12) & 0x3f)] + | |
| 1979 tab8[((threebytes5 >> 12) & 0x3f)] + | |
| 1980 tab8[((threebytes6 >> 12) & 0x3f)]; | |
| 1981 SET_DATA_BYTE(lined, j + 1, valtab[GET_DATA_BYTE(&sum, 3)]); | |
| 1982 | |
| 1983 sum = tab8[((threebytes1 >> 6) & 0x3f)] + | |
| 1984 tab8[((threebytes2 >> 6) & 0x3f)] + | |
| 1985 tab8[((threebytes3 >> 6) & 0x3f)] + | |
| 1986 tab8[((threebytes4 >> 6) & 0x3f)] + | |
| 1987 tab8[((threebytes5 >> 6) & 0x3f)] + | |
| 1988 tab8[((threebytes6 >> 6) & 0x3f)]; | |
| 1989 SET_DATA_BYTE(lined, j + 2, valtab[GET_DATA_BYTE(&sum, 3)]); | |
| 1990 | |
| 1991 sum = tab8[(threebytes1 & 0x3f)] + | |
| 1992 tab8[(threebytes2 & 0x3f)] + | |
| 1993 tab8[(threebytes3 & 0x3f)] + | |
| 1994 tab8[(threebytes4 & 0x3f)] + | |
| 1995 tab8[(threebytes5 & 0x3f)] + | |
| 1996 tab8[(threebytes6 & 0x3f)]; | |
| 1997 SET_DATA_BYTE(lined, j + 3, valtab[GET_DATA_BYTE(&sum, 3)]); | |
| 1998 } | |
| 1999 } | |
| 2000 } | |
| 2001 | |
| 2002 | |
| 2003 /*! | |
| 2004 * \brief makeValTabSG6() | |
| 2005 * | |
| 2006 * <pre> | |
| 2007 * Notes: | |
| 2008 * (1) Returns an 8 bit value for the sum of ON pixels | |
| 2009 * in a 6x6 square, according to | |
| 2010 * val = 255 - (255 * sum)/36 | |
| 2011 * where sum is in [0,...,36] | |
| 2012 * </pre> | |
| 2013 */ | |
| 2014 static l_uint8 * | |
| 2015 makeValTabSG6(void) | |
| 2016 { | |
| 2017 l_int32 i; | |
| 2018 l_uint8 *tab; | |
| 2019 | |
| 2020 tab = (l_uint8 *)LEPT_CALLOC(37, sizeof(l_uint8)); | |
| 2021 for (i = 0; i < 37; i++) | |
| 2022 tab[i] = 0xff - (i * 255) / 36; | |
| 2023 return tab; | |
| 2024 } | |
| 2025 | |
| 2026 | |
| 2027 /*------------------------------------------------------------------* | |
| 2028 * Scale-to-gray 8x * | |
| 2029 *------------------------------------------------------------------*/ | |
| 2030 /*! | |
| 2031 * \brief scaleToGray8Low() | |
| 2032 * | |
| 2033 * \param[in] datad dest data | |
| 2034 * \param[in] wd, hd dest width, height | |
| 2035 * \param[in] wpld dest words/line | |
| 2036 * \param[in] datas src data | |
| 2037 * \param[in] wpls src words/line | |
| 2038 * \param[in] tab8 made from makePixelSumTab8() | |
| 2039 * \param[in] valtab made from makeValTabSG8() | |
| 2040 * \return 0 if OK; 1 on error. | |
| 2041 * | |
| 2042 * <pre> | |
| 2043 * Notes: | |
| 2044 * (1) The output is processed one dest byte at a time, | |
| 2045 * corresponding to 8 rows of src bytes in the input image. | |
| 2046 * Two lookup tables are used. The first, %tab8, gets the | |
| 2047 * sum of ON pixels in a byte. After sums from 8 rows have | |
| 2048 * been added, the second table, %valtab, converts from this | |
| 2049 * value which is between 0 and 64 to an 8 bpp grayscale | |
| 2050 * value between 0 and 255: 0 for all 64 bits ON and 255 | |
| 2051 * for all 64 bits OFF. | |
| 2052 * </pre> | |
| 2053 */ | |
| 2054 static void | |
| 2055 scaleToGray8Low(l_uint32 *datad, | |
| 2056 l_int32 wd, | |
| 2057 l_int32 hd, | |
| 2058 l_int32 wpld, | |
| 2059 l_uint32 *datas, | |
| 2060 l_int32 wpls, | |
| 2061 l_int32 *tab8, | |
| 2062 l_uint8 *valtab) | |
| 2063 { | |
| 2064 l_int32 i, j, k; | |
| 2065 l_int32 sbyte0, sbyte1, sbyte2, sbyte3, sbyte4, sbyte5, sbyte6, sbyte7, sum; | |
| 2066 l_uint32 *lines, *lined; | |
| 2067 | |
| 2068 /* i indexes the dest lines | |
| 2069 * k indexes the source lines | |
| 2070 * j indexes the src and dest bytes | |
| 2071 * We take 8 bytes from the source (in 8 lines of 8 pixels | |
| 2072 * each) and convert it into one 8 bpp byte of the dest. */ | |
| 2073 for (i = 0, k = 0; i < hd; i++, k += 8) { | |
| 2074 lines = datas + k * wpls; | |
| 2075 lined = datad + i * wpld; | |
| 2076 for (j = 0; j < wd; j++) { | |
| 2077 sbyte0 = GET_DATA_BYTE(lines, j); | |
| 2078 sbyte1 = GET_DATA_BYTE(lines + wpls, j); | |
| 2079 sbyte2 = GET_DATA_BYTE(lines + 2 * wpls, j); | |
| 2080 sbyte3 = GET_DATA_BYTE(lines + 3 * wpls, j); | |
| 2081 sbyte4 = GET_DATA_BYTE(lines + 4 * wpls, j); | |
| 2082 sbyte5 = GET_DATA_BYTE(lines + 5 * wpls, j); | |
| 2083 sbyte6 = GET_DATA_BYTE(lines + 6 * wpls, j); | |
| 2084 sbyte7 = GET_DATA_BYTE(lines + 7 * wpls, j); | |
| 2085 sum = tab8[sbyte0] + tab8[sbyte1] + | |
| 2086 tab8[sbyte2] + tab8[sbyte3] + | |
| 2087 tab8[sbyte4] + tab8[sbyte5] + | |
| 2088 tab8[sbyte6] + tab8[sbyte7]; | |
| 2089 SET_DATA_BYTE(lined, j, valtab[sum]); | |
| 2090 } | |
| 2091 } | |
| 2092 } | |
| 2093 | |
| 2094 | |
| 2095 /*! | |
| 2096 * \brief makeValTabSG8() | |
| 2097 * | |
| 2098 * <pre> | |
| 2099 * Notes: | |
| 2100 * (1) Returns an 8 bit value for the sum of ON pixels | |
| 2101 * in an 8x8 square, according to | |
| 2102 * val = 255 - (255 * sum)/64 | |
| 2103 * where sum is in [0,...,64] | |
| 2104 * </pre> | |
| 2105 */ | |
| 2106 static l_uint8 * | |
| 2107 makeValTabSG8(void) | |
| 2108 { | |
| 2109 l_int32 i; | |
| 2110 l_uint8 *tab; | |
| 2111 | |
| 2112 tab = (l_uint8 *)LEPT_CALLOC(65, sizeof(l_uint8)); | |
| 2113 for (i = 0; i < 65; i++) | |
| 2114 tab[i] = 0xff - (i * 255) / 64; | |
| 2115 return tab; | |
| 2116 } | |
| 2117 | |
| 2118 | |
| 2119 /*------------------------------------------------------------------* | |
| 2120 * Scale-to-gray 16x * | |
| 2121 *------------------------------------------------------------------*/ | |
| 2122 /*! | |
| 2123 * \brief scaleToGray16Low() | |
| 2124 * | |
| 2125 * \param[in] datad dest data | |
| 2126 * \param[in] wd, hd dest width, height | |
| 2127 * \param[in] wpld dest words/line | |
| 2128 * \param[in] datas src data | |
| 2129 * \param[in] wpls src words/line | |
| 2130 * \param[in] tab8 made from makePixelSumTab8() | |
| 2131 * \return 0 if OK; 1 on error. | |
| 2132 * | |
| 2133 * <pre> | |
| 2134 * Notes: | |
| 2135 * (1) The output is processed one dest byte at a time, corresponding | |
| 2136 * to 16 rows consisting each of 2 src bytes in the input image. | |
| 2137 * This uses one lookup table, tab8, which gives the sum of | |
| 2138 * ON pixels in a byte. After summing for all ON pixels in the | |
| 2139 * 32 src bytes, which is between 0 and 256, this is converted | |
| 2140 * to an 8 bpp grayscale value between 0 for 255 or 256 bits ON | |
| 2141 * and 255 for 0 bits ON. | |
| 2142 * </pre> | |
| 2143 */ | |
| 2144 static void | |
| 2145 scaleToGray16Low(l_uint32 *datad, | |
| 2146 l_int32 wd, | |
| 2147 l_int32 hd, | |
| 2148 l_int32 wpld, | |
| 2149 l_uint32 *datas, | |
| 2150 l_int32 wpls, | |
| 2151 l_int32 *tab8) | |
| 2152 { | |
| 2153 l_int32 i, j, k, m; | |
| 2154 l_int32 sum; | |
| 2155 l_uint32 *lines, *lined; | |
| 2156 | |
| 2157 /* i indexes the dest lines | |
| 2158 * k indexes the source lines | |
| 2159 * j indexes the dest bytes | |
| 2160 * m indexes the src bytes | |
| 2161 * We take 32 bytes from the source (in 16 lines of 16 pixels | |
| 2162 * each) and convert it into one 8 bpp byte of the dest. */ | |
| 2163 for (i = 0, k = 0; i < hd; i++, k += 16) { | |
| 2164 lines = datas + k * wpls; | |
| 2165 lined = datad + i * wpld; | |
| 2166 for (j = 0; j < wd; j++) { | |
| 2167 m = 2 * j; | |
| 2168 sum = tab8[GET_DATA_BYTE(lines, m)]; | |
| 2169 sum += tab8[GET_DATA_BYTE(lines, m + 1)]; | |
| 2170 sum += tab8[GET_DATA_BYTE(lines + wpls, m)]; | |
| 2171 sum += tab8[GET_DATA_BYTE(lines + wpls, m + 1)]; | |
| 2172 sum += tab8[GET_DATA_BYTE(lines + 2 * wpls, m)]; | |
| 2173 sum += tab8[GET_DATA_BYTE(lines + 2 * wpls, m + 1)]; | |
| 2174 sum += tab8[GET_DATA_BYTE(lines + 3 * wpls, m)]; | |
| 2175 sum += tab8[GET_DATA_BYTE(lines + 3 * wpls, m + 1)]; | |
| 2176 sum += tab8[GET_DATA_BYTE(lines + 4 * wpls, m)]; | |
| 2177 sum += tab8[GET_DATA_BYTE(lines + 4 * wpls, m + 1)]; | |
| 2178 sum += tab8[GET_DATA_BYTE(lines + 5 * wpls, m)]; | |
| 2179 sum += tab8[GET_DATA_BYTE(lines + 5 * wpls, m + 1)]; | |
| 2180 sum += tab8[GET_DATA_BYTE(lines + 6 * wpls, m)]; | |
| 2181 sum += tab8[GET_DATA_BYTE(lines + 6 * wpls, m + 1)]; | |
| 2182 sum += tab8[GET_DATA_BYTE(lines + 7 * wpls, m)]; | |
| 2183 sum += tab8[GET_DATA_BYTE(lines + 7 * wpls, m + 1)]; | |
| 2184 sum += tab8[GET_DATA_BYTE(lines + 8 * wpls, m)]; | |
| 2185 sum += tab8[GET_DATA_BYTE(lines + 8 * wpls, m + 1)]; | |
| 2186 sum += tab8[GET_DATA_BYTE(lines + 9 * wpls, m)]; | |
| 2187 sum += tab8[GET_DATA_BYTE(lines + 9 * wpls, m + 1)]; | |
| 2188 sum += tab8[GET_DATA_BYTE(lines + 10 * wpls, m)]; | |
| 2189 sum += tab8[GET_DATA_BYTE(lines + 10 * wpls, m + 1)]; | |
| 2190 sum += tab8[GET_DATA_BYTE(lines + 11 * wpls, m)]; | |
| 2191 sum += tab8[GET_DATA_BYTE(lines + 11 * wpls, m + 1)]; | |
| 2192 sum += tab8[GET_DATA_BYTE(lines + 12 * wpls, m)]; | |
| 2193 sum += tab8[GET_DATA_BYTE(lines + 12 * wpls, m + 1)]; | |
| 2194 sum += tab8[GET_DATA_BYTE(lines + 13 * wpls, m)]; | |
| 2195 sum += tab8[GET_DATA_BYTE(lines + 13 * wpls, m + 1)]; | |
| 2196 sum += tab8[GET_DATA_BYTE(lines + 14 * wpls, m)]; | |
| 2197 sum += tab8[GET_DATA_BYTE(lines + 14 * wpls, m + 1)]; | |
| 2198 sum += tab8[GET_DATA_BYTE(lines + 15 * wpls, m)]; | |
| 2199 sum += tab8[GET_DATA_BYTE(lines + 15 * wpls, m + 1)]; | |
| 2200 sum = L_MIN(sum, 255); | |
| 2201 SET_DATA_BYTE(lined, j, 255 - sum); | |
| 2202 } | |
| 2203 } | |
| 2204 } | |
| 2205 | |
| 2206 | |
| 2207 | |
| 2208 /*------------------------------------------------------------------* | |
| 2209 * Grayscale mipmap * | |
| 2210 *------------------------------------------------------------------*/ | |
| 2211 /*! | |
| 2212 * \brief scaleMipmapLow() | |
| 2213 * | |
| 2214 * <pre> | |
| 2215 * Notes: | |
| 2216 * (1) See notes in scale.c for pixScaleToGrayMipmap(). This function | |
| 2217 * is here for pedagogical reasons. It gives poor results on document | |
| 2218 * images because of aliasing. | |
| 2219 * </pre> | |
| 2220 */ | |
| 2221 static l_int32 | |
| 2222 scaleMipmapLow(l_uint32 *datad, | |
| 2223 l_int32 wd, | |
| 2224 l_int32 hd, | |
| 2225 l_int32 wpld, | |
| 2226 l_uint32 *datas1, | |
| 2227 l_int32 wpls1, | |
| 2228 l_uint32 *datas2, | |
| 2229 l_int32 wpls2, | |
| 2230 l_float32 red) | |
| 2231 { | |
| 2232 l_int32 i, j, val1, val2, val, row2, col2; | |
| 2233 l_int32 *srow, *scol; | |
| 2234 l_uint32 *lines1, *lines2, *lined; | |
| 2235 l_float32 ratio, w1, w2; | |
| 2236 | |
| 2237 /* Clear dest */ | |
| 2238 memset(datad, 0, 4LL * wpld * hd); | |
| 2239 | |
| 2240 /* Each dest pixel at (j,i) is computed by interpolating | |
| 2241 between the two src images at the corresponding location. | |
| 2242 We store the UL corner locations of the square of | |
| 2243 src pixels in thelower-resolution image that correspond | |
| 2244 to dest pixel (j,i). The are labeled by the arrays | |
| 2245 srow[i], scol[j]. The UL corner locations of the higher | |
| 2246 resolution src pixels are obtained from these arrays | |
| 2247 by multiplying by 2. */ | |
| 2248 if ((srow = (l_int32 *)LEPT_CALLOC(hd, sizeof(l_int32))) == NULL) | |
| 2249 return ERROR_INT("srow not made", __func__, 1); | |
| 2250 if ((scol = (l_int32 *)LEPT_CALLOC(wd, sizeof(l_int32))) == NULL) { | |
| 2251 LEPT_FREE(srow); | |
| 2252 return ERROR_INT("scol not made", __func__, 1); | |
| 2253 } | |
| 2254 ratio = 1.f / (2.f * red); /* 0.5 for red = 1, 1 for red = 0.5 */ | |
| 2255 for (i = 0; i < hd; i++) | |
| 2256 srow[i] = (l_int32)(ratio * i); | |
| 2257 for (j = 0; j < wd; j++) | |
| 2258 scol[j] = (l_int32)(ratio * j); | |
| 2259 | |
| 2260 /* Get weights for linear interpolation: these are the | |
| 2261 * 'distances' of the dest image plane from the two | |
| 2262 * src image planes. */ | |
| 2263 w1 = 2.f * red - 1.f; /* w1 --> 1 as red --> 1 */ | |
| 2264 w2 = 1.f - w1; | |
| 2265 | |
| 2266 /* For each dest pixel, compute linear interpolation */ | |
| 2267 for (i = 0; i < hd; i++) { | |
| 2268 row2 = srow[i]; | |
| 2269 lines1 = datas1 + 2 * row2 * wpls1; | |
| 2270 lines2 = datas2 + row2 * wpls2; | |
| 2271 lined = datad + i * wpld; | |
| 2272 for (j = 0; j < wd; j++) { | |
| 2273 col2 = scol[j]; | |
| 2274 val1 = GET_DATA_BYTE(lines1, 2 * col2); | |
| 2275 val2 = GET_DATA_BYTE(lines2, col2); | |
| 2276 val = (l_int32)(w1 * val1 + w2 * val2); | |
| 2277 SET_DATA_BYTE(lined, j, val); | |
| 2278 } | |
| 2279 } | |
| 2280 | |
| 2281 LEPT_FREE(srow); | |
| 2282 LEPT_FREE(scol); | |
| 2283 return 0; | |
| 2284 } |
