Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/leptonica/src/scale1.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 scale1.c | |
| 29 * <pre> | |
| 30 * Top-level scaling | |
| 31 * PIX *pixScale() | |
| 32 * PIX *pixScaleToSizeRel() | |
| 33 * PIX *pixScaleToSize() | |
| 34 * PIX *pixScaleToResolution() | |
| 35 * PIX *pixScaleGeneral() | |
| 36 * | |
| 37 * Linearly interpreted (usually up-) scaling | |
| 38 * PIX *pixScaleLI() | |
| 39 * PIX *pixScaleColorLI() | |
| 40 * PIX *pixScaleColor2xLI() | |
| 41 * PIX *pixScaleColor4xLI() | |
| 42 * PIX *pixScaleGrayLI() | |
| 43 * PIX *pixScaleGray2xLI() | |
| 44 * PIX *pixScaleGray4xLI() | |
| 45 * | |
| 46 * Upscale 2x followed by binarization | |
| 47 * PIX *pixScaleGray2xLIThresh() | |
| 48 * PIX *pixScaleGray2xLIDither() | |
| 49 * | |
| 50 * Upscale 4x followed by binarization | |
| 51 * PIX *pixScaleGray4xLIThresh() | |
| 52 * PIX *pixScaleGray4xLIDither() | |
| 53 * | |
| 54 * Scaling by closest pixel sampling | |
| 55 * PIX *pixScaleBySampling() | |
| 56 * PIX *pixScaleBySamplingWithShift() | |
| 57 * PIX *pixScaleBySamplingToSize() | |
| 58 * PIX *pixScaleByIntSampling() | |
| 59 * | |
| 60 * Fast integer factor subsampling RGB to gray and to binary | |
| 61 * PIX *pixScaleRGBToGrayFast() | |
| 62 * PIX *pixScaleRGBToBinaryFast() | |
| 63 * PIX *pixScaleGrayToBinaryFast() | |
| 64 * | |
| 65 * Downscaling with (antialias) smoothing | |
| 66 * PIX *pixScaleSmooth() | |
| 67 * PIX *pixScaleSmoothToSize() | |
| 68 * PIX *pixScaleRGBToGray2() [special 2x reduction to gray] | |
| 69 * | |
| 70 * Downscaling with (antialias) area mapping | |
| 71 * PIX *pixScaleAreaMap() | |
| 72 * PIX *pixScaleAreaMap2() | |
| 73 * PIX *pixScaleAreaMapToSize() | |
| 74 * | |
| 75 * Binary scaling by closest pixel sampling | |
| 76 * PIX *pixScaleBinary() | |
| 77 * PIX *pixScaleBinaryWithShift() | |
| 78 * | |
| 79 * Low-level static functions: | |
| 80 * | |
| 81 * Color (interpolated) scaling: general case | |
| 82 * static void scaleColorLILow() | |
| 83 * | |
| 84 * Grayscale (interpolated) scaling: general case | |
| 85 * static void scaleGrayLILow() | |
| 86 * | |
| 87 * Color (interpolated) scaling: 2x upscaling | |
| 88 * static void scaleColor2xLILow() | |
| 89 * static void scaleColor2xLILineLow() | |
| 90 * | |
| 91 * Grayscale (interpolated) scaling: 2x upscaling | |
| 92 * static void scaleGray2xLILow() | |
| 93 * static void scaleGray2xLILineLow() | |
| 94 * | |
| 95 * Grayscale (interpolated) scaling: 4x upscaling | |
| 96 * static void scaleGray4xLILow() | |
| 97 * static void scaleGray4xLILineLow() | |
| 98 * | |
| 99 * Grayscale and color scaling by closest pixel sampling | |
| 100 * static l_int32 scaleBySamplingLow() | |
| 101 * | |
| 102 * Color and grayscale downsampling with (antialias) lowpass filter | |
| 103 * static l_int32 scaleSmoothLow() | |
| 104 * static void scaleRGBToGray2Low() | |
| 105 * | |
| 106 * Color and grayscale downsampling with (antialias) area mapping | |
| 107 * static l_int32 scaleColorAreaMapLow() | |
| 108 * static l_int32 scaleGrayAreaMapLow() | |
| 109 * static l_int32 scaleAreaMapLow2() | |
| 110 * | |
| 111 * Binary scaling by closest pixel sampling | |
| 112 * static l_int32 scaleBinaryLow() | |
| 113 * </pre> | |
| 114 */ | |
| 115 | |
| 116 #ifdef HAVE_CONFIG_H | |
| 117 #include <config_auto.h> | |
| 118 #endif /* HAVE_CONFIG_H */ | |
| 119 | |
| 120 #include <string.h> | |
| 121 #include "allheaders.h" | |
| 122 | |
| 123 static void scaleColorLILow(l_uint32 *datad, l_int32 wd, l_int32 hd, | |
| 124 l_int32 wpld, l_uint32 *datas, l_int32 ws, | |
| 125 l_int32 hs, l_int32 wpls); | |
| 126 static void scaleGrayLILow(l_uint32 *datad, l_int32 wd, l_int32 hd, | |
| 127 l_int32 wpld, l_uint32 *datas, l_int32 ws, | |
| 128 l_int32 hs, l_int32 wpls); | |
| 129 static void scaleColor2xLILow(l_uint32 *datad, l_int32 wpld, l_uint32 *datas, | |
| 130 l_int32 ws, l_int32 hs, l_int32 wpls); | |
| 131 static void scaleColor2xLILineLow(l_uint32 *lined, l_int32 wpld, | |
| 132 l_uint32 *lines, l_int32 ws, l_int32 wpls, | |
| 133 l_int32 lastlineflag); | |
| 134 static void scaleGray2xLILow(l_uint32 *datad, l_int32 wpld, l_uint32 *datas, | |
| 135 l_int32 ws, l_int32 hs, l_int32 wpls); | |
| 136 static void scaleGray2xLILineLow(l_uint32 *lined, l_int32 wpld, | |
| 137 l_uint32 *lines, l_int32 ws, l_int32 wpls, | |
| 138 l_int32 lastlineflag); | |
| 139 static void scaleGray4xLILow(l_uint32 *datad, l_int32 wpld, l_uint32 *datas, | |
| 140 l_int32 ws, l_int32 hs, l_int32 wpls); | |
| 141 static void scaleGray4xLILineLow(l_uint32 *lined, l_int32 wpld, | |
| 142 l_uint32 *lines, l_int32 ws, l_int32 wpls, | |
| 143 l_int32 lastlineflag); | |
| 144 static l_int32 scaleBySamplingLow(l_uint32 *datad, l_int32 wd, l_int32 hd, | |
| 145 l_int32 wpld, l_uint32 *datas, l_int32 ws, | |
| 146 l_int32 hs, l_int32 d, l_int32 wpls, | |
| 147 l_float32 shiftx, l_float32 shifty); | |
| 148 static l_int32 scaleSmoothLow(l_uint32 *datad, l_int32 wd, l_int32 hd, | |
| 149 l_int32 wpld, l_uint32 *datas, l_int32 ws, | |
| 150 l_int32 hs, l_int32 d, l_int32 wpls, | |
| 151 l_int32 size); | |
| 152 static void scaleRGBToGray2Low(l_uint32 *datad, l_int32 wd, l_int32 hd, | |
| 153 l_int32 wpld, l_uint32 *datas, l_int32 wpls, | |
| 154 l_float32 rwt, l_float32 gwt, l_float32 bwt); | |
| 155 static void scaleColorAreaMapLow(l_uint32 *datad, l_int32 wd, l_int32 hd, | |
| 156 l_int32 wpld, l_uint32 *datas, l_int32 ws, | |
| 157 l_int32 hs, l_int32 wpls); | |
| 158 static void scaleGrayAreaMapLow(l_uint32 *datad, l_int32 wd, l_int32 hd, | |
| 159 l_int32 wpld, l_uint32 *datas, l_int32 ws, | |
| 160 l_int32 hs, l_int32 wpls); | |
| 161 static void scaleAreaMapLow2(l_uint32 *datad, l_int32 wd, l_int32 hd, | |
| 162 l_int32 wpld, l_uint32 *datas, l_int32 d, | |
| 163 l_int32 wpls); | |
| 164 static l_int32 scaleBinaryLow(l_uint32 *datad, l_int32 wd, l_int32 hd, | |
| 165 l_int32 wpld, l_uint32 *datas, l_int32 ws, | |
| 166 l_int32 hs, l_int32 wpls, | |
| 167 l_float32 shiftx, l_float32 shifty); | |
| 168 | |
| 169 #ifndef NO_CONSOLE_IO | |
| 170 #define DEBUG_OVERFLOW 0 | |
| 171 #define DEBUG_UNROLLING 0 | |
| 172 #endif /* ~NO_CONSOLE_IO */ | |
| 173 | |
| 174 /*------------------------------------------------------------------* | |
| 175 * Top level scaling dispatcher * | |
| 176 *------------------------------------------------------------------*/ | |
| 177 /*! | |
| 178 * \brief pixScale() | |
| 179 * | |
| 180 * \param[in] pixs 1, 2, 4, 8, 16 and 32 bpp | |
| 181 * \param[in] scalex, scaley | |
| 182 * \return pixd, or NULL on error | |
| 183 * | |
| 184 * This function scales 32 bpp RGB; 2, 4 or 8 bpp palette color; | |
| 185 * 2, 4, 8 or 16 bpp gray; and binary images. | |
| 186 * | |
| 187 * When the input has palette color, the colormap is removed and | |
| 188 * the result is either 8 bpp gray or 32 bpp RGB, depending on whether | |
| 189 * the colormap has color entries. Images with 2, 4 or 16 bpp are | |
| 190 * converted to 8 bpp. | |
| 191 * | |
| 192 * Because pixScale is meant to be a very simple interface to a | |
| 193 * number of scaling functions, including the use of unsharp masking, | |
| 194 * the type of scaling and the sharpening parameters are chosen | |
| 195 * by default. Grayscale and color images are scaled using one | |
| 196 * of five methods, depending on the scale factors: | |
| 197 * 1. antialiased subsampling (lowpass filtering followed by | |
| 198 * subsampling, implemented by convolution, for tiny scale factors: | |
| 199 * min(scalex, scaley) < 0.02. | |
| 200 * 2. antialiased subsampling (implemented by area mapping, for | |
| 201 * small scale factors: | |
| 202 * max(scalex, scaley) < 0.2 and min(scalex, scaley) >= 0.02. | |
| 203 * 3. antialiased subsampling with sharpening, for scale factors | |
| 204 * between 0.2 and 0.7 | |
| 205 * 4. linear interpolation with sharpening, for scale factors between | |
| 206 * 0.7 and 1.4 | |
| 207 * 5. linear interpolation without sharpening, for scale factors >= 1.4. | |
| 208 * | |
| 209 * One could use subsampling for scale factors very close to 1.0, | |
| 210 * because it preserves sharp edges. Linear interpolation blurs | |
| 211 * edges because the dest pixels will typically straddle two src edge | |
| 212 * pixels. Subsmpling removes entire columns and rows, so the edge is | |
| 213 * not blurred. However, there are two reasons for not doing this. | |
| 214 * First, it moves edges, so that a straight line at a large angle to | |
| 215 * both horizontal and vertical will have noticeable kinks where | |
| 216 * horizontal and vertical rasters are removed. Second, although it | |
| 217 * is very fast, you get good results on sharp edges by applying | |
| 218 * a sharpening filter. | |
| 219 * | |
| 220 * For images with sharp edges, sharpening substantially improves the | |
| 221 * image quality for scale factors between about 0.2 and about 2.0. | |
| 222 * pixScale uses a small amount of sharpening by default because | |
| 223 * it strengthens edge pixels that are weak due to anti-aliasing. | |
| 224 * The default sharpening factors are: | |
| 225 * * for scaling factors < 0.7: sharpfract = 0.2 sharpwidth = 1 | |
| 226 * * for scaling factors >= 0.7: sharpfract = 0.4 sharpwidth = 2 | |
| 227 * The cases where the sharpening halfwidth is 1 or 2 have special | |
| 228 * implementations and are about twice as fast as the general case. | |
| 229 * | |
| 230 * However, sharpening is computationally expensive, and one needs | |
| 231 * to consider the speed-quality tradeoff: | |
| 232 * * For upscaling of RGB images, linear interpolation plus default | |
| 233 * sharpening is about 5 times slower than upscaling alone. | |
| 234 * * For downscaling, area mapping plus default sharpening is | |
| 235 * about 10 times slower than downscaling alone. | |
| 236 * When the scale factor is larger than 1.4, the cost of sharpening, | |
| 237 * which is proportional to image area, is very large compared to the | |
| 238 * incremental quality improvement, so we cut off the default use of | |
| 239 * sharpening at 1.4. Thus, for scale factors greater than 1.4, | |
| 240 * pixScale only does linear interpolation. | |
| 241 * | |
| 242 * In many situations you will get a satisfactory result by scaling | |
| 243 * without sharpening: call pixScaleGeneral with %sharpfract = 0.0. | |
| 244 * Alternatively, if you wish to sharpen but not use the default | |
| 245 * value, first call pixScaleGeneral with %sharpfract = 0.0, and | |
| 246 * then sharpen explicitly using pixUnsharpMasking. | |
| 247 * | |
| 248 * Binary images are scaled to binary by sampling the closest pixel, | |
| 249 * without any low-pass filtering averaging of neighboring pixels. | |
| 250 * This will introduce aliasing for reductions. Aliasing can be | |
| 251 * prevented by using pixScaleToGray instead. | |
| 252 */ | |
| 253 PIX * | |
| 254 pixScale(PIX *pixs, | |
| 255 l_float32 scalex, | |
| 256 l_float32 scaley) | |
| 257 { | |
| 258 l_int32 sharpwidth; | |
| 259 l_float32 maxscale, sharpfract; | |
| 260 | |
| 261 if (!pixs) | |
| 262 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 263 | |
| 264 /* Reduce the default sharpening factors by 2 if maxscale < 0.7 */ | |
| 265 maxscale = L_MAX(scalex, scaley); | |
| 266 sharpfract = (maxscale < 0.7) ? 0.2f : 0.4f; | |
| 267 sharpwidth = (maxscale < 0.7) ? 1 : 2; | |
| 268 | |
| 269 return pixScaleGeneral(pixs, scalex, scaley, sharpfract, sharpwidth); | |
| 270 } | |
| 271 | |
| 272 | |
| 273 /*! | |
| 274 * \brief pixScaleToSizeRel() | |
| 275 * | |
| 276 * \param[in] pixs | |
| 277 * \param[in] delw change in width, in pixels; 0 means no change | |
| 278 * \param[in] delh change in height, in pixels; 0 means no change | |
| 279 * \return pixd, or NULL on error | |
| 280 */ | |
| 281 PIX * | |
| 282 pixScaleToSizeRel(PIX *pixs, | |
| 283 l_int32 delw, | |
| 284 l_int32 delh) | |
| 285 { | |
| 286 l_int32 w, h, wd, hd; | |
| 287 | |
| 288 if (!pixs) | |
| 289 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 290 | |
| 291 if (delw == 0 && delh == 0) | |
| 292 return pixCopy(NULL, pixs); | |
| 293 | |
| 294 pixGetDimensions(pixs, &w, &h, NULL); | |
| 295 wd = w + delw; | |
| 296 hd = h + delh; | |
| 297 if (wd <= 0 || hd <= 0) | |
| 298 return (PIX *)ERROR_PTR("pix dimension reduced to 0", __func__, NULL); | |
| 299 | |
| 300 return pixScaleToSize(pixs, wd, hd); | |
| 301 } | |
| 302 | |
| 303 | |
| 304 /*! | |
| 305 * \brief pixScaleToSize() | |
| 306 * | |
| 307 * \param[in] pixs 1, 2, 4, 8, 16 and 32 bpp | |
| 308 * \param[in] wd target width; use 0 if using height as target | |
| 309 * \param[in] hd target height; use 0 if using width as target | |
| 310 * \return pixd, or NULL on error | |
| 311 * | |
| 312 * <pre> | |
| 313 * Notes: | |
| 314 * (1) The output scaled image has the dimension(s) you specify: | |
| 315 * * To specify the width with isotropic scaling, set %hd = 0. | |
| 316 * * To specify the height with isotropic scaling, set %wd = 0. | |
| 317 * * If both %wd and %hd are specified, the image is scaled | |
| 318 * (in general, anisotropically) to that size. | |
| 319 * * It is an error to set both %wd and %hd to 0. | |
| 320 * </pre> | |
| 321 */ | |
| 322 PIX * | |
| 323 pixScaleToSize(PIX *pixs, | |
| 324 l_int32 wd, | |
| 325 l_int32 hd) | |
| 326 { | |
| 327 l_int32 w, h; | |
| 328 l_float32 scalex, scaley; | |
| 329 | |
| 330 if (!pixs) | |
| 331 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 332 if (wd <= 0 && hd <= 0) | |
| 333 return (PIX *)ERROR_PTR("neither wd nor hd > 0", __func__, NULL); | |
| 334 | |
| 335 pixGetDimensions(pixs, &w, &h, NULL); | |
| 336 if (wd <= 0) { | |
| 337 scaley = (l_float32)hd / (l_float32)h; | |
| 338 scalex = scaley; | |
| 339 } else if (hd <= 0) { | |
| 340 scalex = (l_float32)wd / (l_float32)w; | |
| 341 scaley = scalex; | |
| 342 } else { | |
| 343 scalex = (l_float32)wd / (l_float32)w; | |
| 344 scaley = (l_float32)hd / (l_float32)h; | |
| 345 } | |
| 346 | |
| 347 return pixScale(pixs, scalex, scaley); | |
| 348 } | |
| 349 | |
| 350 | |
| 351 /*! | |
| 352 * \brief pixScaleToResolution() | |
| 353 * | |
| 354 * \param[in] pixs | |
| 355 * \param[in] target desired resolution | |
| 356 * \param[in] assumed assumed resolution if not defined; typ. 300. | |
| 357 * \param[out] pscalefact [optional] actual scaling factor used | |
| 358 * \return pixd, or NULL on error | |
| 359 */ | |
| 360 PIX * | |
| 361 pixScaleToResolution(PIX *pixs, | |
| 362 l_float32 target, | |
| 363 l_float32 assumed, | |
| 364 l_float32 *pscalefact) | |
| 365 { | |
| 366 l_int32 xres; | |
| 367 l_float32 factor; | |
| 368 | |
| 369 if (pscalefact) *pscalefact = 1.0; | |
| 370 if (!pixs) | |
| 371 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 372 if (target <= 0) | |
| 373 return (PIX *)ERROR_PTR("target resolution <= 0", __func__, NULL); | |
| 374 | |
| 375 xres = pixGetXRes(pixs); | |
| 376 if (xres <= 0) { | |
| 377 if (assumed == 0) | |
| 378 return pixCopy(NULL, pixs); | |
| 379 xres = assumed; | |
| 380 } | |
| 381 factor = target / (l_float32)xres; | |
| 382 if (pscalefact) *pscalefact = factor; | |
| 383 | |
| 384 return pixScale(pixs, factor, factor); | |
| 385 } | |
| 386 | |
| 387 | |
| 388 /*! | |
| 389 * \brief pixScaleGeneral() | |
| 390 * | |
| 391 * \param[in] pixs 1, 2, 4, 8, 16 and 32 bpp | |
| 392 * \param[in] scalex must be > 0.0 | |
| 393 * \param[in] scaley must be > 0.0 | |
| 394 * \param[in] sharpfract use 0.0 to skip sharpening | |
| 395 * \param[in] sharpwidth halfwidth of low-pass filter; typ. 1 or 2 | |
| 396 * \return pixd, or NULL on error | |
| 397 * | |
| 398 * <pre> | |
| 399 * Notes: | |
| 400 * (1) See pixScale() for usage. | |
| 401 * (2) This interface may change in the future, as other special | |
| 402 * cases are added. | |
| 403 * (3) For tiny scaling factors | |
| 404 * minscale < 0.02: use a simple lowpass filter | |
| 405 * (4) The actual sharpening factors used depend on the maximum | |
| 406 * of the two scale factors (maxscale): | |
| 407 * maxscale <= 0.2: no sharpening | |
| 408 * 0.2 < maxscale < 1.4: uses the input parameters | |
| 409 * maxscale >= 1.4: no sharpening | |
| 410 * (5) To avoid sharpening for grayscale and color images with | |
| 411 * scaling factors between 0.2 and 1.4, call this function | |
| 412 * with %sharpfract == 0.0. | |
| 413 * (6) To use arbitrary sharpening in conjunction with scaling, | |
| 414 * call this function with %sharpfract = 0.0, and follow this | |
| 415 * with a call to pixUnsharpMasking() with your chosen parameters. | |
| 416 * </pre> | |
| 417 */ | |
| 418 PIX * | |
| 419 pixScaleGeneral(PIX *pixs, | |
| 420 l_float32 scalex, | |
| 421 l_float32 scaley, | |
| 422 l_float32 sharpfract, | |
| 423 l_int32 sharpwidth) | |
| 424 { | |
| 425 l_int32 d; | |
| 426 l_float32 maxscale, minscale; | |
| 427 PIX *pix1, *pix2, *pixd; | |
| 428 | |
| 429 if (!pixs) | |
| 430 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 431 d = pixGetDepth(pixs); | |
| 432 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32) | |
| 433 return (PIX *)ERROR_PTR("pixs not {1,2,4,8,16,32} bpp", __func__, NULL); | |
| 434 if (scalex <= 0.0 || scaley <= 0.0) | |
| 435 return (PIX *)ERROR_PTR("scale factor <= 0", __func__, NULL); | |
| 436 if (scalex == 1.0 && scaley == 1.0) | |
| 437 return pixCopy(NULL, pixs); | |
| 438 | |
| 439 if (d == 1) | |
| 440 return pixScaleBinary(pixs, scalex, scaley); | |
| 441 | |
| 442 /* Remove colormap; clone if possible; result is either 8 or 32 bpp */ | |
| 443 if ((pix1 = pixConvertTo8Or32(pixs, L_CLONE, 0)) == NULL) | |
| 444 return (PIX *)ERROR_PTR("pix1 not made", __func__, NULL); | |
| 445 | |
| 446 /* Scale (up or down) */ | |
| 447 d = pixGetDepth(pix1); | |
| 448 maxscale = L_MAX(scalex, scaley); | |
| 449 minscale = L_MIN(scalex, scaley); | |
| 450 if (maxscale < 0.7) { /* use low-pass filter for anti-aliasing */ | |
| 451 if (minscale < 0.02) { /* whole-pixel low-pass filter */ | |
| 452 pix2 = pixScaleSmooth(pix1, scalex, scaley); | |
| 453 } else { /* fractional pixel low-pass filter */ | |
| 454 pix2 = pixScaleAreaMap(pix1, scalex, scaley); | |
| 455 } | |
| 456 if (maxscale > 0.2 && sharpfract > 0.0 && sharpwidth > 0) { | |
| 457 pixd = pixUnsharpMasking(pix2, sharpwidth, sharpfract); | |
| 458 } else { | |
| 459 pixd = pixClone(pix2); | |
| 460 } | |
| 461 } else { /* use linear interpolation */ | |
| 462 if (d == 8) { | |
| 463 pix2 = pixScaleGrayLI(pix1, scalex, scaley); | |
| 464 } else { /* d == 32 */ | |
| 465 pix2 = pixScaleColorLI(pix1, scalex, scaley); | |
| 466 } | |
| 467 if (maxscale < 1.4 && sharpfract > 0.0 && sharpwidth > 0) { | |
| 468 pixd = pixUnsharpMasking(pix2, sharpwidth, sharpfract); | |
| 469 } else { | |
| 470 pixd = pixClone(pix2); | |
| 471 } | |
| 472 } | |
| 473 | |
| 474 pixDestroy(&pix1); | |
| 475 pixDestroy(&pix2); | |
| 476 pixCopyText(pixd, pixs); | |
| 477 pixCopyInputFormat(pixd, pixs); | |
| 478 return pixd; | |
| 479 } | |
| 480 | |
| 481 | |
| 482 /*------------------------------------------------------------------* | |
| 483 * Scaling by linear interpolation * | |
| 484 *------------------------------------------------------------------*/ | |
| 485 /*! | |
| 486 * \brief pixScaleLI() | |
| 487 * | |
| 488 * \param[in] pixs 2, 4, 8 or 32 bpp; with or without colormap | |
| 489 * \param[in] scalex must be >= 0.7 | |
| 490 * \param[in] scaley must be >= 0.7 | |
| 491 * \return pixd, or NULL on error | |
| 492 * | |
| 493 * <pre> | |
| 494 * Notes: | |
| 495 * (1) This function should only be used when the scale factors are | |
| 496 * greater than or equal to 0.7, and typically greater than 1. | |
| 497 * If both scale factors are smaller than 0.7, we issue a warning | |
| 498 * and call pixScaleGeneral(), which will invoke area mapping | |
| 499 * without sharpening. | |
| 500 * (2) This works on 2, 4, 8, 16 and 32 bpp images, as well as on | |
| 501 * 2, 4 and 8 bpp images that have a colormap. If there is a | |
| 502 * colormap, it is removed to either gray or RGB, depending | |
| 503 * on the colormap. | |
| 504 * (3) This does a linear interpolation on the src image. | |
| 505 * (4) It dispatches to much faster implementations for | |
| 506 * the special cases of 2x and 4x expansion. | |
| 507 * </pre> | |
| 508 */ | |
| 509 PIX * | |
| 510 pixScaleLI(PIX *pixs, | |
| 511 l_float32 scalex, | |
| 512 l_float32 scaley) | |
| 513 { | |
| 514 l_int32 d; | |
| 515 l_float32 maxscale; | |
| 516 PIX *pixt, *pixd; | |
| 517 | |
| 518 if (!pixs || (pixGetDepth(pixs) == 1)) | |
| 519 return (PIX *)ERROR_PTR("pixs not defined or 1 bpp", __func__, NULL); | |
| 520 maxscale = L_MAX(scalex, scaley); | |
| 521 if (maxscale < 0.7) { | |
| 522 L_WARNING("scaling factors < 0.7; do regular scaling\n", __func__); | |
| 523 return pixScaleGeneral(pixs, scalex, scaley, 0.0, 0); | |
| 524 } | |
| 525 d = pixGetDepth(pixs); | |
| 526 if (d != 2 && d != 4 && d != 8 && d != 16 && d != 32) | |
| 527 return (PIX *)ERROR_PTR("pixs not {2,4,8,16,32} bpp", __func__, NULL); | |
| 528 | |
| 529 /* Remove colormap; clone if possible; result is either 8 or 32 bpp */ | |
| 530 if ((pixt = pixConvertTo8Or32(pixs, L_CLONE, 0)) == NULL) | |
| 531 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL); | |
| 532 | |
| 533 d = pixGetDepth(pixt); | |
| 534 if (d == 8) | |
| 535 pixd = pixScaleGrayLI(pixt, scalex, scaley); | |
| 536 else /* d == 32 */ | |
| 537 pixd = pixScaleColorLI(pixt, scalex, scaley); | |
| 538 | |
| 539 pixDestroy(&pixt); | |
| 540 pixCopyInputFormat(pixd, pixs); | |
| 541 return pixd; | |
| 542 } | |
| 543 | |
| 544 | |
| 545 /*! | |
| 546 * \brief pixScaleColorLI() | |
| 547 * | |
| 548 * \param[in] pixs 32 bpp, representing rgb | |
| 549 * \param[in] scalex must be >= 0.7 | |
| 550 * \param[in] scaley must be >= 0.7 | |
| 551 * \return pixd, or NULL on error | |
| 552 * | |
| 553 * <pre> | |
| 554 * Notes: | |
| 555 * (1) If both scale factors are smaller than 0.7, we issue a warning | |
| 556 * and call pixScaleGeneral(), which will invoke area mapping | |
| 557 * without sharpening. This is particularly important for | |
| 558 * document images with sharp edges. | |
| 559 * (2) For the general case, it's about 4x faster to manipulate | |
| 560 * the color pixels directly, rather than to make images | |
| 561 * out of each of the 3 components, scale each component | |
| 562 * using the pixScaleGrayLI(), and combine the results back | |
| 563 * into an rgb image. | |
| 564 * </pre> | |
| 565 */ | |
| 566 PIX * | |
| 567 pixScaleColorLI(PIX *pixs, | |
| 568 l_float32 scalex, | |
| 569 l_float32 scaley) | |
| 570 { | |
| 571 l_int32 ws, hs, wpls, wd, hd, wpld; | |
| 572 l_uint32 *datas, *datad; | |
| 573 l_float32 maxscale; | |
| 574 PIX *pixd; | |
| 575 | |
| 576 if (!pixs || (pixGetDepth(pixs) != 32)) | |
| 577 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", __func__, NULL); | |
| 578 maxscale = L_MAX(scalex, scaley); | |
| 579 if (maxscale < 0.7) { | |
| 580 L_WARNING("scaling factors < 0.7; do regular scaling\n", __func__); | |
| 581 return pixScaleGeneral(pixs, scalex, scaley, 0.0, 0); | |
| 582 } | |
| 583 | |
| 584 /* Do fast special cases if possible */ | |
| 585 if (scalex == 1.0 && scaley == 1.0) | |
| 586 return pixCopy(NULL, pixs); | |
| 587 if (scalex == 2.0 && scaley == 2.0) | |
| 588 return pixScaleColor2xLI(pixs); | |
| 589 if (scalex == 4.0 && scaley == 4.0) | |
| 590 return pixScaleColor4xLI(pixs); | |
| 591 | |
| 592 /* General case */ | |
| 593 pixGetDimensions(pixs, &ws, &hs, NULL); | |
| 594 datas = pixGetData(pixs); | |
| 595 wpls = pixGetWpl(pixs); | |
| 596 wd = (l_int32)(scalex * (l_float32)ws + 0.5); | |
| 597 hd = (l_int32)(scaley * (l_float32)hs + 0.5); | |
| 598 if ((pixd = pixCreate(wd, hd, 32)) == NULL) | |
| 599 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 600 pixCopyResolution(pixd, pixs); | |
| 601 pixScaleResolution(pixd, scalex, scaley); | |
| 602 datad = pixGetData(pixd); | |
| 603 wpld = pixGetWpl(pixd); | |
| 604 scaleColorLILow(datad, wd, hd, wpld, datas, ws, hs, wpls); | |
| 605 if (pixGetSpp(pixs) == 4) | |
| 606 pixScaleAndTransferAlpha(pixd, pixs, scalex, scaley); | |
| 607 | |
| 608 pixCopyInputFormat(pixd, pixs); | |
| 609 return pixd; | |
| 610 } | |
| 611 | |
| 612 | |
| 613 /*! | |
| 614 * \brief pixScaleColor2xLI() | |
| 615 * | |
| 616 * \param[in] pixs 32 bpp, representing rgb | |
| 617 * \return pixd, or NULL on error | |
| 618 * | |
| 619 * <pre> | |
| 620 * Notes: | |
| 621 * (1) This is a special case of linear interpolated scaling, | |
| 622 * for 2x upscaling. It is about 8x faster than using | |
| 623 * the generic pixScaleColorLI(), and about 4x faster than | |
| 624 * using the special 2x scale function pixScaleGray2xLI() | |
| 625 * on each of the three components separately. | |
| 626 * </pre> | |
| 627 */ | |
| 628 PIX * | |
| 629 pixScaleColor2xLI(PIX *pixs) | |
| 630 { | |
| 631 l_int32 ws, hs, wpls, wpld; | |
| 632 l_uint32 *datas, *datad; | |
| 633 PIX *pixd; | |
| 634 | |
| 635 if (!pixs || (pixGetDepth(pixs) != 32)) | |
| 636 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", __func__, NULL); | |
| 637 | |
| 638 pixGetDimensions(pixs, &ws, &hs, NULL); | |
| 639 datas = pixGetData(pixs); | |
| 640 wpls = pixGetWpl(pixs); | |
| 641 if ((pixd = pixCreate(2 * ws, 2 * hs, 32)) == NULL) | |
| 642 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 643 pixCopyResolution(pixd, pixs); | |
| 644 pixScaleResolution(pixd, 2.0, 2.0); | |
| 645 datad = pixGetData(pixd); | |
| 646 wpld = pixGetWpl(pixd); | |
| 647 scaleColor2xLILow(datad, wpld, datas, ws, hs, wpls); | |
| 648 if (pixGetSpp(pixs) == 4) | |
| 649 pixScaleAndTransferAlpha(pixd, pixs, 2.0, 2.0); | |
| 650 | |
| 651 pixCopyInputFormat(pixd, pixs); | |
| 652 return pixd; | |
| 653 } | |
| 654 | |
| 655 | |
| 656 /*! | |
| 657 * \brief pixScaleColor4xLI() | |
| 658 * | |
| 659 * \param[in] pixs 32 bpp, representing rgb | |
| 660 * \return pixd, or NULL on error | |
| 661 * | |
| 662 * <pre> | |
| 663 * Notes: | |
| 664 * (1) This is a special case of color linear interpolated scaling, | |
| 665 * for 4x upscaling. It is about 3x faster than using | |
| 666 * the generic pixScaleColorLI(). | |
| 667 * (2) This scales each component separately, using pixScaleGray4xLI(). | |
| 668 * It would be about 4x faster to inline the color code properly, | |
| 669 * in analogy to scaleColor4xLILow(), and I leave this as | |
| 670 * an exercise for someone who really needs it. | |
| 671 * </pre> | |
| 672 */ | |
| 673 PIX * | |
| 674 pixScaleColor4xLI(PIX *pixs) | |
| 675 { | |
| 676 PIX *pixr, *pixg, *pixb; | |
| 677 PIX *pixrs, *pixgs, *pixbs; | |
| 678 PIX *pixd; | |
| 679 | |
| 680 if (!pixs || (pixGetDepth(pixs) != 32)) | |
| 681 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", __func__, NULL); | |
| 682 | |
| 683 pixr = pixGetRGBComponent(pixs, COLOR_RED); | |
| 684 pixrs = pixScaleGray4xLI(pixr); | |
| 685 pixDestroy(&pixr); | |
| 686 pixg = pixGetRGBComponent(pixs, COLOR_GREEN); | |
| 687 pixgs = pixScaleGray4xLI(pixg); | |
| 688 pixDestroy(&pixg); | |
| 689 pixb = pixGetRGBComponent(pixs, COLOR_BLUE); | |
| 690 pixbs = pixScaleGray4xLI(pixb); | |
| 691 pixDestroy(&pixb); | |
| 692 | |
| 693 if ((pixd = pixCreateRGBImage(pixrs, pixgs, pixbs)) == NULL) { | |
| 694 L_ERROR("pixd not made\n", __func__); | |
| 695 } else { | |
| 696 if (pixGetSpp(pixs) == 4) | |
| 697 pixScaleAndTransferAlpha(pixd, pixs, 4.0, 4.0); | |
| 698 pixCopyInputFormat(pixd, pixs); | |
| 699 } | |
| 700 | |
| 701 pixDestroy(&pixrs); | |
| 702 pixDestroy(&pixgs); | |
| 703 pixDestroy(&pixbs); | |
| 704 return pixd; | |
| 705 } | |
| 706 | |
| 707 | |
| 708 /*! | |
| 709 * \brief pixScaleGrayLI() | |
| 710 * | |
| 711 * \param[in] pixs 8 bpp grayscale, no cmap | |
| 712 * \param[in] scalex must be >= 0.7 | |
| 713 * \param[in] scaley must be >= 0.7 | |
| 714 * \return pixd, or NULL on error | |
| 715 * | |
| 716 * <pre> | |
| 717 * Notes: | |
| 718 * (1) This function is appropriate for upscaling magnification, where the | |
| 719 * scale factor is > 1, as well as for a small amount of downscaling | |
| 720 * reduction, with scale factor >= 0.7. If the scale factor is < 0.7, | |
| 721 * the best result is obtained by area mapping. | |
| 722 * (2) Here are some details: | |
| 723 * - For each pixel in the dest, this does a linear | |
| 724 * interpolation of 4 neighboring pixels in the src. | |
| 725 * Specifically, consider the UL corner of src and | |
| 726 * dest pixels. The UL corner of the dest falls within | |
| 727 * a src pixel, whose four corners are the UL corners | |
| 728 * of 4 adjacent src pixels. The value of the dest | |
| 729 * is taken by linear interpolation using the values of | |
| 730 * the four src pixels and the distance of the UL corner | |
| 731 * of the dest from each corner. | |
| 732 * - If the image is expanded so that the dest pixel is | |
| 733 * smaller than the src pixel, such interpolation | |
| 734 * is a reasonable approach. This interpolation is | |
| 735 * also good for a small image reduction factor that | |
| 736 * is not more than a 2x reduction. | |
| 737 * - The linear interpolation algorithm for scaling is | |
| 738 * identical in form to the area-mapping algorithm | |
| 739 * for grayscale rotation. The latter corresponds to a | |
| 740 * translation of each pixel without scaling. | |
| 741 * - This function is NOT optimal if the scaling involves | |
| 742 * a large reduction. If the image is significantly | |
| 743 * reduced, so that the dest pixel is much larger than | |
| 744 * the src pixels, this interpolation, which is over src | |
| 745 * pixels only near the UL corner of the dest pixel, | |
| 746 * is not going to give a good area-mapping average. | |
| 747 * Because area mapping for image scaling is considerably | |
| 748 * more computationally intensive than linear interpolation, | |
| 749 * we choose not to use it. For large image reduction, | |
| 750 * linear interpolation over adjacent src pixels | |
| 751 * degenerates asymptotically to subsampling. But | |
| 752 * subsampling without a low-pass pre-filter causes | |
| 753 * aliasing by the nyquist theorem. To avoid aliasing, | |
| 754 * a low-pass filter e.g., an averaging filter of | |
| 755 * size roughly equal to the dest pixel i.e., the reduction | |
| 756 * factor should be applied to the src before subsampling. | |
| 757 * - As an alternative to low-pass filtering and subsampling | |
| 758 * for large reduction factors, linear interpolation can | |
| 759 * also be done between the widely separated src pixels in | |
| 760 * which the corners of the dest pixel lie. This also is | |
| 761 * not optimal, as it samples src pixels only near the | |
| 762 * corners of the dest pixel, and it is not implemented. | |
| 763 * </pre> | |
| 764 */ | |
| 765 PIX * | |
| 766 pixScaleGrayLI(PIX *pixs, | |
| 767 l_float32 scalex, | |
| 768 l_float32 scaley) | |
| 769 { | |
| 770 l_int32 ws, hs, wpls, wd, hd, wpld; | |
| 771 l_uint32 *datas, *datad; | |
| 772 l_float32 maxscale; | |
| 773 PIX *pixd; | |
| 774 | |
| 775 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs)) | |
| 776 return (PIX *)ERROR_PTR("pixs undefined, cmapped or not 8 bpp", | |
| 777 __func__, NULL); | |
| 778 maxscale = L_MAX(scalex, scaley); | |
| 779 if (maxscale < 0.7) { | |
| 780 L_WARNING("scaling factors < 0.7; do regular scaling\n", __func__); | |
| 781 return pixScaleGeneral(pixs, scalex, scaley, 0.0, 0); | |
| 782 } | |
| 783 | |
| 784 /* Do fast special cases if possible */ | |
| 785 if (scalex == 1.0 && scaley == 1.0) | |
| 786 return pixCopy(NULL, pixs); | |
| 787 if (scalex == 2.0 && scaley == 2.0) | |
| 788 return pixScaleGray2xLI(pixs); | |
| 789 if (scalex == 4.0 && scaley == 4.0) | |
| 790 return pixScaleGray4xLI(pixs); | |
| 791 | |
| 792 /* General case */ | |
| 793 pixGetDimensions(pixs, &ws, &hs, NULL); | |
| 794 datas = pixGetData(pixs); | |
| 795 wpls = pixGetWpl(pixs); | |
| 796 wd = (l_int32)(scalex * (l_float32)ws + 0.5); | |
| 797 hd = (l_int32)(scaley * (l_float32)hs + 0.5); | |
| 798 if ((pixd = pixCreate(wd, hd, 8)) == NULL) | |
| 799 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 800 pixCopyText(pixd, pixs); | |
| 801 pixCopyResolution(pixd, pixs); | |
| 802 pixCopyInputFormat(pixd, pixs); | |
| 803 pixScaleResolution(pixd, scalex, scaley); | |
| 804 datad = pixGetData(pixd); | |
| 805 wpld = pixGetWpl(pixd); | |
| 806 scaleGrayLILow(datad, wd, hd, wpld, datas, ws, hs, wpls); | |
| 807 return pixd; | |
| 808 } | |
| 809 | |
| 810 | |
| 811 /*! | |
| 812 * \brief pixScaleGray2xLI() | |
| 813 * | |
| 814 * \param[in] pixs 8 bpp grayscale, not cmapped | |
| 815 * \return pixd, or NULL on error | |
| 816 * | |
| 817 * <pre> | |
| 818 * Notes: | |
| 819 * (1) This is a special case of gray linear interpolated scaling, | |
| 820 * for 2x upscaling. It is about 6x faster than using | |
| 821 * the generic pixScaleGrayLI(). | |
| 822 * </pre> | |
| 823 */ | |
| 824 PIX * | |
| 825 pixScaleGray2xLI(PIX *pixs) | |
| 826 { | |
| 827 l_int32 ws, hs, wpls, wpld; | |
| 828 l_uint32 *datas, *datad; | |
| 829 PIX *pixd; | |
| 830 | |
| 831 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs)) | |
| 832 return (PIX *)ERROR_PTR("pixs undefined, cmapped or not 8 bpp", | |
| 833 __func__, NULL); | |
| 834 | |
| 835 pixGetDimensions(pixs, &ws, &hs, NULL); | |
| 836 datas = pixGetData(pixs); | |
| 837 wpls = pixGetWpl(pixs); | |
| 838 if ((pixd = pixCreate(2 * ws, 2 * hs, 8)) == NULL) | |
| 839 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 840 pixCopyResolution(pixd, pixs); | |
| 841 pixCopyInputFormat(pixd, pixs); | |
| 842 pixScaleResolution(pixd, 2.0, 2.0); | |
| 843 datad = pixGetData(pixd); | |
| 844 wpld = pixGetWpl(pixd); | |
| 845 scaleGray2xLILow(datad, wpld, datas, ws, hs, wpls); | |
| 846 return pixd; | |
| 847 } | |
| 848 | |
| 849 | |
| 850 /*! | |
| 851 * \brief pixScaleGray4xLI() | |
| 852 * | |
| 853 * \param[in] pixs 8 bpp grayscale, not cmapped | |
| 854 * \return pixd, or NULL on error | |
| 855 * | |
| 856 * <pre> | |
| 857 * Notes: | |
| 858 * (1) This is a special case of gray linear interpolated scaling, | |
| 859 * for 4x upscaling. It is about 12x faster than using | |
| 860 * the generic pixScaleGrayLI(). | |
| 861 * </pre> | |
| 862 */ | |
| 863 PIX * | |
| 864 pixScaleGray4xLI(PIX *pixs) | |
| 865 { | |
| 866 l_int32 ws, hs, wpls, wpld; | |
| 867 l_uint32 *datas, *datad; | |
| 868 PIX *pixd; | |
| 869 | |
| 870 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs)) | |
| 871 return (PIX *)ERROR_PTR("pixs undefined, cmapped or not 8 bpp", | |
| 872 __func__, NULL); | |
| 873 | |
| 874 pixGetDimensions(pixs, &ws, &hs, NULL); | |
| 875 datas = pixGetData(pixs); | |
| 876 wpls = pixGetWpl(pixs); | |
| 877 if ((pixd = pixCreate(4 * ws, 4 * hs, 8)) == NULL) | |
| 878 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 879 pixCopyResolution(pixd, pixs); | |
| 880 pixCopyInputFormat(pixd, pixs); | |
| 881 pixScaleResolution(pixd, 4.0, 4.0); | |
| 882 datad = pixGetData(pixd); | |
| 883 wpld = pixGetWpl(pixd); | |
| 884 scaleGray4xLILow(datad, wpld, datas, ws, hs, wpls); | |
| 885 return pixd; | |
| 886 } | |
| 887 | |
| 888 | |
| 889 /*------------------------------------------------------------------* | |
| 890 * Scale 2x followed by binarization * | |
| 891 *------------------------------------------------------------------*/ | |
| 892 /*! | |
| 893 * \brief pixScaleGray2xLIThresh() | |
| 894 * | |
| 895 * \param[in] pixs 8 bpp, not cmapped | |
| 896 * \param[in] thresh between 0 and 256 | |
| 897 * \return pixd 1 bpp, or NULL on error | |
| 898 * | |
| 899 * <pre> | |
| 900 * Notes: | |
| 901 * (1) This does 2x upscale on pixs, using linear interpolation, | |
| 902 * followed by thresholding to binary. | |
| 903 * (2) Buffers are used to avoid making a large grayscale image. | |
| 904 * </pre> | |
| 905 */ | |
| 906 PIX * | |
| 907 pixScaleGray2xLIThresh(PIX *pixs, | |
| 908 l_int32 thresh) | |
| 909 { | |
| 910 l_int32 i, ws, hs, hsm, wd, hd, wpls, wplb, wpld; | |
| 911 l_uint32 *datas, *datad, *lines, *lined, *lineb; | |
| 912 PIX *pixd; | |
| 913 | |
| 914 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs)) | |
| 915 return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped", | |
| 916 __func__, NULL); | |
| 917 if (thresh < 0 || thresh > 256) | |
| 918 return (PIX *)ERROR_PTR("thresh must be in [0, ... 256]", | |
| 919 __func__, NULL); | |
| 920 | |
| 921 pixGetDimensions(pixs, &ws, &hs, NULL); | |
| 922 wd = 2 * ws; | |
| 923 hd = 2 * hs; | |
| 924 hsm = hs - 1; | |
| 925 datas = pixGetData(pixs); | |
| 926 wpls = pixGetWpl(pixs); | |
| 927 | |
| 928 /* Make line buffer for 2 lines of virtual intermediate image */ | |
| 929 wplb = (wd + 3) / 4; | |
| 930 if ((lineb = (l_uint32 *)LEPT_CALLOC(2 * wplb, sizeof(l_uint32))) == NULL) | |
| 931 return (PIX *)ERROR_PTR("lineb not made", __func__, NULL); | |
| 932 | |
| 933 /* Make dest binary image */ | |
| 934 if ((pixd = pixCreate(wd, hd, 1)) == NULL) { | |
| 935 LEPT_FREE(lineb); | |
| 936 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 937 } | |
| 938 pixCopyInputFormat(pixd, pixs); | |
| 939 pixCopyResolution(pixd, pixs); | |
| 940 pixScaleResolution(pixd, 2.0, 2.0); | |
| 941 wpld = pixGetWpl(pixd); | |
| 942 datad = pixGetData(pixd); | |
| 943 | |
| 944 /* Do all but last src line */ | |
| 945 for (i = 0; i < hsm; i++) { | |
| 946 lines = datas + i * wpls; | |
| 947 lined = datad + 2 * i * wpld; /* do 2 dest lines at a time */ | |
| 948 scaleGray2xLILineLow(lineb, wplb, lines, ws, wpls, 0); | |
| 949 thresholdToBinaryLineLow(lined, wd, lineb, 8, thresh); | |
| 950 thresholdToBinaryLineLow(lined + wpld, wd, lineb + wplb, 8, thresh); | |
| 951 } | |
| 952 | |
| 953 /* Do last src line */ | |
| 954 lines = datas + hsm * wpls; | |
| 955 lined = datad + 2 * hsm * wpld; | |
| 956 scaleGray2xLILineLow(lineb, wplb, lines, ws, wpls, 1); | |
| 957 thresholdToBinaryLineLow(lined, wd, lineb, 8, thresh); | |
| 958 thresholdToBinaryLineLow(lined + wpld, wd, lineb + wplb, 8, thresh); | |
| 959 | |
| 960 LEPT_FREE(lineb); | |
| 961 return pixd; | |
| 962 } | |
| 963 | |
| 964 | |
| 965 /*! | |
| 966 * \brief pixScaleGray2xLIDither() | |
| 967 * | |
| 968 * \param[in] pixs 8 bpp, not cmapped | |
| 969 * \return pixd 1 bpp, or NULL on error | |
| 970 * | |
| 971 * <pre> | |
| 972 * Notes: | |
| 973 * (1) This does 2x upscale on pixs, using linear interpolation, | |
| 974 * followed by Floyd-Steinberg dithering to binary. | |
| 975 * (2) Buffers are used to avoid making a large grayscale image. | |
| 976 * ~ Two line buffers are used for the src, required for the 2x | |
| 977 * LI upscale. | |
| 978 * ~ Three line buffers are used for the intermediate image. | |
| 979 * Two are filled with each 2xLI row operation; the third is | |
| 980 * needed because the upscale and dithering ops are out of sync. | |
| 981 * </pre> | |
| 982 */ | |
| 983 PIX * | |
| 984 pixScaleGray2xLIDither(PIX *pixs) | |
| 985 { | |
| 986 l_int32 i, ws, hs, hsm, wd, hd, wpls, wplb, wpld; | |
| 987 l_uint32 *datas, *datad; | |
| 988 l_uint32 *lined; | |
| 989 l_uint32 *lineb = NULL; /* 2 intermediate buffer lines */ | |
| 990 l_uint32 *linebp = NULL; /* 1 intermediate buffer line */ | |
| 991 l_uint32 *bufs = NULL; /* 2 source buffer lines */ | |
| 992 PIX *pixd = NULL; | |
| 993 | |
| 994 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs)) | |
| 995 return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped", | |
| 996 __func__, NULL); | |
| 997 | |
| 998 pixGetDimensions(pixs, &ws, &hs, NULL); | |
| 999 wd = 2 * ws; | |
| 1000 hd = 2 * hs; | |
| 1001 hsm = hs - 1; | |
| 1002 datas = pixGetData(pixs); | |
| 1003 wpls = pixGetWpl(pixs); | |
| 1004 | |
| 1005 /* Make line buffers for 2 lines of src image */ | |
| 1006 if ((bufs = (l_uint32 *)LEPT_CALLOC(2 * wpls, sizeof(l_uint32))) == NULL) | |
| 1007 return (PIX *)ERROR_PTR("bufs not made", __func__, NULL); | |
| 1008 | |
| 1009 /* Make line buffer for 2 lines of virtual intermediate image */ | |
| 1010 wplb = (wd + 3) / 4; | |
| 1011 if ((lineb = (l_uint32 *)LEPT_CALLOC(2 * wplb, sizeof(l_uint32))) == NULL) { | |
| 1012 L_ERROR("lineb not made\n", __func__); | |
| 1013 goto cleanup; | |
| 1014 } | |
| 1015 | |
| 1016 /* Make line buffer for 1 line of virtual intermediate image */ | |
| 1017 if ((linebp = (l_uint32 *)LEPT_CALLOC(wplb, sizeof(l_uint32))) == NULL) { | |
| 1018 L_ERROR("linebp not made\n", __func__); | |
| 1019 goto cleanup; | |
| 1020 } | |
| 1021 | |
| 1022 /* Make dest binary image */ | |
| 1023 if ((pixd = pixCreate(wd, hd, 1)) == NULL) { | |
| 1024 L_ERROR("pixd not made\n", __func__); | |
| 1025 goto cleanup; | |
| 1026 } | |
| 1027 pixCopyInputFormat(pixd, pixs); | |
| 1028 pixCopyResolution(pixd, pixs); | |
| 1029 pixScaleResolution(pixd, 2.0, 2.0); | |
| 1030 wpld = pixGetWpl(pixd); | |
| 1031 datad = pixGetData(pixd); | |
| 1032 | |
| 1033 /* Start with the first src and the first dest line */ | |
| 1034 memcpy(bufs, datas, 4 * wpls); /* first src line */ | |
| 1035 memcpy(bufs + wpls, datas + wpls, 4 * wpls); /* 2nd src line */ | |
| 1036 scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 2 i lines */ | |
| 1037 lined = datad; | |
| 1038 ditherToBinaryLineLow(lined, wd, lineb, lineb + wplb, | |
| 1039 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0); | |
| 1040 /* 1st d line */ | |
| 1041 | |
| 1042 /* Do all but last src line */ | |
| 1043 for (i = 1; i < hsm; i++) { | |
| 1044 memcpy(bufs, datas + i * wpls, 4 * wpls); /* i-th src line */ | |
| 1045 memcpy(bufs + wpls, datas + (i + 1) * wpls, 4 * wpls); | |
| 1046 memcpy(linebp, lineb + wplb, 4 * wplb); | |
| 1047 scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 2 i lines */ | |
| 1048 lined = datad + 2 * i * wpld; | |
| 1049 ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb, | |
| 1050 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0); | |
| 1051 /* odd dest line */ | |
| 1052 ditherToBinaryLineLow(lined, wd, lineb, lineb + wplb, | |
| 1053 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0); | |
| 1054 /* even dest line */ | |
| 1055 } | |
| 1056 | |
| 1057 /* Do the last src line and the last 3 dest lines */ | |
| 1058 memcpy(bufs, datas + hsm * wpls, 4 * wpls); /* hsm-th src line */ | |
| 1059 memcpy(linebp, lineb + wplb, 4 * wplb); /* 1 i line */ | |
| 1060 scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 1); /* 2 i lines */ | |
| 1061 ditherToBinaryLineLow(lined + wpld, wd, linebp, lineb, | |
| 1062 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0); | |
| 1063 /* odd dest line */ | |
| 1064 ditherToBinaryLineLow(lined + 2 * wpld, wd, lineb, lineb + wplb, | |
| 1065 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0); | |
| 1066 /* even dest line */ | |
| 1067 ditherToBinaryLineLow(lined + 3 * wpld, wd, lineb + wplb, NULL, | |
| 1068 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 1); | |
| 1069 /* last dest line */ | |
| 1070 | |
| 1071 cleanup: | |
| 1072 LEPT_FREE(bufs); | |
| 1073 LEPT_FREE(lineb); | |
| 1074 LEPT_FREE(linebp); | |
| 1075 return pixd; | |
| 1076 } | |
| 1077 | |
| 1078 | |
| 1079 /*------------------------------------------------------------------* | |
| 1080 * Scale 4x followed by binarization * | |
| 1081 *------------------------------------------------------------------*/ | |
| 1082 /*! | |
| 1083 * \brief pixScaleGray4xLIThresh() | |
| 1084 * | |
| 1085 * \param[in] pixs 8 bpp | |
| 1086 * \param[in] thresh between 0 and 256 | |
| 1087 * \return pixd 1 bpp, or NULL on error | |
| 1088 * | |
| 1089 * <pre> | |
| 1090 * Notes: | |
| 1091 * (1) This does 4x upscale on pixs, using linear interpolation, | |
| 1092 * followed by thresholding to binary. | |
| 1093 * (2) Buffers are used to avoid making a large grayscale image. | |
| 1094 * (3) If a full 4x expanded grayscale image can be kept in memory, | |
| 1095 * this function is only about 10% faster than separately doing | |
| 1096 * a linear interpolation to a large grayscale image, followed | |
| 1097 * by thresholding to binary. | |
| 1098 * </pre> | |
| 1099 */ | |
| 1100 PIX * | |
| 1101 pixScaleGray4xLIThresh(PIX *pixs, | |
| 1102 l_int32 thresh) | |
| 1103 { | |
| 1104 l_int32 i, j, ws, hs, hsm, wd, hd, wpls, wplb, wpld; | |
| 1105 l_uint32 *datas, *datad, *lines, *lined, *lineb; | |
| 1106 PIX *pixd; | |
| 1107 | |
| 1108 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs)) | |
| 1109 return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped", | |
| 1110 __func__, NULL); | |
| 1111 if (thresh < 0 || thresh > 256) | |
| 1112 return (PIX *)ERROR_PTR("thresh must be in [0, ... 256]", | |
| 1113 __func__, NULL); | |
| 1114 | |
| 1115 pixGetDimensions(pixs, &ws, &hs, NULL); | |
| 1116 wd = 4 * ws; | |
| 1117 hd = 4 * hs; | |
| 1118 hsm = hs - 1; | |
| 1119 datas = pixGetData(pixs); | |
| 1120 wpls = pixGetWpl(pixs); | |
| 1121 | |
| 1122 /* Make line buffer for 4 lines of virtual intermediate image */ | |
| 1123 wplb = (wd + 3) / 4; | |
| 1124 if ((lineb = (l_uint32 *)LEPT_CALLOC(4 * wplb, sizeof(l_uint32))) == NULL) | |
| 1125 return (PIX *)ERROR_PTR("lineb not made", __func__, NULL); | |
| 1126 | |
| 1127 /* Make dest binary image */ | |
| 1128 if ((pixd = pixCreate(wd, hd, 1)) == NULL) { | |
| 1129 LEPT_FREE(lineb); | |
| 1130 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 1131 } | |
| 1132 pixCopyInputFormat(pixd, pixs); | |
| 1133 pixCopyResolution(pixd, pixs); | |
| 1134 pixScaleResolution(pixd, 4.0, 4.0); | |
| 1135 wpld = pixGetWpl(pixd); | |
| 1136 datad = pixGetData(pixd); | |
| 1137 | |
| 1138 /* Do all but last src line */ | |
| 1139 for (i = 0; i < hsm; i++) { | |
| 1140 lines = datas + i * wpls; | |
| 1141 lined = datad + 4 * i * wpld; /* do 4 dest lines at a time */ | |
| 1142 scaleGray4xLILineLow(lineb, wplb, lines, ws, wpls, 0); | |
| 1143 for (j = 0; j < 4; j++) { | |
| 1144 thresholdToBinaryLineLow(lined + j * wpld, wd, | |
| 1145 lineb + j * wplb, 8, thresh); | |
| 1146 } | |
| 1147 } | |
| 1148 | |
| 1149 /* Do last src line */ | |
| 1150 lines = datas + hsm * wpls; | |
| 1151 lined = datad + 4 * hsm * wpld; | |
| 1152 scaleGray4xLILineLow(lineb, wplb, lines, ws, wpls, 1); | |
| 1153 for (j = 0; j < 4; j++) { | |
| 1154 thresholdToBinaryLineLow(lined + j * wpld, wd, | |
| 1155 lineb + j * wplb, 8, thresh); | |
| 1156 } | |
| 1157 | |
| 1158 LEPT_FREE(lineb); | |
| 1159 return pixd; | |
| 1160 } | |
| 1161 | |
| 1162 | |
| 1163 /*! | |
| 1164 * \brief pixScaleGray4xLIDither() | |
| 1165 * | |
| 1166 * \param[in] pixs 8 bpp, not cmapped | |
| 1167 * \return pixd 1 bpp, or NULL on error | |
| 1168 * | |
| 1169 * <pre> | |
| 1170 * Notes: | |
| 1171 * (1) This does 4x upscale on pixs, using linear interpolation, | |
| 1172 * followed by Floyd-Steinberg dithering to binary. | |
| 1173 * (2) Buffers are used to avoid making a large grayscale image. | |
| 1174 * ~ Two line buffers are used for the src, required for the | |
| 1175 * 4xLI upscale. | |
| 1176 * ~ Five line buffers are used for the intermediate image. | |
| 1177 * Four are filled with each 4xLI row operation; the fifth | |
| 1178 * is needed because the upscale and dithering ops are | |
| 1179 * out of sync. | |
| 1180 * (3) If a full 4x expanded grayscale image can be kept in memory, | |
| 1181 * this function is only about 5% faster than separately doing | |
| 1182 * a linear interpolation to a large grayscale image, followed | |
| 1183 * by error-diffusion dithering to binary. | |
| 1184 * </pre> | |
| 1185 */ | |
| 1186 PIX * | |
| 1187 pixScaleGray4xLIDither(PIX *pixs) | |
| 1188 { | |
| 1189 l_int32 i, j, ws, hs, hsm, wd, hd, wpls, wplb, wpld; | |
| 1190 l_uint32 *datas, *datad; | |
| 1191 l_uint32 *lined; | |
| 1192 l_uint32 *lineb = NULL; /* 4 intermediate buffer lines */ | |
| 1193 l_uint32 *linebp = NULL; /* 1 intermediate buffer line */ | |
| 1194 l_uint32 *bufs = NULL; /* 2 source buffer lines */ | |
| 1195 PIX *pixd = NULL; | |
| 1196 | |
| 1197 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs)) | |
| 1198 return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped", | |
| 1199 __func__, NULL); | |
| 1200 | |
| 1201 pixGetDimensions(pixs, &ws, &hs, NULL); | |
| 1202 wd = 4 * ws; | |
| 1203 hd = 4 * hs; | |
| 1204 hsm = hs - 1; | |
| 1205 datas = pixGetData(pixs); | |
| 1206 wpls = pixGetWpl(pixs); | |
| 1207 | |
| 1208 /* Make line buffers for 2 lines of src image */ | |
| 1209 if ((bufs = (l_uint32 *)LEPT_CALLOC(2 * wpls, sizeof(l_uint32))) == NULL) | |
| 1210 return (PIX *)ERROR_PTR("bufs not made", __func__, NULL); | |
| 1211 | |
| 1212 /* Make line buffer for 4 lines of virtual intermediate image */ | |
| 1213 wplb = (wd + 3) / 4; | |
| 1214 if ((lineb = (l_uint32 *)LEPT_CALLOC(4 * wplb, sizeof(l_uint32))) == NULL) { | |
| 1215 L_ERROR("lineb not made\n", __func__); | |
| 1216 goto cleanup; | |
| 1217 } | |
| 1218 | |
| 1219 /* Make line buffer for 1 line of virtual intermediate image */ | |
| 1220 if ((linebp = (l_uint32 *)LEPT_CALLOC(wplb, sizeof(l_uint32))) == NULL) { | |
| 1221 L_ERROR("linebp not made\n", __func__); | |
| 1222 goto cleanup; | |
| 1223 } | |
| 1224 | |
| 1225 /* Make dest binary image */ | |
| 1226 if ((pixd = pixCreate(wd, hd, 1)) == NULL) { | |
| 1227 L_ERROR("pixd not made\n", __func__); | |
| 1228 goto cleanup; | |
| 1229 } | |
| 1230 pixCopyInputFormat(pixd, pixs); | |
| 1231 pixCopyResolution(pixd, pixs); | |
| 1232 pixScaleResolution(pixd, 4.0, 4.0); | |
| 1233 wpld = pixGetWpl(pixd); | |
| 1234 datad = pixGetData(pixd); | |
| 1235 | |
| 1236 /* Start with the first src and the first 3 dest lines */ | |
| 1237 memcpy(bufs, datas, 4 * wpls); /* first src line */ | |
| 1238 memcpy(bufs + wpls, datas + wpls, 4 * wpls); /* 2nd src line */ | |
| 1239 scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 4 b lines */ | |
| 1240 lined = datad; | |
| 1241 for (j = 0; j < 3; j++) { /* first 3 d lines of Q */ | |
| 1242 ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb, | |
| 1243 lineb + (j + 1) * wplb, | |
| 1244 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0); | |
| 1245 } | |
| 1246 | |
| 1247 /* Do all but last src line */ | |
| 1248 for (i = 1; i < hsm; i++) { | |
| 1249 memcpy(bufs, datas + i * wpls, 4 * wpls); /* i-th src line */ | |
| 1250 memcpy(bufs + wpls, datas + (i + 1) * wpls, 4 * wpls); | |
| 1251 memcpy(linebp, lineb + 3 * wplb, 4 * wplb); | |
| 1252 scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 4 b lines */ | |
| 1253 lined = datad + 4 * i * wpld; | |
| 1254 ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb, | |
| 1255 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0); | |
| 1256 /* 4th dest line of Q */ | |
| 1257 for (j = 0; j < 3; j++) { /* next 3 d lines of Quad */ | |
| 1258 ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb, | |
| 1259 lineb + (j + 1) * wplb, | |
| 1260 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0); | |
| 1261 } | |
| 1262 } | |
| 1263 | |
| 1264 /* Do the last src line and the last 5 dest lines */ | |
| 1265 memcpy(bufs, datas + hsm * wpls, 4 * wpls); /* hsm-th src line */ | |
| 1266 memcpy(linebp, lineb + 3 * wplb, 4 * wplb); /* 1 b line */ | |
| 1267 scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 1); /* 4 b lines */ | |
| 1268 lined = datad + 4 * hsm * wpld; | |
| 1269 ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb, | |
| 1270 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0); | |
| 1271 /* 4th dest line of Q */ | |
| 1272 for (j = 0; j < 3; j++) { /* next 3 d lines of Quad */ | |
| 1273 ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb, | |
| 1274 lineb + (j + 1) * wplb, | |
| 1275 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0); | |
| 1276 } | |
| 1277 /* And finally, the last dest line */ | |
| 1278 ditherToBinaryLineLow(lined + 3 * wpld, wd, lineb + 3 * wplb, NULL, | |
| 1279 DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 1); | |
| 1280 | |
| 1281 cleanup: | |
| 1282 LEPT_FREE(bufs); | |
| 1283 LEPT_FREE(lineb); | |
| 1284 LEPT_FREE(linebp); | |
| 1285 return pixd; | |
| 1286 } | |
| 1287 | |
| 1288 | |
| 1289 /*------------------------------------------------------------------* | |
| 1290 * Scaling by closest pixel sampling * | |
| 1291 *------------------------------------------------------------------*/ | |
| 1292 /*! | |
| 1293 * \brief pixScaleBySampling() | |
| 1294 * | |
| 1295 * \param[in] pixs 1, 2, 4, 8, 16, 32 bpp | |
| 1296 * \param[in] scalex must be > 0.0 | |
| 1297 * \param[in] scaley must be > 0.0 | |
| 1298 * \return pixd, or NULL on error | |
| 1299 * | |
| 1300 * <pre> | |
| 1301 * Notes: | |
| 1302 * (1) This function samples from the source without | |
| 1303 * filtering. As a result, aliasing will occur for | |
| 1304 * subsampling (%scalex and/or %scaley < 1.0). | |
| 1305 * (2) If %scalex == 1.0 and %scaley == 1.0, returns a copy. | |
| 1306 * (3) For upscaling by an integer, use pixExpandReplicate(). | |
| 1307 * (4) By default, indexing for the sampled source pixel is done | |
| 1308 * by rounding. This shifts the source pixel sampling down | |
| 1309 * and to the right by half a pixel, which has the effect of | |
| 1310 * shifting the destination image up and to the left by a | |
| 1311 * number of pixels approximately equal to half the scaling | |
| 1312 * factor. To avoid this shift in the destination image, | |
| 1313 * call pixScalebySamplingWithShift() using 0 for both shifts. | |
| 1314 * </pre> | |
| 1315 */ | |
| 1316 PIX * | |
| 1317 pixScaleBySampling(PIX *pixs, | |
| 1318 l_float32 scalex, | |
| 1319 l_float32 scaley) | |
| 1320 { | |
| 1321 if (!pixs) | |
| 1322 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 1323 return pixScaleBySamplingWithShift(pixs, scalex, scaley, 0.5, 0.5); | |
| 1324 } | |
| 1325 | |
| 1326 | |
| 1327 /*! | |
| 1328 * \brief pixScaleBySamplingWithShift() | |
| 1329 * | |
| 1330 * \param[in] pixs 1, 2, 4, 8, 16, 32 bpp | |
| 1331 * \param[in] scalex must be > 0.0 | |
| 1332 * \param[in] scaley must be > 0.0 | |
| 1333 * \param[in] shiftx 0.5 for default; 0.0 to mihimize edge effects | |
| 1334 * \param[in] shifty 0.5 for default; 0.0 to mihimize edge effects | |
| 1335 * \return pixd, or NULL on error | |
| 1336 * | |
| 1337 * <pre> | |
| 1338 * Notes: | |
| 1339 * (1) The @shiftx and @shifty parameters are usually unimportant. | |
| 1340 * Visible artifacts are minimized by using 0.0. | |
| 1341 * Allowed values are 0.0 and 0.5. | |
| 1342 * </pre> | |
| 1343 */ | |
| 1344 PIX * | |
| 1345 pixScaleBySamplingWithShift(PIX *pixs, | |
| 1346 l_float32 scalex, | |
| 1347 l_float32 scaley, | |
| 1348 l_float32 shiftx, | |
| 1349 l_float32 shifty) | |
| 1350 { | |
| 1351 l_int32 ws, hs, d, wpls, wd, hd, wpld; | |
| 1352 l_uint32 *datas, *datad; | |
| 1353 PIX *pixd; | |
| 1354 | |
| 1355 if (!pixs) | |
| 1356 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 1357 if (scalex <= 0.0 || scaley <= 0.0) | |
| 1358 return (PIX *)ERROR_PTR("scale factor <= 0", __func__, NULL); | |
| 1359 if (scalex == 1.0 && scaley == 1.0) | |
| 1360 return pixCopy(NULL, pixs); | |
| 1361 if (shiftx != 0.0 && shiftx != 0.5) | |
| 1362 return (PIX *)ERROR_PTR("shiftx != 0.0 or 0.5", __func__, NULL); | |
| 1363 if (shifty != 0.0 && shifty != 0.5) | |
| 1364 return (PIX *)ERROR_PTR("shifty != 0.0 or 0.5", __func__, NULL); | |
| 1365 if ((d = pixGetDepth(pixs)) == 1) | |
| 1366 return pixScaleBinaryWithShift(pixs, scalex, scaley, shiftx, shifty); | |
| 1367 | |
| 1368 pixGetDimensions(pixs, &ws, &hs, NULL); | |
| 1369 datas = pixGetData(pixs); | |
| 1370 wpls = pixGetWpl(pixs); | |
| 1371 wd = (l_int32)(scalex * (l_float32)ws + 0.5); | |
| 1372 hd = (l_int32)(scaley * (l_float32)hs + 0.5); | |
| 1373 if ((pixd = pixCreate(wd, hd, d)) == NULL) | |
| 1374 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 1375 pixCopyResolution(pixd, pixs); | |
| 1376 pixScaleResolution(pixd, scalex, scaley); | |
| 1377 pixCopyColormap(pixd, pixs); | |
| 1378 pixCopyText(pixd, pixs); | |
| 1379 pixCopyInputFormat(pixd, pixs); | |
| 1380 pixCopySpp(pixd, pixs); | |
| 1381 datad = pixGetData(pixd); | |
| 1382 wpld = pixGetWpl(pixd); | |
| 1383 scaleBySamplingLow(datad, wd, hd, wpld, datas, ws, hs, d, wpls, | |
| 1384 shiftx, shifty); | |
| 1385 if (d == 32 && pixGetSpp(pixs) == 4) | |
| 1386 pixScaleAndTransferAlpha(pixd, pixs, scalex, scaley); | |
| 1387 | |
| 1388 return pixd; | |
| 1389 } | |
| 1390 | |
| 1391 | |
| 1392 /*! | |
| 1393 * \brief pixScaleBySamplingToSize() | |
| 1394 * | |
| 1395 * \param[in] pixs 1, 2, 4, 8, 16 and 32 bpp | |
| 1396 * \param[in] wd target width; use 0 if using height as target | |
| 1397 * \param[in] hd target height; use 0 if using width as target | |
| 1398 * \return pixd, or NULL on error | |
| 1399 * | |
| 1400 * <pre> | |
| 1401 * Notes: | |
| 1402 * (1) This guarantees that the output scaled image has the | |
| 1403 * dimension(s) you specify. | |
| 1404 * ~ To specify the width with isotropic scaling, set %hd = 0. | |
| 1405 * ~ To specify the height with isotropic scaling, set %wd = 0. | |
| 1406 * ~ If both %wd and %hd are specified, the image is scaled | |
| 1407 * (in general, anisotropically) to that size. | |
| 1408 * ~ It is an error to set both %wd and %hd to 0. | |
| 1409 * </pre> | |
| 1410 */ | |
| 1411 PIX * | |
| 1412 pixScaleBySamplingToSize(PIX *pixs, | |
| 1413 l_int32 wd, | |
| 1414 l_int32 hd) | |
| 1415 { | |
| 1416 l_int32 w, h; | |
| 1417 l_float32 scalex, scaley; | |
| 1418 | |
| 1419 if (!pixs) | |
| 1420 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 1421 if (wd <= 0 && hd <= 0) | |
| 1422 return (PIX *)ERROR_PTR("neither wd nor hd > 0", __func__, NULL); | |
| 1423 | |
| 1424 pixGetDimensions(pixs, &w, &h, NULL); | |
| 1425 if (wd <= 0) { | |
| 1426 scaley = (l_float32)hd / (l_float32)h; | |
| 1427 scalex = scaley; | |
| 1428 } else if (hd <= 0) { | |
| 1429 scalex = (l_float32)wd / (l_float32)w; | |
| 1430 scaley = scalex; | |
| 1431 } else { | |
| 1432 scalex = (l_float32)wd / (l_float32)w; | |
| 1433 scaley = (l_float32)hd / (l_float32)h; | |
| 1434 } | |
| 1435 | |
| 1436 return pixScaleBySampling(pixs, scalex, scaley); | |
| 1437 } | |
| 1438 | |
| 1439 | |
| 1440 /*! | |
| 1441 * \brief pixScaleByIntSampling() | |
| 1442 * | |
| 1443 * \param[in] pixs 1, 2, 4, 8, 16, 32 bpp (all depths) | |
| 1444 * \param[in] factor integer subsampling; >= 1 | |
| 1445 * \return pixd, or NULL on error | |
| 1446 * | |
| 1447 * <pre> | |
| 1448 * Notes: | |
| 1449 * (1) Simple interface to pixScaleBySampling(), for isotropic | |
| 1450 * integer reduction. If %factor == 1, returns a copy. | |
| 1451 * </pre> | |
| 1452 */ | |
| 1453 PIX * | |
| 1454 pixScaleByIntSampling(PIX *pixs, | |
| 1455 l_int32 factor) | |
| 1456 { | |
| 1457 l_float32 scale; | |
| 1458 | |
| 1459 if (!pixs) | |
| 1460 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 1461 if (factor <= 1) { | |
| 1462 if (factor < 1) | |
| 1463 L_ERROR("factor must be >= 1; returning a copy\n", __func__); | |
| 1464 return pixCopy(NULL, pixs); | |
| 1465 } | |
| 1466 | |
| 1467 scale = 1.f / (l_float32)factor; | |
| 1468 return pixScaleBySampling(pixs, scale, scale); | |
| 1469 } | |
| 1470 | |
| 1471 | |
| 1472 /*------------------------------------------------------------------* | |
| 1473 * Fast integer factor subsampling RGB to gray * | |
| 1474 *------------------------------------------------------------------*/ | |
| 1475 /*! | |
| 1476 * \brief pixScaleRGBToGrayFast() | |
| 1477 * | |
| 1478 * \param[in] pixs 32 bpp rgb | |
| 1479 * \param[in] factor integer reduction factor >= 1 | |
| 1480 * \param[in] color one of COLOR_RED, COLOR_GREEN, COLOR_BLUE | |
| 1481 * \return pixd 8 bpp, or NULL on error | |
| 1482 * | |
| 1483 * <pre> | |
| 1484 * Notes: | |
| 1485 * (1) This does simultaneous subsampling by an integer factor and | |
| 1486 * extraction of the color from the RGB pix. | |
| 1487 * (2) It is designed for maximum speed, and is used for quickly | |
| 1488 * generating a downsized grayscale image from a higher resolution | |
| 1489 * RGB image. This would typically be used for image analysis. | |
| 1490 * (3) The standard color byte order (RGBA) is assumed. | |
| 1491 * </pre> | |
| 1492 */ | |
| 1493 PIX * | |
| 1494 pixScaleRGBToGrayFast(PIX *pixs, | |
| 1495 l_int32 factor, | |
| 1496 l_int32 color) | |
| 1497 { | |
| 1498 l_int32 byteval, shift; | |
| 1499 l_int32 i, j, ws, hs, wd, hd, wpls, wpld; | |
| 1500 l_uint32 *datas, *words, *datad, *lined; | |
| 1501 l_float32 scale; | |
| 1502 PIX *pixd; | |
| 1503 | |
| 1504 if (!pixs) | |
| 1505 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 1506 if (pixGetDepth(pixs) != 32) | |
| 1507 return (PIX *)ERROR_PTR("depth not 32 bpp", __func__, NULL); | |
| 1508 if (factor < 1) | |
| 1509 return (PIX *)ERROR_PTR("factor must be >= 1", __func__, NULL); | |
| 1510 | |
| 1511 if (color == COLOR_RED) | |
| 1512 shift = L_RED_SHIFT; | |
| 1513 else if (color == COLOR_GREEN) | |
| 1514 shift = L_GREEN_SHIFT; | |
| 1515 else if (color == COLOR_BLUE) | |
| 1516 shift = L_BLUE_SHIFT; | |
| 1517 else | |
| 1518 return (PIX *)ERROR_PTR("invalid color", __func__, NULL); | |
| 1519 | |
| 1520 pixGetDimensions(pixs, &ws, &hs, NULL); | |
| 1521 datas = pixGetData(pixs); | |
| 1522 wpls = pixGetWpl(pixs); | |
| 1523 | |
| 1524 wd = ws / factor; | |
| 1525 hd = hs / factor; | |
| 1526 if ((pixd = pixCreate(wd, hd, 8)) == NULL) | |
| 1527 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 1528 pixCopyResolution(pixd, pixs); | |
| 1529 pixCopyInputFormat(pixd, pixs); | |
| 1530 scale = 1.f / (l_float32) factor; | |
| 1531 pixScaleResolution(pixd, scale, scale); | |
| 1532 datad = pixGetData(pixd); | |
| 1533 wpld = pixGetWpl(pixd); | |
| 1534 | |
| 1535 for (i = 0; i < hd; i++) { | |
| 1536 words = datas + i * factor * wpls; | |
| 1537 lined = datad + i * wpld; | |
| 1538 for (j = 0; j < wd; j++, words += factor) { | |
| 1539 byteval = ((*words) >> shift) & 0xff; | |
| 1540 SET_DATA_BYTE(lined, j, byteval); | |
| 1541 } | |
| 1542 } | |
| 1543 | |
| 1544 return pixd; | |
| 1545 } | |
| 1546 | |
| 1547 | |
| 1548 /*! | |
| 1549 * \brief pixScaleRGBToBinaryFast() | |
| 1550 * | |
| 1551 * \param[in] pixs 32 bpp RGB | |
| 1552 * \param[in] factor integer reduction factor >= 1 | |
| 1553 * \param[in] thresh binarization threshold | |
| 1554 * \return pixd 1 bpp, or NULL on error | |
| 1555 * | |
| 1556 * <pre> | |
| 1557 * Notes: | |
| 1558 * (1) This does simultaneous subsampling by an integer factor and | |
| 1559 * conversion from RGB to gray to binary. | |
| 1560 * (2) It is designed for maximum speed, and is used for quickly | |
| 1561 * generating a downsized binary image from a higher resolution | |
| 1562 * RGB image. This would typically be used for image analysis. | |
| 1563 * (3) It uses the green channel to represent the RGB pixel intensity. | |
| 1564 * </pre> | |
| 1565 */ | |
| 1566 PIX * | |
| 1567 pixScaleRGBToBinaryFast(PIX *pixs, | |
| 1568 l_int32 factor, | |
| 1569 l_int32 thresh) | |
| 1570 { | |
| 1571 l_int32 byteval; | |
| 1572 l_int32 i, j, ws, hs, wd, hd, wpls, wpld; | |
| 1573 l_uint32 *datas, *words, *datad, *lined; | |
| 1574 l_float32 scale; | |
| 1575 PIX *pixd; | |
| 1576 | |
| 1577 if (!pixs) | |
| 1578 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 1579 if (factor < 1) | |
| 1580 return (PIX *)ERROR_PTR("factor must be >= 1", __func__, NULL); | |
| 1581 if (pixGetDepth(pixs) != 32) | |
| 1582 return (PIX *)ERROR_PTR("depth not 32 bpp", __func__, NULL); | |
| 1583 | |
| 1584 pixGetDimensions(pixs, &ws, &hs, NULL); | |
| 1585 datas = pixGetData(pixs); | |
| 1586 wpls = pixGetWpl(pixs); | |
| 1587 | |
| 1588 wd = ws / factor; | |
| 1589 hd = hs / factor; | |
| 1590 if ((pixd = pixCreate(wd, hd, 1)) == NULL) | |
| 1591 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 1592 pixCopyResolution(pixd, pixs); | |
| 1593 pixCopyInputFormat(pixd, pixs); | |
| 1594 scale = 1. / (l_float32) factor; | |
| 1595 pixScaleResolution(pixd, scale, scale); | |
| 1596 datad = pixGetData(pixd); | |
| 1597 wpld = pixGetWpl(pixd); | |
| 1598 | |
| 1599 for (i = 0; i < hd; i++) { | |
| 1600 words = datas + i * factor * wpls; | |
| 1601 lined = datad + i * wpld; | |
| 1602 for (j = 0; j < wd; j++, words += factor) { | |
| 1603 byteval = ((*words) >> L_GREEN_SHIFT) & 0xff; | |
| 1604 if (byteval < thresh) | |
| 1605 SET_DATA_BIT(lined, j); | |
| 1606 } | |
| 1607 } | |
| 1608 | |
| 1609 return pixd; | |
| 1610 } | |
| 1611 | |
| 1612 | |
| 1613 /*! | |
| 1614 * \brief pixScaleGrayToBinaryFast() | |
| 1615 * | |
| 1616 * \param[in] pixs 8 bpp grayscale | |
| 1617 * \param[in] factor integer reduction factor >= 1 | |
| 1618 * \param[in] thresh binarization threshold | |
| 1619 * \return pixd 1 bpp, or NULL on error | |
| 1620 * | |
| 1621 * <pre> | |
| 1622 * Notes: | |
| 1623 * (1) This does simultaneous subsampling by an integer factor and | |
| 1624 * thresholding from gray to binary. | |
| 1625 * (2) It is designed for maximum speed, and is used for quickly | |
| 1626 * generating a downsized binary image from a higher resolution | |
| 1627 * gray image. This would typically be used for image analysis. | |
| 1628 * </pre> | |
| 1629 */ | |
| 1630 PIX * | |
| 1631 pixScaleGrayToBinaryFast(PIX *pixs, | |
| 1632 l_int32 factor, | |
| 1633 l_int32 thresh) | |
| 1634 { | |
| 1635 l_int32 byteval; | |
| 1636 l_int32 i, j, ws, hs, wd, hd, wpls, wpld, sj; | |
| 1637 l_uint32 *datas, *datad, *lines, *lined; | |
| 1638 l_float32 scale; | |
| 1639 PIX *pixd; | |
| 1640 | |
| 1641 if (!pixs) | |
| 1642 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 1643 if (factor < 1) | |
| 1644 return (PIX *)ERROR_PTR("factor must be >= 1", __func__, NULL); | |
| 1645 if (pixGetDepth(pixs) != 8) | |
| 1646 return (PIX *)ERROR_PTR("depth not 8 bpp", __func__, NULL); | |
| 1647 | |
| 1648 pixGetDimensions(pixs, &ws, &hs, NULL); | |
| 1649 datas = pixGetData(pixs); | |
| 1650 wpls = pixGetWpl(pixs); | |
| 1651 | |
| 1652 wd = ws / factor; | |
| 1653 hd = hs / factor; | |
| 1654 if ((pixd = pixCreate(wd, hd, 1)) == NULL) | |
| 1655 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 1656 pixCopyResolution(pixd, pixs); | |
| 1657 pixCopyInputFormat(pixd, pixs); | |
| 1658 scale = 1.f / (l_float32) factor; | |
| 1659 pixScaleResolution(pixd, scale, scale); | |
| 1660 datad = pixGetData(pixd); | |
| 1661 wpld = pixGetWpl(pixd); | |
| 1662 | |
| 1663 for (i = 0; i < hd; i++) { | |
| 1664 lines = datas + i * factor * wpls; | |
| 1665 lined = datad + i * wpld; | |
| 1666 for (j = 0, sj = 0; j < wd; j++, sj += factor) { | |
| 1667 byteval = GET_DATA_BYTE(lines, sj); | |
| 1668 if (byteval < thresh) | |
| 1669 SET_DATA_BIT(lined, j); | |
| 1670 } | |
| 1671 } | |
| 1672 | |
| 1673 return pixd; | |
| 1674 } | |
| 1675 | |
| 1676 | |
| 1677 /*------------------------------------------------------------------* | |
| 1678 * Downscaling with (antialias) smoothing * | |
| 1679 *------------------------------------------------------------------*/ | |
| 1680 /*! | |
| 1681 * \brief pixScaleSmooth() | |
| 1682 * | |
| 1683 * \param[in] pix 2, 4, 8 or 32 bpp; and 2, 4, 8 bpp with colormap | |
| 1684 * \param[in] scalex must be < 0.7 | |
| 1685 * \param[in] scaley must be < 0.7 | |
| 1686 * \return pixd, or NULL on error | |
| 1687 * | |
| 1688 * <pre> | |
| 1689 * Notes: | |
| 1690 * (1) This function should only be used when the scale factors are less | |
| 1691 * than 0.7. If either scale factor is >= 0.7, issue a warning | |
| 1692 * and call pixScaleGeneral(), which will invoke linear interpolation | |
| 1693 * without sharpening. | |
| 1694 * (2) This works only on 2, 4, 8 and 32 bpp images, and if there is | |
| 1695 * a colormap, it is removed by converting to RGB. | |
| 1696 * (3) It does simple (flat filter) convolution, with a filter size | |
| 1697 * commensurate with the amount of reduction, to avoid antialiasing. | |
| 1698 * (4) It does simple subsampling after smoothing, which is appropriate | |
| 1699 * for this range of scaling. Linear interpolation gives essentially | |
| 1700 * the same result with more computation for these scale factors, | |
| 1701 * so we don't use it. | |
| 1702 * (5) The result is the same as doing a full block convolution followed by | |
| 1703 * subsampling, but this is faster because the results of the block | |
| 1704 * convolution are only computed at the subsampling locations. | |
| 1705 * In fact, the computation time is approximately independent of | |
| 1706 * the scale factor, because the convolution kernel is adjusted | |
| 1707 * so that each source pixel is summed approximately once. | |
| 1708 * </pre> | |
| 1709 */ | |
| 1710 PIX * | |
| 1711 pixScaleSmooth(PIX *pix, | |
| 1712 l_float32 scalex, | |
| 1713 l_float32 scaley) | |
| 1714 { | |
| 1715 l_int32 ws, hs, d, wd, hd, wpls, wpld, isize; | |
| 1716 l_uint32 val; | |
| 1717 l_uint32 *datas, *datad; | |
| 1718 l_float32 minscale, size; | |
| 1719 PIX *pixs, *pixd; | |
| 1720 | |
| 1721 if (!pix) | |
| 1722 return (PIX *)ERROR_PTR("pix not defined", __func__, NULL); | |
| 1723 if (scalex >= 0.7 || scaley >= 0.7) { | |
| 1724 L_WARNING("scaling factor not < 0.7; do regular scaling\n", __func__); | |
| 1725 return pixScaleGeneral(pix, scalex, scaley, 0.0, 0); | |
| 1726 } | |
| 1727 d = pixGetDepth(pix); | |
| 1728 if (d != 2 && d != 4 && d !=8 && d != 32) | |
| 1729 return (PIX *)ERROR_PTR("pix not 2, 4, 8 or 32 bpp", __func__, NULL); | |
| 1730 | |
| 1731 /* Remove colormap; clone if possible; result is either 8 or 32 bpp */ | |
| 1732 if ((pixs = pixConvertTo8Or32(pix, L_CLONE, 0)) == NULL) | |
| 1733 return (PIX *)ERROR_PTR("pixs not made", __func__, NULL); | |
| 1734 d = pixGetDepth(pixs); | |
| 1735 | |
| 1736 /* If 1.42 < 1/minscale < 2.5, use isize = 2 | |
| 1737 * If 2.5 =< 1/minscale < 3.5, use isize = 3, etc. | |
| 1738 * Under no conditions use isize < 2 */ | |
| 1739 minscale = L_MIN(scalex, scaley); | |
| 1740 size = 1.0f / minscale; /* ideal filter full width */ | |
| 1741 isize = L_MIN(10000, L_MAX(2, (l_int32)(size + 0.5))); | |
| 1742 | |
| 1743 pixGetDimensions(pixs, &ws, &hs, NULL); | |
| 1744 if ((ws < isize) || (hs < isize)) { | |
| 1745 pixd = pixCreate(1, 1, d); | |
| 1746 pixGetPixel(pixs, ws / 2, hs / 2, &val); | |
| 1747 pixSetPixel(pixd, 0, 0, val); | |
| 1748 L_WARNING("ridiculously small scaling factor %f\n", __func__, minscale); | |
| 1749 pixDestroy(&pixs); | |
| 1750 return pixd; | |
| 1751 } | |
| 1752 | |
| 1753 datas = pixGetData(pixs); | |
| 1754 wpls = pixGetWpl(pixs); | |
| 1755 wd = L_MAX(1, (l_int32)(scalex * (l_float32)ws + 0.5)); | |
| 1756 hd = L_MAX(1, (l_int32)(scaley * (l_float32)hs + 0.5)); | |
| 1757 if ((pixd = pixCreate(wd, hd, d)) == NULL) { | |
| 1758 pixDestroy(&pixs); | |
| 1759 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 1760 } | |
| 1761 pixCopyResolution(pixd, pixs); | |
| 1762 pixCopyInputFormat(pixd, pixs); | |
| 1763 pixScaleResolution(pixd, scalex, scaley); | |
| 1764 datad = pixGetData(pixd); | |
| 1765 wpld = pixGetWpl(pixd); | |
| 1766 scaleSmoothLow(datad, wd, hd, wpld, datas, ws, hs, d, wpls, isize); | |
| 1767 if (d == 32 && pixGetSpp(pixs) == 4) | |
| 1768 pixScaleAndTransferAlpha(pixd, pixs, scalex, scaley); | |
| 1769 | |
| 1770 pixDestroy(&pixs); | |
| 1771 return pixd; | |
| 1772 } | |
| 1773 | |
| 1774 | |
| 1775 /*! | |
| 1776 * \brief pixScaleSmoothToSize() | |
| 1777 * | |
| 1778 * \param[in] pixs 2, 4, 8 or 32 bpp; and 2, 4, 8 bpp with colormap | |
| 1779 * \param[in] wd target width; use 0 if using height as target | |
| 1780 * \param[in] hd target height; use 0 if using width as target | |
| 1781 * \return pixd, or NULL on error | |
| 1782 * | |
| 1783 * <pre> | |
| 1784 * Notes: | |
| 1785 * (1) See notes in pixScaleSmooth(). | |
| 1786 * (2) The output scaled image has the dimension(s) you specify: | |
| 1787 * - To specify the width with isotropic scaling, set %hd = 0. | |
| 1788 * - To specify the height with isotropic scaling, set %wd = 0. | |
| 1789 * - If both %wd and %hd are specified, the image is scaled | |
| 1790 * (in general, anisotropically) to that size. | |
| 1791 * - It is an error to set both %wd and %hd to 0. | |
| 1792 * </pre> | |
| 1793 */ | |
| 1794 PIX * | |
| 1795 pixScaleSmoothToSize(PIX *pixs, | |
| 1796 l_int32 wd, | |
| 1797 l_int32 hd) | |
| 1798 { | |
| 1799 l_int32 w, h; | |
| 1800 l_float32 scalex, scaley; | |
| 1801 | |
| 1802 if (!pixs) | |
| 1803 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 1804 if (wd <= 0 && hd <= 0) | |
| 1805 return (PIX *)ERROR_PTR("neither wd nor hd > 0", __func__, NULL); | |
| 1806 | |
| 1807 pixGetDimensions(pixs, &w, &h, NULL); | |
| 1808 if (wd <= 0) { | |
| 1809 scaley = (l_float32)hd / (l_float32)h; | |
| 1810 scalex = scaley; | |
| 1811 } else if (hd <= 0) { | |
| 1812 scalex = (l_float32)wd / (l_float32)w; | |
| 1813 scaley = scalex; | |
| 1814 } else { | |
| 1815 scalex = (l_float32)wd / (l_float32)w; | |
| 1816 scaley = (l_float32)hd / (l_float32)h; | |
| 1817 } | |
| 1818 | |
| 1819 return pixScaleSmooth(pixs, scalex, scaley); | |
| 1820 } | |
| 1821 | |
| 1822 | |
| 1823 /*! | |
| 1824 * \brief pixScaleRGBToGray2() | |
| 1825 * | |
| 1826 * \param[in] pixs 32 bpp rgb | |
| 1827 * \param[in] rwt, gwt, bwt must sum to 1.0 | |
| 1828 * \return pixd, 8 bpp, 2x reduced, or NULL on error | |
| 1829 */ | |
| 1830 PIX * | |
| 1831 pixScaleRGBToGray2(PIX *pixs, | |
| 1832 l_float32 rwt, | |
| 1833 l_float32 gwt, | |
| 1834 l_float32 bwt) | |
| 1835 { | |
| 1836 l_int32 wd, hd, wpls, wpld; | |
| 1837 l_uint32 *datas, *datad; | |
| 1838 PIX *pixd; | |
| 1839 | |
| 1840 if (!pixs) | |
| 1841 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 1842 if (pixGetDepth(pixs) != 32) | |
| 1843 return (PIX *)ERROR_PTR("pixs not 32 bpp", __func__, NULL); | |
| 1844 if (rwt + gwt + bwt < 0.98 || rwt + gwt + bwt > 1.02) | |
| 1845 return (PIX *)ERROR_PTR("sum of wts should be 1.0", __func__, NULL); | |
| 1846 | |
| 1847 wd = pixGetWidth(pixs) / 2; | |
| 1848 hd = pixGetHeight(pixs) / 2; | |
| 1849 wpls = pixGetWpl(pixs); | |
| 1850 datas = pixGetData(pixs); | |
| 1851 if ((pixd = pixCreate(wd, hd, 8)) == NULL) | |
| 1852 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 1853 pixCopyResolution(pixd, pixs); | |
| 1854 pixCopyInputFormat(pixd, pixs); | |
| 1855 pixScaleResolution(pixd, 0.5, 0.5); | |
| 1856 wpld = pixGetWpl(pixd); | |
| 1857 datad = pixGetData(pixd); | |
| 1858 scaleRGBToGray2Low(datad, wd, hd, wpld, datas, wpls, rwt, gwt, bwt); | |
| 1859 return pixd; | |
| 1860 } | |
| 1861 | |
| 1862 | |
| 1863 /*------------------------------------------------------------------* | |
| 1864 * Downscaling with (antialias) area mapping * | |
| 1865 *------------------------------------------------------------------*/ | |
| 1866 /*! | |
| 1867 * \brief pixScaleAreaMap() | |
| 1868 * | |
| 1869 * \param[in] pix 2, 4, 8 or 32 bpp; and 2, 4, 8 bpp with colormap | |
| 1870 * \param[in] scalex must be < 0.7; minimum is 0.02 | |
| 1871 * \param[in] scaley must be < 0.7; minimum is 0.02 | |
| 1872 * \return pixd, or NULL on error | |
| 1873 * | |
| 1874 * <pre> | |
| 1875 * Notes: | |
| 1876 * (1) This is a low-pass filter that averages over fractional pixels. | |
| 1877 * It should only be used when the scale factors are less than 0.7. | |
| 1878 * If either scale factor is greater than or equal to 0.7, we | |
| 1879 * issue a warning and call pixScaleGeneral(), which will invoke | |
| 1880 * linear interpolation without sharpening. | |
| 1881 * (2) The minimum scale factor allowed for area mapping reduction | |
| 1882 * is 0.02. Various overflows will occur when scale factors are | |
| 1883 * less than about 1/256. If a scale factor smaller than 0.02 | |
| 1884 * is given, we use pixScaleSmooth(), which is a low-pass filter | |
| 1885 * that averages over entire pixels. | |
| 1886 * (3) This works only on 2, 4, 8 and 32 bpp images. If there is | |
| 1887 * a colormap, it is removed by converting to RGB. In other | |
| 1888 * cases, we issue a warning and call pixScaleGeneral(). | |
| 1889 * (4) This is faster than pixScale() because it does not do sharpening. | |
| 1890 * (5) It does a relatively expensive area mapping computation, to | |
| 1891 * avoid antialiasing. It is about 2x slower than pixScaleSmooth(), | |
| 1892 * but the results are much better on fine text. | |
| 1893 * (6) pixScaleAreaMap2() is typically about 7x faster for the special | |
| 1894 * case of 2x reduction for color images, and about 9x faster | |
| 1895 * for grayscale images. Surprisingly, the improvement in speed | |
| 1896 * when using a cascade of 2x reductions for small scale factors is | |
| 1897 * less than one might expect, and in most situations gives | |
| 1898 * poorer image quality. But see (6). | |
| 1899 * (7) For reductions between 0.35 and 0.5, a 2x area map reduction | |
| 1900 * followed by using pixScaleGeneral() on a 2x larger scalefactor | |
| 1901 * (which further reduces the image size using bilinear interpolation) | |
| 1902 * would give a significant speed increase, with little loss of | |
| 1903 * quality, but this is not enabled as it would break too many tests. | |
| 1904 * For scaling factors below 0.35, scaling atomically is nearly | |
| 1905 * as fast as using a cascade of 2x scalings, and gives | |
| 1906 * better results. | |
| 1907 * </pre> | |
| 1908 */ | |
| 1909 PIX * | |
| 1910 pixScaleAreaMap(PIX *pix, | |
| 1911 l_float32 scalex, | |
| 1912 l_float32 scaley) | |
| 1913 { | |
| 1914 l_int32 ws, hs, d, wd, hd, wpls, wpld; | |
| 1915 l_uint32 *datas, *datad; | |
| 1916 l_float32 maxscale, minscale; | |
| 1917 PIX *pixs, *pixd, *pix1, *pix2, *pix3; | |
| 1918 | |
| 1919 if (!pix) | |
| 1920 return (PIX *)ERROR_PTR("pix not defined", __func__, NULL); | |
| 1921 d = pixGetDepth(pix); | |
| 1922 if (d != 2 && d != 4 && d != 8 && d != 32) | |
| 1923 return (PIX *)ERROR_PTR("pix not 2, 4, 8 or 32 bpp", __func__, NULL); | |
| 1924 | |
| 1925 minscale = L_MIN(scalex, scaley); | |
| 1926 if (minscale < 0.02) { /* too small for area mapping */ | |
| 1927 L_WARNING("tiny scaling factor; using pixScaleSmooth()\n", __func__); | |
| 1928 return pixScaleSmooth(pix, scalex, scaley); | |
| 1929 } | |
| 1930 | |
| 1931 maxscale = L_MAX(scalex, scaley); | |
| 1932 if (maxscale >= 0.7) { /* too large for area mapping */ | |
| 1933 L_WARNING("scaling factor >= 0.7; do regular scaling\n", __func__); | |
| 1934 return pixScaleGeneral(pix, scalex, scaley, 0.0, 0); | |
| 1935 } | |
| 1936 | |
| 1937 /* Special cases: 2x, 4x, 8x, 16x reduction */ | |
| 1938 if (scalex == 0.5 && scaley == 0.5) | |
| 1939 return pixScaleAreaMap2(pix); | |
| 1940 if (scalex == 0.25 && scaley == 0.25) { | |
| 1941 pix1 = pixScaleAreaMap2(pix); | |
| 1942 pixd = pixScaleAreaMap2(pix1); | |
| 1943 pixDestroy(&pix1); | |
| 1944 return pixd; | |
| 1945 } | |
| 1946 if (scalex == 0.125 && scaley == 0.125) { | |
| 1947 pix1 = pixScaleAreaMap2(pix); | |
| 1948 pix2 = pixScaleAreaMap2(pix1); | |
| 1949 pixd = pixScaleAreaMap2(pix2); | |
| 1950 pixDestroy(&pix1); | |
| 1951 pixDestroy(&pix2); | |
| 1952 return pixd; | |
| 1953 } | |
| 1954 if (scalex == 0.0625 && scaley == 0.0625) { | |
| 1955 pix1 = pixScaleAreaMap2(pix); | |
| 1956 pix2 = pixScaleAreaMap2(pix1); | |
| 1957 pix3 = pixScaleAreaMap2(pix2); | |
| 1958 pixd = pixScaleAreaMap2(pix3); | |
| 1959 pixDestroy(&pix1); | |
| 1960 pixDestroy(&pix2); | |
| 1961 pixDestroy(&pix3); | |
| 1962 return pixd; | |
| 1963 } | |
| 1964 | |
| 1965 #if 0 /* Not enabled because it breaks too many tests that rely on exact | |
| 1966 * pixel matches. */ | |
| 1967 /* Special case where it is significantly faster to downscale first | |
| 1968 * by 2x, with relatively little degradation in image quality. */ | |
| 1969 if (scalex > 0.35 && scalex < 0.5) { | |
| 1970 pix1 = pixScaleAreaMap2(pix); | |
| 1971 pixd = pixScaleAreaMap(pix1, 2.0 * scalex, 2.0 * scaley); | |
| 1972 pixDestroy(&pix1); | |
| 1973 return pixd; | |
| 1974 } | |
| 1975 #endif | |
| 1976 | |
| 1977 /* Remove colormap if necessary. | |
| 1978 * If 2 bpp or 4 bpp gray, convert to 8 bpp */ | |
| 1979 if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) { | |
| 1980 L_WARNING("pix has colormap; removing\n", __func__); | |
| 1981 pixs = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC); | |
| 1982 d = pixGetDepth(pixs); | |
| 1983 } else if (d == 2 || d == 4) { | |
| 1984 pixs = pixConvertTo8(pix, FALSE); | |
| 1985 d = 8; | |
| 1986 } else { | |
| 1987 pixs = pixClone(pix); | |
| 1988 } | |
| 1989 | |
| 1990 pixGetDimensions(pixs, &ws, &hs, NULL); | |
| 1991 datas = pixGetData(pixs); | |
| 1992 wpls = pixGetWpl(pixs); | |
| 1993 wd = (l_int32)(scalex * (l_float32)ws + 0.5); | |
| 1994 hd = (l_int32)(scaley * (l_float32)hs + 0.5); | |
| 1995 if (wd < 1 || hd < 1) { | |
| 1996 pixDestroy(&pixs); | |
| 1997 return (PIX *)ERROR_PTR("pixd too small", __func__, NULL); | |
| 1998 } | |
| 1999 if ((pixd = pixCreate(wd, hd, d)) == NULL) { | |
| 2000 pixDestroy(&pixs); | |
| 2001 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 2002 } | |
| 2003 pixCopyInputFormat(pixd, pixs); | |
| 2004 pixCopyResolution(pixd, pixs); | |
| 2005 pixScaleResolution(pixd, scalex, scaley); | |
| 2006 datad = pixGetData(pixd); | |
| 2007 wpld = pixGetWpl(pixd); | |
| 2008 if (d == 8) { | |
| 2009 scaleGrayAreaMapLow(datad, wd, hd, wpld, datas, ws, hs, wpls); | |
| 2010 } else { /* RGB, d == 32 */ | |
| 2011 scaleColorAreaMapLow(datad, wd, hd, wpld, datas, ws, hs, wpls); | |
| 2012 if (pixGetSpp(pixs) == 4) | |
| 2013 pixScaleAndTransferAlpha(pixd, pixs, scalex, scaley); | |
| 2014 } | |
| 2015 | |
| 2016 pixDestroy(&pixs); | |
| 2017 return pixd; | |
| 2018 } | |
| 2019 | |
| 2020 | |
| 2021 /*! | |
| 2022 * \brief pixScaleAreaMap2() | |
| 2023 * | |
| 2024 * \param[in] pix 2, 4, 8 or 32 bpp; and 2, 4, 8 bpp with colormap | |
| 2025 * \return pixd, or NULL on error | |
| 2026 * | |
| 2027 * <pre> | |
| 2028 * Notes: | |
| 2029 * (1) This function does an area mapping (average) for 2x | |
| 2030 * reduction. | |
| 2031 * (2) This works only on 2, 4, 8 and 32 bpp images. If there is | |
| 2032 * a colormap, it is removed by converting to RGB. | |
| 2033 * (3) Compared to the general pixScaleAreaMap(), for this function | |
| 2034 * gray processing is about 14x faster and color processing | |
| 2035 * is about 4x faster. Consequently, pixScaleAreaMap2() is | |
| 2036 * incorporated into the general area map scaling function, | |
| 2037 * for the special cases of 2x, 4x, 8x and 16x reduction. | |
| 2038 * </pre> | |
| 2039 */ | |
| 2040 PIX * | |
| 2041 pixScaleAreaMap2(PIX *pix) | |
| 2042 { | |
| 2043 l_int32 wd, hd, d, wpls, wpld; | |
| 2044 l_uint32 *datas, *datad; | |
| 2045 PIX *pixs, *pixd; | |
| 2046 | |
| 2047 if (!pix) | |
| 2048 return (PIX *)ERROR_PTR("pix not defined", __func__, NULL); | |
| 2049 d = pixGetDepth(pix); | |
| 2050 if (d != 2 && d != 4 && d != 8 && d != 32) | |
| 2051 return (PIX *)ERROR_PTR("pix not 2, 4, 8 or 32 bpp", __func__, NULL); | |
| 2052 | |
| 2053 /* Remove colormap if necessary. | |
| 2054 * If 2 bpp or 4 bpp gray, convert to 8 bpp */ | |
| 2055 if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) { | |
| 2056 L_WARNING("pix has colormap; removing\n", __func__); | |
| 2057 pixs = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC); | |
| 2058 d = pixGetDepth(pixs); | |
| 2059 } else if (d == 2 || d == 4) { | |
| 2060 pixs = pixConvertTo8(pix, FALSE); | |
| 2061 d = 8; | |
| 2062 } else { | |
| 2063 pixs = pixClone(pix); | |
| 2064 } | |
| 2065 | |
| 2066 wd = pixGetWidth(pixs) / 2; | |
| 2067 hd = pixGetHeight(pixs) / 2; | |
| 2068 datas = pixGetData(pixs); | |
| 2069 wpls = pixGetWpl(pixs); | |
| 2070 pixd = pixCreate(wd, hd, d); | |
| 2071 datad = pixGetData(pixd); | |
| 2072 wpld = pixGetWpl(pixd); | |
| 2073 pixCopyInputFormat(pixd, pixs); | |
| 2074 pixCopyResolution(pixd, pixs); | |
| 2075 pixScaleResolution(pixd, 0.5, 0.5); | |
| 2076 scaleAreaMapLow2(datad, wd, hd, wpld, datas, d, wpls); | |
| 2077 if (pixGetSpp(pixs) == 4) | |
| 2078 pixScaleAndTransferAlpha(pixd, pixs, 0.5, 0.5); | |
| 2079 pixDestroy(&pixs); | |
| 2080 return pixd; | |
| 2081 } | |
| 2082 | |
| 2083 | |
| 2084 /*! | |
| 2085 * \brief pixScaleAreaMapToSize() | |
| 2086 * | |
| 2087 * \param[in] pixs 2, 4, 8 or 32 bpp; and 2, 4, 8 bpp with colormap | |
| 2088 * \param[in] wd target width; use 0 if using height as target | |
| 2089 * \param[in] hd target height; use 0 if using width as target | |
| 2090 * \return pixd, or NULL on error | |
| 2091 * | |
| 2092 * <pre> | |
| 2093 * Notes: | |
| 2094 * (1) See notes in pixScaleAreaMap(). | |
| 2095 * (2) The output scaled image has the dimension(s) you specify: | |
| 2096 * - To specify the width with isotropic scaling, set %hd = 0. | |
| 2097 * - To specify the height with isotropic scaling, set %wd = 0. | |
| 2098 * - If both %wd and %hd are specified, the image is scaled | |
| 2099 * (in general, anisotropically) to that size. | |
| 2100 * - It is an error to set both %wd and %hd to 0. | |
| 2101 * </pre> | |
| 2102 */ | |
| 2103 PIX * | |
| 2104 pixScaleAreaMapToSize(PIX *pixs, | |
| 2105 l_int32 wd, | |
| 2106 l_int32 hd) | |
| 2107 { | |
| 2108 l_int32 w, h; | |
| 2109 l_float32 scalex, scaley; | |
| 2110 | |
| 2111 if (!pixs) | |
| 2112 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 2113 if (wd <= 0 && hd <= 0) | |
| 2114 return (PIX *)ERROR_PTR("neither wd nor hd > 0", __func__, NULL); | |
| 2115 | |
| 2116 pixGetDimensions(pixs, &w, &h, NULL); | |
| 2117 if (wd <= 0) { | |
| 2118 scaley = (l_float32)hd / (l_float32)h; | |
| 2119 scalex = scaley; | |
| 2120 } else if (hd <= 0) { | |
| 2121 scalex = (l_float32)wd / (l_float32)w; | |
| 2122 scaley = scalex; | |
| 2123 } else { | |
| 2124 scalex = (l_float32)wd / (l_float32)w; | |
| 2125 scaley = (l_float32)hd / (l_float32)h; | |
| 2126 } | |
| 2127 | |
| 2128 return pixScaleAreaMap(pixs, scalex, scaley); | |
| 2129 } | |
| 2130 | |
| 2131 | |
| 2132 /*------------------------------------------------------------------* | |
| 2133 * Binary scaling by closest pixel sampling * | |
| 2134 *------------------------------------------------------------------*/ | |
| 2135 /*! | |
| 2136 * \brief pixScaleBinary() | |
| 2137 * | |
| 2138 * \param[in] pixs 1 bpp | |
| 2139 * \param[in] scalex must be > 0.0 | |
| 2140 * \param[in] scaley must be > 0.0 | |
| 2141 * \return pixd, or NULL on error | |
| 2142 * | |
| 2143 * <pre> | |
| 2144 * Notes: | |
| 2145 * (1) This function samples from the source without | |
| 2146 * filtering. As a result, aliasing will occur for | |
| 2147 * subsampling (scalex and scaley < 1.0). | |
| 2148 * (2) By default, indexing for the sampled source pixel is done | |
| 2149 * by rounding. This shifts the source pixel sampling down | |
| 2150 * and to the right by half a pixel, which has the effect of | |
| 2151 * shifting the destination image up and to the left by a | |
| 2152 * number of pixels approximately equal to half the scaling | |
| 2153 * factor. To avoid this shift in the destination image, | |
| 2154 * call pixScalebySamplingWithShift() using 0 for both shifts. | |
| 2155 * </pre> | |
| 2156 */ | |
| 2157 PIX * | |
| 2158 pixScaleBinary(PIX *pixs, | |
| 2159 l_float32 scalex, | |
| 2160 l_float32 scaley) | |
| 2161 { | |
| 2162 if (!pixs) | |
| 2163 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 2164 if (pixGetDepth(pixs) != 1) | |
| 2165 return (PIX *)ERROR_PTR("pixs must be 1 bpp", __func__, NULL); | |
| 2166 return pixScaleBinaryWithShift(pixs, scalex, scaley, 0.5, 0.5); | |
| 2167 } | |
| 2168 | |
| 2169 | |
| 2170 /*! | |
| 2171 * \brief pixScaleBinaryWithShift() | |
| 2172 * | |
| 2173 * \param[in] pixs 1 bpp | |
| 2174 * \param[in] scalex must be > 0.0 | |
| 2175 * \param[in] scaley must be > 0.0 | |
| 2176 * \param[in] shiftx 0.5 for default; 0.0 to mihimize edge effects | |
| 2177 * \param[in] shifty 0.5 for default; 0.0 to mihimize edge effects | |
| 2178 * \return pixd, or NULL on error | |
| 2179 * | |
| 2180 * <pre> | |
| 2181 * Notes: | |
| 2182 * (1) The @shiftx and @shifty parameters are usually unimportant. | |
| 2183 * Visible artifacts are minimized by using 0.0. | |
| 2184 * Allowed values are 0.0 and 0.5. | |
| 2185 * </pre> | |
| 2186 */ | |
| 2187 PIX * | |
| 2188 pixScaleBinaryWithShift(PIX *pixs, | |
| 2189 l_float32 scalex, | |
| 2190 l_float32 scaley, | |
| 2191 l_float32 shiftx, | |
| 2192 l_float32 shifty) | |
| 2193 { | |
| 2194 l_int32 ws, hs, wpls, wd, hd, wpld; | |
| 2195 l_uint32 *datas, *datad; | |
| 2196 PIX *pixd; | |
| 2197 | |
| 2198 if (!pixs) | |
| 2199 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); | |
| 2200 if (pixGetDepth(pixs) != 1) | |
| 2201 return (PIX *)ERROR_PTR("pixs must be 1 bpp", __func__, NULL); | |
| 2202 if (scalex <= 0.0 || scaley <= 0.0) | |
| 2203 return (PIX *)ERROR_PTR("scale factor <= 0", __func__, NULL); | |
| 2204 if (scalex == 1.0 && scaley == 1.0) | |
| 2205 return pixCopy(NULL, pixs); | |
| 2206 if (shiftx != 0.0 && shiftx != 0.5) | |
| 2207 return (PIX *)ERROR_PTR("shiftx != 0.0 or 0.5", __func__, NULL); | |
| 2208 if (shifty != 0.0 && shifty != 0.5) | |
| 2209 return (PIX *)ERROR_PTR("shifty != 0.0 or 0.5", __func__, NULL); | |
| 2210 | |
| 2211 pixGetDimensions(pixs, &ws, &hs, NULL); | |
| 2212 datas = pixGetData(pixs); | |
| 2213 wpls = pixGetWpl(pixs); | |
| 2214 wd = (l_int32)(scalex * (l_float32)ws + 0.5); | |
| 2215 hd = (l_int32)(scaley * (l_float32)hs + 0.5); | |
| 2216 if ((pixd = pixCreate(wd, hd, 1)) == NULL) | |
| 2217 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); | |
| 2218 pixCopyColormap(pixd, pixs); | |
| 2219 pixCopyText(pixd, pixs); | |
| 2220 pixCopyInputFormat(pixd, pixs); | |
| 2221 pixCopyResolution(pixd, pixs); | |
| 2222 pixScaleResolution(pixd, scalex, scaley); | |
| 2223 datad = pixGetData(pixd); | |
| 2224 wpld = pixGetWpl(pixd); | |
| 2225 scaleBinaryLow(datad, wd, hd, wpld, datas, ws, hs, wpls, shiftx, shifty); | |
| 2226 return pixd; | |
| 2227 } | |
| 2228 | |
| 2229 | |
| 2230 /* ================================================================ * | |
| 2231 * Low level static functions * | |
| 2232 * ================================================================ */ | |
| 2233 | |
| 2234 /*------------------------------------------------------------------* | |
| 2235 * General linear interpolated color scaling * | |
| 2236 *------------------------------------------------------------------*/ | |
| 2237 /*! | |
| 2238 * \brief scaleColorLILow() | |
| 2239 * | |
| 2240 * <pre> | |
| 2241 * Notes: | |
| 2242 * (1) We choose to divide each pixel into 16 x 16 sub-pixels. | |
| 2243 * Linear interpolation is equivalent to finding the | |
| 2244 * fractional area (i.e., number of sub-pixels divided | |
| 2245 * by 256) associated with each of the four nearest src pixels, | |
| 2246 * and weighting each pixel value by this fractional area. | |
| 2247 * </pre> | |
| 2248 */ | |
| 2249 static void | |
| 2250 scaleColorLILow(l_uint32 *datad, | |
| 2251 l_int32 wd, | |
| 2252 l_int32 hd, | |
| 2253 l_int32 wpld, | |
| 2254 l_uint32 *datas, | |
| 2255 l_int32 ws, | |
| 2256 l_int32 hs, | |
| 2257 l_int32 wpls) | |
| 2258 { | |
| 2259 l_int32 i, j, wm2, hm2; | |
| 2260 l_int32 xpm, ypm; /* location in src image, to 1/16 of a pixel */ | |
| 2261 l_int32 xp, yp, xf, yf; /* src pixel and pixel fraction coordinates */ | |
| 2262 l_uint32 v00r, v01r, v10r, v11r, v00g, v01g, v10g, v11g; | |
| 2263 l_uint32 v00b, v01b, v10b, v11b, area00, area01, area10, area11; | |
| 2264 l_uint32 pixels1, pixels2, pixels3, pixels4, pixel; | |
| 2265 l_uint32 *lines, *lined; | |
| 2266 l_float32 scx, scy; | |
| 2267 | |
| 2268 /* (scx, scy) are scaling factors that are applied to the | |
| 2269 * dest coords to get the corresponding src coords. | |
| 2270 * We need them because we iterate over dest pixels | |
| 2271 * and must find the corresponding set of src pixels. */ | |
| 2272 scx = 16.f * (l_float32)ws / (l_float32)wd; | |
| 2273 scy = 16.f * (l_float32)hs / (l_float32)hd; | |
| 2274 wm2 = ws - 2; | |
| 2275 hm2 = hs - 2; | |
| 2276 | |
| 2277 /* Iterate over the destination pixels */ | |
| 2278 for (i = 0; i < hd; i++) { | |
| 2279 ypm = (l_int32)(scy * (l_float32)i); | |
| 2280 yp = ypm >> 4; | |
| 2281 yf = ypm & 0x0f; | |
| 2282 lined = datad + i * wpld; | |
| 2283 lines = datas + yp * wpls; | |
| 2284 for (j = 0; j < wd; j++) { | |
| 2285 xpm = (l_int32)(scx * (l_float32)j); | |
| 2286 xp = xpm >> 4; | |
| 2287 xf = xpm & 0x0f; | |
| 2288 | |
| 2289 /* Do bilinear interpolation. This is a simple | |
| 2290 * generalization of the calculation in scaleGrayLILow(). | |
| 2291 * Without this, we could simply subsample: | |
| 2292 * *(lined + j) = *(lines + xp); | |
| 2293 * which is faster but gives lousy results! */ | |
| 2294 pixels1 = *(lines + xp); | |
| 2295 | |
| 2296 if (xp > wm2 || yp > hm2) { | |
| 2297 if (yp > hm2 && xp <= wm2) { /* pixels near bottom */ | |
| 2298 pixels2 = *(lines + xp + 1); | |
| 2299 pixels3 = pixels1; | |
| 2300 pixels4 = pixels2; | |
| 2301 } else if (xp > wm2 && yp <= hm2) { /* pixels near rt side */ | |
| 2302 pixels2 = pixels1; | |
| 2303 pixels3 = *(lines + wpls + xp); | |
| 2304 pixels4 = pixels3; | |
| 2305 } else { /* pixels at LR corner */ | |
| 2306 pixels4 = pixels3 = pixels2 = pixels1; | |
| 2307 } | |
| 2308 } else { | |
| 2309 pixels2 = *(lines + xp + 1); | |
| 2310 pixels3 = *(lines + wpls + xp); | |
| 2311 pixels4 = *(lines + wpls + xp + 1); | |
| 2312 } | |
| 2313 | |
| 2314 area00 = (16 - xf) * (16 - yf); | |
| 2315 area10 = xf * (16 - yf); | |
| 2316 area01 = (16 - xf) * yf; | |
| 2317 area11 = xf * yf; | |
| 2318 v00r = area00 * ((pixels1 >> L_RED_SHIFT) & 0xff); | |
| 2319 v00g = area00 * ((pixels1 >> L_GREEN_SHIFT) & 0xff); | |
| 2320 v00b = area00 * ((pixels1 >> L_BLUE_SHIFT) & 0xff); | |
| 2321 v10r = area10 * ((pixels2 >> L_RED_SHIFT) & 0xff); | |
| 2322 v10g = area10 * ((pixels2 >> L_GREEN_SHIFT) & 0xff); | |
| 2323 v10b = area10 * ((pixels2 >> L_BLUE_SHIFT) & 0xff); | |
| 2324 v01r = area01 * ((pixels3 >> L_RED_SHIFT) & 0xff); | |
| 2325 v01g = area01 * ((pixels3 >> L_GREEN_SHIFT) & 0xff); | |
| 2326 v01b = area01 * ((pixels3 >> L_BLUE_SHIFT) & 0xff); | |
| 2327 v11r = area11 * ((pixels4 >> L_RED_SHIFT) & 0xff); | |
| 2328 v11g = area11 * ((pixels4 >> L_GREEN_SHIFT) & 0xff); | |
| 2329 v11b = area11 * ((pixels4 >> L_BLUE_SHIFT) & 0xff); | |
| 2330 pixel = (((v00r + v10r + v01r + v11r + 128) << 16) & 0xff000000) | | |
| 2331 (((v00g + v10g + v01g + v11g + 128) << 8) & 0x00ff0000) | | |
| 2332 ((v00b + v10b + v01b + v11b + 128) & 0x0000ff00); | |
| 2333 *(lined + j) = pixel; | |
| 2334 } | |
| 2335 } | |
| 2336 } | |
| 2337 | |
| 2338 | |
| 2339 /*------------------------------------------------------------------* | |
| 2340 * General linear interpolated gray scaling * | |
| 2341 *------------------------------------------------------------------*/ | |
| 2342 /*! | |
| 2343 * \brief scaleGrayLILow() | |
| 2344 * | |
| 2345 * <pre> | |
| 2346 * Notes: | |
| 2347 * (1) We choose to divide each pixel into 16 x 16 sub-pixels. | |
| 2348 * Linear interpolation is equivalent to finding the | |
| 2349 * fractional area (i.e., number of sub-pixels divided | |
| 2350 * by 256) associated with each of the four nearest src pixels, | |
| 2351 * and weighting each pixel value by this fractional area. | |
| 2352 * </pre> | |
| 2353 */ | |
| 2354 static void | |
| 2355 scaleGrayLILow(l_uint32 *datad, | |
| 2356 l_int32 wd, | |
| 2357 l_int32 hd, | |
| 2358 l_int32 wpld, | |
| 2359 l_uint32 *datas, | |
| 2360 l_int32 ws, | |
| 2361 l_int32 hs, | |
| 2362 l_int32 wpls) | |
| 2363 { | |
| 2364 l_int32 i, j, wm2, hm2; | |
| 2365 l_int32 xpm, ypm; /* location in src image, to 1/16 of a pixel */ | |
| 2366 l_int32 xp, yp, xf, yf; /* src pixel and pixel fraction coordinates */ | |
| 2367 l_int32 v00, v01, v10, v11, v00_val, v01_val, v10_val, v11_val; | |
| 2368 l_uint8 val; | |
| 2369 l_uint32 *lines, *lined; | |
| 2370 l_float32 scx, scy; | |
| 2371 | |
| 2372 /* (scx, scy) are scaling factors that are applied to the | |
| 2373 * dest coords to get the corresponding src coords. | |
| 2374 * We need them because we iterate over dest pixels | |
| 2375 * and must find the corresponding set of src pixels. */ | |
| 2376 scx = 16.f * (l_float32)ws / (l_float32)wd; | |
| 2377 scy = 16.f * (l_float32)hs / (l_float32)hd; | |
| 2378 wm2 = ws - 2; | |
| 2379 hm2 = hs - 2; | |
| 2380 | |
| 2381 /* Iterate over the destination pixels */ | |
| 2382 for (i = 0; i < hd; i++) { | |
| 2383 ypm = (l_int32)(scy * (l_float32)i); | |
| 2384 yp = ypm >> 4; | |
| 2385 yf = ypm & 0x0f; | |
| 2386 lined = datad + i * wpld; | |
| 2387 lines = datas + yp * wpls; | |
| 2388 for (j = 0; j < wd; j++) { | |
| 2389 xpm = (l_int32)(scx * (l_float32)j); | |
| 2390 xp = xpm >> 4; | |
| 2391 xf = xpm & 0x0f; | |
| 2392 | |
| 2393 /* Do bilinear interpolation. Without this, we could | |
| 2394 * simply subsample: | |
| 2395 * SET_DATA_BYTE(lined, j, GET_DATA_BYTE(lines, xp)); | |
| 2396 * which is faster but gives lousy results! */ | |
| 2397 v00_val = GET_DATA_BYTE(lines, xp); | |
| 2398 if (xp > wm2 || yp > hm2) { | |
| 2399 if (yp > hm2 && xp <= wm2) { /* pixels near bottom */ | |
| 2400 v01_val = v00_val; | |
| 2401 v10_val = GET_DATA_BYTE(lines, xp + 1); | |
| 2402 v11_val = v10_val; | |
| 2403 } else if (xp > wm2 && yp <= hm2) { /* pixels near rt side */ | |
| 2404 v01_val = GET_DATA_BYTE(lines + wpls, xp); | |
| 2405 v10_val = v00_val; | |
| 2406 v11_val = v01_val; | |
| 2407 } else { /* pixels at LR corner */ | |
| 2408 v10_val = v01_val = v11_val = v00_val; | |
| 2409 } | |
| 2410 } else { | |
| 2411 v10_val = GET_DATA_BYTE(lines, xp + 1); | |
| 2412 v01_val = GET_DATA_BYTE(lines + wpls, xp); | |
| 2413 v11_val = GET_DATA_BYTE(lines + wpls, xp + 1); | |
| 2414 } | |
| 2415 | |
| 2416 v00 = (16 - xf) * (16 - yf) * v00_val; | |
| 2417 v10 = xf * (16 - yf) * v10_val; | |
| 2418 v01 = (16 - xf) * yf * v01_val; | |
| 2419 v11 = xf * yf * v11_val; | |
| 2420 | |
| 2421 val = (l_uint8)((v00 + v01 + v10 + v11 + 128) / 256); | |
| 2422 SET_DATA_BYTE(lined, j, val); | |
| 2423 } | |
| 2424 } | |
| 2425 } | |
| 2426 | |
| 2427 | |
| 2428 /*------------------------------------------------------------------* | |
| 2429 * 2x linear interpolated color scaling * | |
| 2430 *------------------------------------------------------------------*/ | |
| 2431 /*! | |
| 2432 * \brief scaleColor2xLILow() | |
| 2433 * | |
| 2434 * <pre> | |
| 2435 * Notes: | |
| 2436 * (1) This is a special case of 2x expansion by linear | |
| 2437 * interpolation. Each src pixel contains 4 dest pixels. | |
| 2438 * The 4 dest pixels in src pixel 1 are numbered at | |
| 2439 * their UL corners. The 4 dest pixels in src pixel 1 | |
| 2440 * are related to that src pixel and its 3 neighboring | |
| 2441 * src pixels as follows: | |
| 2442 * | |
| 2443 * 1-----2-----|-----|-----| | |
| 2444 * | | | | | | |
| 2445 * | | | | | | |
| 2446 * src 1 --> 3-----4-----| | | <-- src 2 | |
| 2447 * | | | | | | |
| 2448 * | | | | | | |
| 2449 * |-----|-----|-----|-----| | |
| 2450 * | | | | | | |
| 2451 * | | | | | | |
| 2452 * src 3 --> | | | | | <-- src 4 | |
| 2453 * | | | | | | |
| 2454 * | | | | | | |
| 2455 * |-----|-----|-----|-----| | |
| 2456 * | |
| 2457 * dest src | |
| 2458 * ---- --- | |
| 2459 * dp1 = sp1 | |
| 2460 * dp2 = (sp1 + sp2) / 2 | |
| 2461 * dp3 = (sp1 + sp3) / 2 | |
| 2462 * dp4 = (sp1 + sp2 + sp3 + sp4) / 4 | |
| 2463 * | |
| 2464 * (2) We iterate over the src pixels, and unroll the calculation | |
| 2465 * for each set of 4 dest pixels corresponding to that src | |
| 2466 * pixel, caching pixels for the next src pixel whenever possible. | |
| 2467 * The method is exactly analogous to the one we use for | |
| 2468 * scaleGray2xLILow() and its line version. | |
| 2469 * </pre> | |
| 2470 */ | |
| 2471 static void | |
| 2472 scaleColor2xLILow(l_uint32 *datad, | |
| 2473 l_int32 wpld, | |
| 2474 l_uint32 *datas, | |
| 2475 l_int32 ws, | |
| 2476 l_int32 hs, | |
| 2477 l_int32 wpls) | |
| 2478 { | |
| 2479 l_int32 i, hsm; | |
| 2480 l_uint32 *lines, *lined; | |
| 2481 | |
| 2482 hsm = hs - 1; | |
| 2483 | |
| 2484 /* We're taking 2 src and 2 dest lines at a time, | |
| 2485 * and for each src line, we're computing 2 dest lines. | |
| 2486 * Call these 2 dest lines: destline1 and destline2. | |
| 2487 * The first src line is used for destline 1. | |
| 2488 * On all but the last src line, both src lines are | |
| 2489 * used in the linear interpolation for destline2. | |
| 2490 * On the last src line, both destline1 and destline2 | |
| 2491 * are computed using only that src line (because there | |
| 2492 * isn't a lower src line). */ | |
| 2493 | |
| 2494 /* iterate over all but the last src line */ | |
| 2495 for (i = 0; i < hsm; i++) { | |
| 2496 lines = datas + i * wpls; | |
| 2497 lined = datad + 2 * i * wpld; | |
| 2498 scaleColor2xLILineLow(lined, wpld, lines, ws, wpls, 0); | |
| 2499 } | |
| 2500 | |
| 2501 /* last src line */ | |
| 2502 lines = datas + hsm * wpls; | |
| 2503 lined = datad + 2 * hsm * wpld; | |
| 2504 scaleColor2xLILineLow(lined, wpld, lines, ws, wpls, 1); | |
| 2505 } | |
| 2506 | |
| 2507 | |
| 2508 /*! | |
| 2509 * \brief scaleColor2xLILineLow() | |
| 2510 * | |
| 2511 * \param[in] lined ptr to top destline, to be made from current src line | |
| 2512 * \param[in] wpld | |
| 2513 * \param[in] lines ptr to current src line | |
| 2514 * \param[in] ws | |
| 2515 * \param[in] wpls | |
| 2516 * \param[in] lastlineflag 1 if last src line; 0 otherwise | |
| 2517 * \return void | |
| 2518 */ | |
| 2519 static void | |
| 2520 scaleColor2xLILineLow(l_uint32 *lined, | |
| 2521 l_int32 wpld, | |
| 2522 l_uint32 *lines, | |
| 2523 l_int32 ws, | |
| 2524 l_int32 wpls, | |
| 2525 l_int32 lastlineflag) | |
| 2526 { | |
| 2527 l_int32 j, jd, wsm; | |
| 2528 l_uint32 rval1, rval2, rval3, rval4, gval1, gval2, gval3, gval4; | |
| 2529 l_uint32 bval1, bval2, bval3, bval4; | |
| 2530 l_uint32 pixels1, pixels2, pixels3, pixels4, pixel; | |
| 2531 l_uint32 *linesp, *linedp; | |
| 2532 | |
| 2533 wsm = ws - 1; | |
| 2534 | |
| 2535 if (lastlineflag == 0) { | |
| 2536 linesp = lines + wpls; | |
| 2537 linedp = lined + wpld; | |
| 2538 pixels1 = *lines; | |
| 2539 pixels3 = *linesp; | |
| 2540 | |
| 2541 /* initialize with v(2) and v(4) */ | |
| 2542 rval2 = pixels1 >> 24; | |
| 2543 gval2 = (pixels1 >> 16) & 0xff; | |
| 2544 bval2 = (pixels1 >> 8) & 0xff; | |
| 2545 rval4 = pixels3 >> 24; | |
| 2546 gval4 = (pixels3 >> 16) & 0xff; | |
| 2547 bval4 = (pixels3 >> 8) & 0xff; | |
| 2548 | |
| 2549 for (j = 0, jd = 0; j < wsm; j++, jd += 2) { | |
| 2550 /* shift in previous src values */ | |
| 2551 rval1 = rval2; | |
| 2552 gval1 = gval2; | |
| 2553 bval1 = bval2; | |
| 2554 rval3 = rval4; | |
| 2555 gval3 = gval4; | |
| 2556 bval3 = bval4; | |
| 2557 /* get new src values */ | |
| 2558 pixels2 = *(lines + j + 1); | |
| 2559 pixels4 = *(linesp + j + 1); | |
| 2560 rval2 = pixels2 >> 24; | |
| 2561 gval2 = (pixels2 >> 16) & 0xff; | |
| 2562 bval2 = (pixels2 >> 8) & 0xff; | |
| 2563 rval4 = pixels4 >> 24; | |
| 2564 gval4 = (pixels4 >> 16) & 0xff; | |
| 2565 bval4 = (pixels4 >> 8) & 0xff; | |
| 2566 /* save dest values */ | |
| 2567 pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8); | |
| 2568 *(lined + jd) = pixel; /* pix 1 */ | |
| 2569 pixel = ((((rval1 + rval2) << 23) & 0xff000000) | | |
| 2570 (((gval1 + gval2) << 15) & 0x00ff0000) | | |
| 2571 (((bval1 + bval2) << 7) & 0x0000ff00)); | |
| 2572 *(lined + jd + 1) = pixel; /* pix 2 */ | |
| 2573 pixel = ((((rval1 + rval3) << 23) & 0xff000000) | | |
| 2574 (((gval1 + gval3) << 15) & 0x00ff0000) | | |
| 2575 (((bval1 + bval3) << 7) & 0x0000ff00)); | |
| 2576 *(linedp + jd) = pixel; /* pix 3 */ | |
| 2577 pixel = ((((rval1 + rval2 + rval3 + rval4) << 22) & 0xff000000) | | |
| 2578 (((gval1 + gval2 + gval3 + gval4) << 14) & 0x00ff0000) | | |
| 2579 (((bval1 + bval2 + bval3 + bval4) << 6) & 0x0000ff00)); | |
| 2580 *(linedp + jd + 1) = pixel; /* pix 4 */ | |
| 2581 } | |
| 2582 /* last src pixel on line */ | |
| 2583 rval1 = rval2; | |
| 2584 gval1 = gval2; | |
| 2585 bval1 = bval2; | |
| 2586 rval3 = rval4; | |
| 2587 gval3 = gval4; | |
| 2588 bval3 = bval4; | |
| 2589 pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8); | |
| 2590 *(lined + 2 * wsm) = pixel; /* pix 1 */ | |
| 2591 *(lined + 2 * wsm + 1) = pixel; /* pix 2 */ | |
| 2592 pixel = ((((rval1 + rval3) << 23) & 0xff000000) | | |
| 2593 (((gval1 + gval3) << 15) & 0x00ff0000) | | |
| 2594 (((bval1 + bval3) << 7) & 0x0000ff00)); | |
| 2595 *(linedp + 2 * wsm) = pixel; /* pix 3 */ | |
| 2596 *(linedp + 2 * wsm + 1) = pixel; /* pix 4 */ | |
| 2597 } else { /* last row of src pixels: lastlineflag == 1 */ | |
| 2598 linedp = lined + wpld; | |
| 2599 pixels2 = *lines; | |
| 2600 rval2 = pixels2 >> 24; | |
| 2601 gval2 = (pixels2 >> 16) & 0xff; | |
| 2602 bval2 = (pixels2 >> 8) & 0xff; | |
| 2603 for (j = 0, jd = 0; j < wsm; j++, jd += 2) { | |
| 2604 rval1 = rval2; | |
| 2605 gval1 = gval2; | |
| 2606 bval1 = bval2; | |
| 2607 pixels2 = *(lines + j + 1); | |
| 2608 rval2 = pixels2 >> 24; | |
| 2609 gval2 = (pixels2 >> 16) & 0xff; | |
| 2610 bval2 = (pixels2 >> 8) & 0xff; | |
| 2611 pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8); | |
| 2612 *(lined + jd) = pixel; /* pix 1 */ | |
| 2613 *(linedp + jd) = pixel; /* pix 2 */ | |
| 2614 pixel = ((((rval1 + rval2) << 23) & 0xff000000) | | |
| 2615 (((gval1 + gval2) << 15) & 0x00ff0000) | | |
| 2616 (((bval1 + bval2) << 7) & 0x0000ff00)); | |
| 2617 *(lined + jd + 1) = pixel; /* pix 3 */ | |
| 2618 *(linedp + jd + 1) = pixel; /* pix 4 */ | |
| 2619 } | |
| 2620 rval1 = rval2; | |
| 2621 gval1 = gval2; | |
| 2622 bval1 = bval2; | |
| 2623 pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8); | |
| 2624 *(lined + 2 * wsm) = pixel; /* pix 1 */ | |
| 2625 *(lined + 2 * wsm + 1) = pixel; /* pix 2 */ | |
| 2626 *(linedp + 2 * wsm) = pixel; /* pix 3 */ | |
| 2627 *(linedp + 2 * wsm + 1) = pixel; /* pix 4 */ | |
| 2628 } | |
| 2629 } | |
| 2630 | |
| 2631 | |
| 2632 /*------------------------------------------------------------------* | |
| 2633 * 2x linear interpolated gray scaling * | |
| 2634 *------------------------------------------------------------------*/ | |
| 2635 /*! | |
| 2636 * \brief scaleGray2xLILow() | |
| 2637 * | |
| 2638 * <pre> | |
| 2639 * Notes: | |
| 2640 * (1) This is a special case of 2x expansion by linear | |
| 2641 * interpolation. Each src pixel contains 4 dest pixels. | |
| 2642 * The 4 dest pixels in src pixel 1 are numbered at | |
| 2643 * their UL corners. The 4 dest pixels in src pixel 1 | |
| 2644 * are related to that src pixel and its 3 neighboring | |
| 2645 * src pixels as follows: | |
| 2646 * | |
| 2647 * 1-----2-----|-----|-----| | |
| 2648 * | | | | | | |
| 2649 * | | | | | | |
| 2650 * src 1 --> 3-----4-----| | | <-- src 2 | |
| 2651 * | | | | | | |
| 2652 * | | | | | | |
| 2653 * |-----|-----|-----|-----| | |
| 2654 * | | | | | | |
| 2655 * | | | | | | |
| 2656 * src 3 --> | | | | | <-- src 4 | |
| 2657 * | | | | | | |
| 2658 * | | | | | | |
| 2659 * |-----|-----|-----|-----| | |
| 2660 * | |
| 2661 * dest src | |
| 2662 * ---- --- | |
| 2663 * dp1 = sp1 | |
| 2664 * dp2 = (sp1 + sp2) / 2 | |
| 2665 * dp3 = (sp1 + sp3) / 2 | |
| 2666 * dp4 = (sp1 + sp2 + sp3 + sp4) / 4 | |
| 2667 * | |
| 2668 * (2) We iterate over the src pixels, and unroll the calculation | |
| 2669 * for each set of 4 dest pixels corresponding to that src | |
| 2670 * pixel, caching pixels for the next src pixel whenever possible. | |
| 2671 * </pre> | |
| 2672 */ | |
| 2673 static void | |
| 2674 scaleGray2xLILow(l_uint32 *datad, | |
| 2675 l_int32 wpld, | |
| 2676 l_uint32 *datas, | |
| 2677 l_int32 ws, | |
| 2678 l_int32 hs, | |
| 2679 l_int32 wpls) | |
| 2680 { | |
| 2681 l_int32 i, hsm; | |
| 2682 l_uint32 *lines, *lined; | |
| 2683 | |
| 2684 hsm = hs - 1; | |
| 2685 | |
| 2686 /* We're taking 2 src and 2 dest lines at a time, | |
| 2687 * and for each src line, we're computing 2 dest lines. | |
| 2688 * Call these 2 dest lines: destline1 and destline2. | |
| 2689 * The first src line is used for destline 1. | |
| 2690 * On all but the last src line, both src lines are | |
| 2691 * used in the linear interpolation for destline2. | |
| 2692 * On the last src line, both destline1 and destline2 | |
| 2693 * are computed using only that src line (because there | |
| 2694 * isn't a lower src line). */ | |
| 2695 | |
| 2696 /* iterate over all but the last src line */ | |
| 2697 for (i = 0; i < hsm; i++) { | |
| 2698 lines = datas + i * wpls; | |
| 2699 lined = datad + 2 * i * wpld; | |
| 2700 scaleGray2xLILineLow(lined, wpld, lines, ws, wpls, 0); | |
| 2701 } | |
| 2702 | |
| 2703 /* last src line */ | |
| 2704 lines = datas + hsm * wpls; | |
| 2705 lined = datad + 2 * hsm * wpld; | |
| 2706 scaleGray2xLILineLow(lined, wpld, lines, ws, wpls, 1); | |
| 2707 } | |
| 2708 | |
| 2709 | |
| 2710 /*! | |
| 2711 * \brief scaleGray2xLILineLow() | |
| 2712 * | |
| 2713 * \param[in] lined ptr to top destline, to be made from current src line | |
| 2714 * \param[in] wpld | |
| 2715 * \param[in] lines ptr to current src line | |
| 2716 * \param[in] ws | |
| 2717 * \param[in] wpls | |
| 2718 * \param[in] lastlineflag 1 if last src line; 0 otherwise | |
| 2719 * \return void | |
| 2720 */ | |
| 2721 static void | |
| 2722 scaleGray2xLILineLow(l_uint32 *lined, | |
| 2723 l_int32 wpld, | |
| 2724 l_uint32 *lines, | |
| 2725 l_int32 ws, | |
| 2726 l_int32 wpls, | |
| 2727 l_int32 lastlineflag) | |
| 2728 { | |
| 2729 l_int32 j, jd, wsm, w; | |
| 2730 l_uint32 sval1, sval2, sval3, sval4; | |
| 2731 l_uint32 *linesp, *linedp; | |
| 2732 l_uint32 words, wordsp, wordd, worddp; | |
| 2733 | |
| 2734 wsm = ws - 1; | |
| 2735 | |
| 2736 if (lastlineflag == 0) { | |
| 2737 linesp = lines + wpls; | |
| 2738 linedp = lined + wpld; | |
| 2739 | |
| 2740 /* Unroll the loop 4x and work on full words */ | |
| 2741 words = lines[0]; | |
| 2742 wordsp = linesp[0]; | |
| 2743 sval2 = (words >> 24) & 0xff; | |
| 2744 sval4 = (wordsp >> 24) & 0xff; | |
| 2745 for (j = 0, jd = 0, w = 0; j + 3 < wsm; j += 4, jd += 8, w++) { | |
| 2746 /* At the top of the loop, | |
| 2747 * words == lines[w], wordsp == linesp[w] | |
| 2748 * and the top bytes of those have been loaded into | |
| 2749 * sval2 and sval4. */ | |
| 2750 sval1 = sval2; | |
| 2751 sval2 = (words >> 16) & 0xff; | |
| 2752 sval3 = sval4; | |
| 2753 sval4 = (wordsp >> 16) & 0xff; | |
| 2754 wordd = (sval1 << 24) | (((sval1 + sval2) >> 1) << 16); | |
| 2755 worddp = (((sval1 + sval3) >> 1) << 24) | | |
| 2756 (((sval1 + sval2 + sval3 + sval4) >> 2) << 16); | |
| 2757 | |
| 2758 sval1 = sval2; | |
| 2759 sval2 = (words >> 8) & 0xff; | |
| 2760 sval3 = sval4; | |
| 2761 sval4 = (wordsp >> 8) & 0xff; | |
| 2762 wordd |= (sval1 << 8) | ((sval1 + sval2) >> 1); | |
| 2763 worddp |= (((sval1 + sval3) >> 1) << 8) | | |
| 2764 ((sval1 + sval2 + sval3 + sval4) >> 2); | |
| 2765 lined[w * 2] = wordd; | |
| 2766 linedp[w * 2] = worddp; | |
| 2767 | |
| 2768 sval1 = sval2; | |
| 2769 sval2 = words & 0xff; | |
| 2770 sval3 = sval4; | |
| 2771 sval4 = wordsp & 0xff; | |
| 2772 wordd = (sval1 << 24) | /* pix 1 */ | |
| 2773 (((sval1 + sval2) >> 1) << 16); /* pix 2 */ | |
| 2774 worddp = (((sval1 + sval3) >> 1) << 24) | /* pix 3 */ | |
| 2775 (((sval1 + sval2 + sval3 + sval4) >> 2) << 16); /* pix 4 */ | |
| 2776 | |
| 2777 /* Load the next word as we need its first byte */ | |
| 2778 words = lines[w + 1]; | |
| 2779 wordsp = linesp[w + 1]; | |
| 2780 sval1 = sval2; | |
| 2781 sval2 = (words >> 24) & 0xff; | |
| 2782 sval3 = sval4; | |
| 2783 sval4 = (wordsp >> 24) & 0xff; | |
| 2784 wordd |= (sval1 << 8) | /* pix 1 */ | |
| 2785 ((sval1 + sval2) >> 1); /* pix 2 */ | |
| 2786 worddp |= (((sval1 + sval3) >> 1) << 8) | /* pix 3 */ | |
| 2787 ((sval1 + sval2 + sval3 + sval4) >> 2); /* pix 4 */ | |
| 2788 lined[w * 2 + 1] = wordd; | |
| 2789 linedp[w * 2 + 1] = worddp; | |
| 2790 } | |
| 2791 | |
| 2792 /* Finish up the last word */ | |
| 2793 for (; j < wsm; j++, jd += 2) { | |
| 2794 sval1 = sval2; | |
| 2795 sval3 = sval4; | |
| 2796 sval2 = GET_DATA_BYTE(lines, j + 1); | |
| 2797 sval4 = GET_DATA_BYTE(linesp, j + 1); | |
| 2798 SET_DATA_BYTE(lined, jd, sval1); /* pix 1 */ | |
| 2799 SET_DATA_BYTE(lined, jd + 1, (sval1 + sval2) / 2); /* pix 2 */ | |
| 2800 SET_DATA_BYTE(linedp, jd, (sval1 + sval3) / 2); /* pix 3 */ | |
| 2801 SET_DATA_BYTE(linedp, jd + 1, | |
| 2802 (sval1 + sval2 + sval3 + sval4) / 4); /* pix 4 */ | |
| 2803 } | |
| 2804 sval1 = sval2; | |
| 2805 sval3 = sval4; | |
| 2806 SET_DATA_BYTE(lined, 2 * wsm, sval1); /* pix 1 */ | |
| 2807 SET_DATA_BYTE(lined, 2 * wsm + 1, sval1); /* pix 2 */ | |
| 2808 SET_DATA_BYTE(linedp, 2 * wsm, (sval1 + sval3) / 2); /* pix 3 */ | |
| 2809 SET_DATA_BYTE(linedp, 2 * wsm + 1, (sval1 + sval3) / 2); /* pix 4 */ | |
| 2810 | |
| 2811 #if DEBUG_UNROLLING | |
| 2812 #define CHECK_BYTE(a, b, c) if (GET_DATA_BYTE(a, b) != c) {\ | |
| 2813 lept_stderr("Error: mismatch at %d, %d vs %d\n", \ | |
| 2814 j, GET_DATA_BYTE(a, b), c); } | |
| 2815 | |
| 2816 sval2 = GET_DATA_BYTE(lines, 0); | |
| 2817 sval4 = GET_DATA_BYTE(linesp, 0); | |
| 2818 for (j = 0, jd = 0; j < wsm; j++, jd += 2) { | |
| 2819 sval1 = sval2; | |
| 2820 sval3 = sval4; | |
| 2821 sval2 = GET_DATA_BYTE(lines, j + 1); | |
| 2822 sval4 = GET_DATA_BYTE(linesp, j + 1); | |
| 2823 CHECK_BYTE(lined, jd, sval1); /* pix 1 */ | |
| 2824 CHECK_BYTE(lined, jd + 1, (sval1 + sval2) / 2); /* pix 2 */ | |
| 2825 CHECK_BYTE(linedp, jd, (sval1 + sval3) / 2); /* pix 3 */ | |
| 2826 CHECK_BYTE(linedp, jd + 1, | |
| 2827 (sval1 + sval2 + sval3 + sval4) / 4); /* pix 4 */ | |
| 2828 } | |
| 2829 sval1 = sval2; | |
| 2830 sval3 = sval4; | |
| 2831 CHECK_BYTE(lined, 2 * wsm, sval1); /* pix 1 */ | |
| 2832 CHECK_BYTE(lined, 2 * wsm + 1, sval1); /* pix 2 */ | |
| 2833 CHECK_BYTE(linedp, 2 * wsm, (sval1 + sval3) / 2); /* pix 3 */ | |
| 2834 CHECK_BYTE(linedp, 2 * wsm + 1, (sval1 + sval3) / 2); /* pix 4 */ | |
| 2835 #undef CHECK_BYTE | |
| 2836 #endif | |
| 2837 } else { /* last row of src pixels: lastlineflag == 1 */ | |
| 2838 linedp = lined + wpld; | |
| 2839 sval2 = GET_DATA_BYTE(lines, 0); | |
| 2840 for (j = 0, jd = 0; j < wsm; j++, jd += 2) { | |
| 2841 sval1 = sval2; | |
| 2842 sval2 = GET_DATA_BYTE(lines, j + 1); | |
| 2843 SET_DATA_BYTE(lined, jd, sval1); /* pix 1 */ | |
| 2844 SET_DATA_BYTE(linedp, jd, sval1); /* pix 3 */ | |
| 2845 SET_DATA_BYTE(lined, jd + 1, (sval1 + sval2) / 2); /* pix 2 */ | |
| 2846 SET_DATA_BYTE(linedp, jd + 1, (sval1 + sval2) / 2); /* pix 4 */ | |
| 2847 } | |
| 2848 sval1 = sval2; | |
| 2849 SET_DATA_BYTE(lined, 2 * wsm, sval1); /* pix 1 */ | |
| 2850 SET_DATA_BYTE(lined, 2 * wsm + 1, sval1); /* pix 2 */ | |
| 2851 SET_DATA_BYTE(linedp, 2 * wsm, sval1); /* pix 3 */ | |
| 2852 SET_DATA_BYTE(linedp, 2 * wsm + 1, sval1); /* pix 4 */ | |
| 2853 } | |
| 2854 } | |
| 2855 | |
| 2856 | |
| 2857 /*------------------------------------------------------------------* | |
| 2858 * 4x linear interpolated gray scaling * | |
| 2859 *------------------------------------------------------------------*/ | |
| 2860 /*! | |
| 2861 * \brief scaleGray4xLILow() | |
| 2862 * | |
| 2863 * <pre> | |
| 2864 * Notes: | |
| 2865 * (1) This is a special case of 4x expansion by linear | |
| 2866 * interpolation. Each src pixel contains 16 dest pixels. | |
| 2867 * The 16 dest pixels in src pixel 1 are numbered at | |
| 2868 * their UL corners. The 16 dest pixels in src pixel 1 | |
| 2869 * are related to that src pixel and its 3 neighboring | |
| 2870 * src pixels as follows: | |
| 2871 * | |
| 2872 * 1---2---3---4---|---|---|---|---| | |
| 2873 * | | | | | | | | | | |
| 2874 * 5---6---7---8---|---|---|---|---| | |
| 2875 * | | | | | | | | | | |
| 2876 * src 1 --> 9---a---b---c---|---|---|---|---| <-- src 2 | |
| 2877 * | | | | | | | | | | |
| 2878 * d---e---f---g---|---|---|---|---| | |
| 2879 * | | | | | | | | | | |
| 2880 * |===|===|===|===|===|===|===|===| | |
| 2881 * | | | | | | | | | | |
| 2882 * |---|---|---|---|---|---|---|---| | |
| 2883 * | | | | | | | | | | |
| 2884 * src 3 --> |---|---|---|---|---|---|---|---| <-- src 4 | |
| 2885 * | | | | | | | | | | |
| 2886 * |---|---|---|---|---|---|---|---| | |
| 2887 * | | | | | | | | | | |
| 2888 * |---|---|---|---|---|---|---|---| | |
| 2889 * | |
| 2890 * dest src | |
| 2891 * ---- --- | |
| 2892 * dp1 = sp1 | |
| 2893 * dp2 = (3 * sp1 + sp2) / 4 | |
| 2894 * dp3 = (sp1 + sp2) / 2 | |
| 2895 * dp4 = (sp1 + 3 * sp2) / 4 | |
| 2896 * dp5 = (3 * sp1 + sp3) / 4 | |
| 2897 * dp6 = (9 * sp1 + 3 * sp2 + 3 * sp3 + sp4) / 16 | |
| 2898 * dp7 = (3 * sp1 + 3 * sp2 + sp3 + sp4) / 8 | |
| 2899 * dp8 = (3 * sp1 + 9 * sp2 + 1 * sp3 + 3 * sp4) / 16 | |
| 2900 * dp9 = (sp1 + sp3) / 2 | |
| 2901 * dp10 = (3 * sp1 + sp2 + 3 * sp3 + sp4) / 8 | |
| 2902 * dp11 = (sp1 + sp2 + sp3 + sp4) / 4 | |
| 2903 * dp12 = (sp1 + 3 * sp2 + sp3 + 3 * sp4) / 8 | |
| 2904 * dp13 = (sp1 + 3 * sp3) / 4 | |
| 2905 * dp14 = (3 * sp1 + sp2 + 9 * sp3 + 3 * sp4) / 16 | |
| 2906 * dp15 = (sp1 + sp2 + 3 * sp3 + 3 * sp4) / 8 | |
| 2907 * dp16 = (sp1 + 3 * sp2 + 3 * sp3 + 9 * sp4) / 16 | |
| 2908 * | |
| 2909 * (2) We iterate over the src pixels, and unroll the calculation | |
| 2910 * for each set of 16 dest pixels corresponding to that src | |
| 2911 * pixel, caching pixels for the next src pixel whenever possible. | |
| 2912 * </pre> | |
| 2913 */ | |
| 2914 static void | |
| 2915 scaleGray4xLILow(l_uint32 *datad, | |
| 2916 l_int32 wpld, | |
| 2917 l_uint32 *datas, | |
| 2918 l_int32 ws, | |
| 2919 l_int32 hs, | |
| 2920 l_int32 wpls) | |
| 2921 { | |
| 2922 l_int32 i, hsm; | |
| 2923 l_uint32 *lines, *lined; | |
| 2924 | |
| 2925 hsm = hs - 1; | |
| 2926 | |
| 2927 /* We're taking 2 src and 4 dest lines at a time, | |
| 2928 * and for each src line, we're computing 4 dest lines. | |
| 2929 * Call these 4 dest lines: destline1 - destline4. | |
| 2930 * The first src line is used for destline 1. | |
| 2931 * Two src lines are used for all other dest lines, | |
| 2932 * except for the last 4 dest lines, which are computed | |
| 2933 * using only the last src line. */ | |
| 2934 | |
| 2935 /* iterate over all but the last src line */ | |
| 2936 for (i = 0; i < hsm; i++) { | |
| 2937 lines = datas + i * wpls; | |
| 2938 lined = datad + 4 * i * wpld; | |
| 2939 scaleGray4xLILineLow(lined, wpld, lines, ws, wpls, 0); | |
| 2940 } | |
| 2941 | |
| 2942 /* last src line */ | |
| 2943 lines = datas + hsm * wpls; | |
| 2944 lined = datad + 4 * hsm * wpld; | |
| 2945 scaleGray4xLILineLow(lined, wpld, lines, ws, wpls, 1); | |
| 2946 } | |
| 2947 | |
| 2948 | |
| 2949 /*! | |
| 2950 * \brief scaleGray4xLILineLow() | |
| 2951 * | |
| 2952 * \param[in] lined ptr to top destline, to be made from current src line | |
| 2953 * \param[in] wpld | |
| 2954 * \param[in] lines ptr to current src line | |
| 2955 * \param[in] ws | |
| 2956 * \param[in] wpls | |
| 2957 * \param[in] lastlineflag 1 if last src line; 0 otherwise | |
| 2958 * \return void | |
| 2959 */ | |
| 2960 static void | |
| 2961 scaleGray4xLILineLow(l_uint32 *lined, | |
| 2962 l_int32 wpld, | |
| 2963 l_uint32 *lines, | |
| 2964 l_int32 ws, | |
| 2965 l_int32 wpls, | |
| 2966 l_int32 lastlineflag) | |
| 2967 { | |
| 2968 l_int32 j, jd, wsm, wsm4; | |
| 2969 l_int32 s1, s2, s3, s4, s1t, s2t, s3t, s4t; | |
| 2970 l_uint32 *linesp, *linedp1, *linedp2, *linedp3; | |
| 2971 | |
| 2972 wsm = ws - 1; | |
| 2973 wsm4 = 4 * wsm; | |
| 2974 | |
| 2975 if (lastlineflag == 0) { | |
| 2976 linesp = lines + wpls; | |
| 2977 linedp1 = lined + wpld; | |
| 2978 linedp2 = lined + 2 * wpld; | |
| 2979 linedp3 = lined + 3 * wpld; | |
| 2980 s2 = GET_DATA_BYTE(lines, 0); | |
| 2981 s4 = GET_DATA_BYTE(linesp, 0); | |
| 2982 for (j = 0, jd = 0; j < wsm; j++, jd += 4) { | |
| 2983 s1 = s2; | |
| 2984 s3 = s4; | |
| 2985 s2 = GET_DATA_BYTE(lines, j + 1); | |
| 2986 s4 = GET_DATA_BYTE(linesp, j + 1); | |
| 2987 s1t = 3 * s1; | |
| 2988 s2t = 3 * s2; | |
| 2989 s3t = 3 * s3; | |
| 2990 s4t = 3 * s4; | |
| 2991 SET_DATA_BYTE(lined, jd, s1); /* d1 */ | |
| 2992 SET_DATA_BYTE(lined, jd + 1, (s1t + s2) / 4); /* d2 */ | |
| 2993 SET_DATA_BYTE(lined, jd + 2, (s1 + s2) / 2); /* d3 */ | |
| 2994 SET_DATA_BYTE(lined, jd + 3, (s1 + s2t) / 4); /* d4 */ | |
| 2995 SET_DATA_BYTE(linedp1, jd, (s1t + s3) / 4); /* d5 */ | |
| 2996 SET_DATA_BYTE(linedp1, jd + 1, (9*s1 + s2t + s3t + s4) / 16); /*d6*/ | |
| 2997 SET_DATA_BYTE(linedp1, jd + 2, (s1t + s2t + s3 + s4) / 8); /* d7 */ | |
| 2998 SET_DATA_BYTE(linedp1, jd + 3, (s1t + 9*s2 + s3 + s4t) / 16);/*d8*/ | |
| 2999 SET_DATA_BYTE(linedp2, jd, (s1 + s3) / 2); /* d9 */ | |
| 3000 SET_DATA_BYTE(linedp2, jd + 1, (s1t + s2 + s3t + s4) / 8);/* d10 */ | |
| 3001 SET_DATA_BYTE(linedp2, jd + 2, (s1 + s2 + s3 + s4) / 4); /* d11 */ | |
| 3002 SET_DATA_BYTE(linedp2, jd + 3, (s1 + s2t + s3 + s4t) / 8);/* d12 */ | |
| 3003 SET_DATA_BYTE(linedp3, jd, (s1 + s3t) / 4); /* d13 */ | |
| 3004 SET_DATA_BYTE(linedp3, jd + 1, (s1t + s2 + 9*s3 + s4t) / 16);/*d14*/ | |
| 3005 SET_DATA_BYTE(linedp3, jd + 2, (s1 + s2 + s3t + s4t) / 8); /* d15 */ | |
| 3006 SET_DATA_BYTE(linedp3, jd + 3, (s1 + s2t + s3t + 9*s4) / 16);/*d16*/ | |
| 3007 } | |
| 3008 s1 = s2; | |
| 3009 s3 = s4; | |
| 3010 s1t = 3 * s1; | |
| 3011 s3t = 3 * s3; | |
| 3012 SET_DATA_BYTE(lined, wsm4, s1); /* d1 */ | |
| 3013 SET_DATA_BYTE(lined, wsm4 + 1, s1); /* d2 */ | |
| 3014 SET_DATA_BYTE(lined, wsm4 + 2, s1); /* d3 */ | |
| 3015 SET_DATA_BYTE(lined, wsm4 + 3, s1); /* d4 */ | |
| 3016 SET_DATA_BYTE(linedp1, wsm4, (s1t + s3) / 4); /* d5 */ | |
| 3017 SET_DATA_BYTE(linedp1, wsm4 + 1, (s1t + s3) / 4); /* d6 */ | |
| 3018 SET_DATA_BYTE(linedp1, wsm4 + 2, (s1t + s3) / 4); /* d7 */ | |
| 3019 SET_DATA_BYTE(linedp1, wsm4 + 3, (s1t + s3) / 4); /* d8 */ | |
| 3020 SET_DATA_BYTE(linedp2, wsm4, (s1 + s3) / 2); /* d9 */ | |
| 3021 SET_DATA_BYTE(linedp2, wsm4 + 1, (s1 + s3) / 2); /* d10 */ | |
| 3022 SET_DATA_BYTE(linedp2, wsm4 + 2, (s1 + s3) / 2); /* d11 */ | |
| 3023 SET_DATA_BYTE(linedp2, wsm4 + 3, (s1 + s3) / 2); /* d12 */ | |
| 3024 SET_DATA_BYTE(linedp3, wsm4, (s1 + s3t) / 4); /* d13 */ | |
| 3025 SET_DATA_BYTE(linedp3, wsm4 + 1, (s1 + s3t) / 4); /* d14 */ | |
| 3026 SET_DATA_BYTE(linedp3, wsm4 + 2, (s1 + s3t) / 4); /* d15 */ | |
| 3027 SET_DATA_BYTE(linedp3, wsm4 + 3, (s1 + s3t) / 4); /* d16 */ | |
| 3028 } else { /* last row of src pixels: lastlineflag == 1 */ | |
| 3029 linedp1 = lined + wpld; | |
| 3030 linedp2 = lined + 2 * wpld; | |
| 3031 linedp3 = lined + 3 * wpld; | |
| 3032 s2 = GET_DATA_BYTE(lines, 0); | |
| 3033 for (j = 0, jd = 0; j < wsm; j++, jd += 4) { | |
| 3034 s1 = s2; | |
| 3035 s2 = GET_DATA_BYTE(lines, j + 1); | |
| 3036 s1t = 3 * s1; | |
| 3037 s2t = 3 * s2; | |
| 3038 SET_DATA_BYTE(lined, jd, s1); /* d1 */ | |
| 3039 SET_DATA_BYTE(lined, jd + 1, (s1t + s2) / 4 ); /* d2 */ | |
| 3040 SET_DATA_BYTE(lined, jd + 2, (s1 + s2) / 2 ); /* d3 */ | |
| 3041 SET_DATA_BYTE(lined, jd + 3, (s1 + s2t) / 4 ); /* d4 */ | |
| 3042 SET_DATA_BYTE(linedp1, jd, s1); /* d5 */ | |
| 3043 SET_DATA_BYTE(linedp1, jd + 1, (s1t + s2) / 4 ); /* d6 */ | |
| 3044 SET_DATA_BYTE(linedp1, jd + 2, (s1 + s2) / 2 ); /* d7 */ | |
| 3045 SET_DATA_BYTE(linedp1, jd + 3, (s1 + s2t) / 4 ); /* d8 */ | |
| 3046 SET_DATA_BYTE(linedp2, jd, s1); /* d9 */ | |
| 3047 SET_DATA_BYTE(linedp2, jd + 1, (s1t + s2) / 4 ); /* d10 */ | |
| 3048 SET_DATA_BYTE(linedp2, jd + 2, (s1 + s2) / 2 ); /* d11 */ | |
| 3049 SET_DATA_BYTE(linedp2, jd + 3, (s1 + s2t) / 4 ); /* d12 */ | |
| 3050 SET_DATA_BYTE(linedp3, jd, s1); /* d13 */ | |
| 3051 SET_DATA_BYTE(linedp3, jd + 1, (s1t + s2) / 4 ); /* d14 */ | |
| 3052 SET_DATA_BYTE(linedp3, jd + 2, (s1 + s2) / 2 ); /* d15 */ | |
| 3053 SET_DATA_BYTE(linedp3, jd + 3, (s1 + s2t) / 4 ); /* d16 */ | |
| 3054 } | |
| 3055 s1 = s2; | |
| 3056 SET_DATA_BYTE(lined, wsm4, s1); /* d1 */ | |
| 3057 SET_DATA_BYTE(lined, wsm4 + 1, s1); /* d2 */ | |
| 3058 SET_DATA_BYTE(lined, wsm4 + 2, s1); /* d3 */ | |
| 3059 SET_DATA_BYTE(lined, wsm4 + 3, s1); /* d4 */ | |
| 3060 SET_DATA_BYTE(linedp1, wsm4, s1); /* d5 */ | |
| 3061 SET_DATA_BYTE(linedp1, wsm4 + 1, s1); /* d6 */ | |
| 3062 SET_DATA_BYTE(linedp1, wsm4 + 2, s1); /* d7 */ | |
| 3063 SET_DATA_BYTE(linedp1, wsm4 + 3, s1); /* d8 */ | |
| 3064 SET_DATA_BYTE(linedp2, wsm4, s1); /* d9 */ | |
| 3065 SET_DATA_BYTE(linedp2, wsm4 + 1, s1); /* d10 */ | |
| 3066 SET_DATA_BYTE(linedp2, wsm4 + 2, s1); /* d11 */ | |
| 3067 SET_DATA_BYTE(linedp2, wsm4 + 3, s1); /* d12 */ | |
| 3068 SET_DATA_BYTE(linedp3, wsm4, s1); /* d13 */ | |
| 3069 SET_DATA_BYTE(linedp3, wsm4 + 1, s1); /* d14 */ | |
| 3070 SET_DATA_BYTE(linedp3, wsm4 + 2, s1); /* d15 */ | |
| 3071 SET_DATA_BYTE(linedp3, wsm4 + 3, s1); /* d16 */ | |
| 3072 } | |
| 3073 } | |
| 3074 | |
| 3075 | |
| 3076 /*------------------------------------------------------------------* | |
| 3077 * Grayscale and color scaling by closest pixel sampling * | |
| 3078 *------------------------------------------------------------------*/ | |
| 3079 /*! | |
| 3080 * \brief scaleBySamplingLow() | |
| 3081 * | |
| 3082 * <pre> | |
| 3083 * Notes: | |
| 3084 * (1) The dest must be cleared prior to this operation, | |
| 3085 * and we clear it here in the low-level code. | |
| 3086 * (2) We reuse dest pixels and dest pixel rows whenever | |
| 3087 * possible. This speeds the upscaling; downscaling | |
| 3088 * is done by strict subsampling and is unaffected. | |
| 3089 * (3) Because we are sampling and not interpolating, this | |
| 3090 * routine works directly, without conversion to full | |
| 3091 * RGB color, for 2, 4 or 8 bpp palette color images. | |
| 3092 * </pre> | |
| 3093 */ | |
| 3094 static l_int32 | |
| 3095 scaleBySamplingLow(l_uint32 *datad, | |
| 3096 l_int32 wd, | |
| 3097 l_int32 hd, | |
| 3098 l_int32 wpld, | |
| 3099 l_uint32 *datas, | |
| 3100 l_int32 ws, | |
| 3101 l_int32 hs, | |
| 3102 l_int32 d, | |
| 3103 l_int32 wpls, | |
| 3104 l_float32 shiftx, | |
| 3105 l_float32 shifty) | |
| 3106 { | |
| 3107 l_int32 i, j; | |
| 3108 l_int32 xs, prevxs, sval; | |
| 3109 l_int32 *srow, *scol; | |
| 3110 l_uint32 csval; | |
| 3111 l_uint32 *lines, *prevlines, *lined, *prevlined; | |
| 3112 l_float32 wratio, hratio; | |
| 3113 | |
| 3114 if (d != 2 && d != 4 && d !=8 && d != 16 && d != 32) | |
| 3115 return ERROR_INT("pixel depth not supported", __func__, 1); | |
| 3116 | |
| 3117 /* Clear dest */ | |
| 3118 memset(datad, 0, 4LL * hd * wpld); | |
| 3119 | |
| 3120 /* the source row corresponding to dest row i ==> srow[i] | |
| 3121 * the source col corresponding to dest col j ==> scol[j] */ | |
| 3122 if ((srow = (l_int32 *)LEPT_CALLOC(hd, sizeof(l_int32))) == NULL) | |
| 3123 return ERROR_INT("srow not made", __func__, 1); | |
| 3124 if ((scol = (l_int32 *)LEPT_CALLOC(wd, sizeof(l_int32))) == NULL) { | |
| 3125 LEPT_FREE(srow); | |
| 3126 return ERROR_INT("scol not made", __func__, 1); | |
| 3127 } | |
| 3128 | |
| 3129 wratio = (l_float32)ws / (l_float32)wd; | |
| 3130 hratio = (l_float32)hs / (l_float32)hd; | |
| 3131 for (i = 0; i < hd; i++) | |
| 3132 srow[i] = L_MIN((l_int32)(hratio * i + shifty), hs - 1); | |
| 3133 for (j = 0; j < wd; j++) | |
| 3134 scol[j] = L_MIN((l_int32)(wratio * j + shiftx), ws - 1); | |
| 3135 | |
| 3136 prevlines = NULL; | |
| 3137 for (i = 0; i < hd; i++) { | |
| 3138 lines = datas + srow[i] * wpls; | |
| 3139 lined = datad + i * wpld; | |
| 3140 if (lines != prevlines) { /* make dest from new source row */ | |
| 3141 prevxs = -1; | |
| 3142 sval = 0; | |
| 3143 csval = 0; | |
| 3144 if (d == 2) { | |
| 3145 for (j = 0; j < wd; j++) { | |
| 3146 xs = scol[j]; | |
| 3147 if (xs != prevxs) { /* get dest pix from source col */ | |
| 3148 sval = GET_DATA_DIBIT(lines, xs); | |
| 3149 SET_DATA_DIBIT(lined, j, sval); | |
| 3150 prevxs = xs; | |
| 3151 } else { /* copy prev dest pix */ | |
| 3152 SET_DATA_DIBIT(lined, j, sval); | |
| 3153 } | |
| 3154 } | |
| 3155 } else if (d == 4) { | |
| 3156 for (j = 0; j < wd; j++) { | |
| 3157 xs = scol[j]; | |
| 3158 if (xs != prevxs) { /* get dest pix from source col */ | |
| 3159 sval = GET_DATA_QBIT(lines, xs); | |
| 3160 SET_DATA_QBIT(lined, j, sval); | |
| 3161 prevxs = xs; | |
| 3162 } else { /* copy prev dest pix */ | |
| 3163 SET_DATA_QBIT(lined, j, sval); | |
| 3164 } | |
| 3165 } | |
| 3166 } else if (d == 8) { | |
| 3167 for (j = 0; j < wd; j++) { | |
| 3168 xs = scol[j]; | |
| 3169 if (xs != prevxs) { /* get dest pix from source col */ | |
| 3170 sval = GET_DATA_BYTE(lines, xs); | |
| 3171 SET_DATA_BYTE(lined, j, sval); | |
| 3172 prevxs = xs; | |
| 3173 } else { /* copy prev dest pix */ | |
| 3174 SET_DATA_BYTE(lined, j, sval); | |
| 3175 } | |
| 3176 } | |
| 3177 } else if (d == 16) { | |
| 3178 for (j = 0; j < wd; j++) { | |
| 3179 xs = scol[j]; | |
| 3180 if (xs != prevxs) { /* get dest pix from source col */ | |
| 3181 sval = GET_DATA_TWO_BYTES(lines, xs); | |
| 3182 SET_DATA_TWO_BYTES(lined, j, sval); | |
| 3183 prevxs = xs; | |
| 3184 } else { /* copy prev dest pix */ | |
| 3185 SET_DATA_TWO_BYTES(lined, j, sval); | |
| 3186 } | |
| 3187 } | |
| 3188 } else { /* d == 32 */ | |
| 3189 for (j = 0; j < wd; j++) { | |
| 3190 xs = scol[j]; | |
| 3191 if (xs != prevxs) { /* get dest pix from source col */ | |
| 3192 csval = lines[xs]; | |
| 3193 lined[j] = csval; | |
| 3194 prevxs = xs; | |
| 3195 } else { /* copy prev dest pix */ | |
| 3196 lined[j] = csval; | |
| 3197 } | |
| 3198 } | |
| 3199 } | |
| 3200 } else { /* lines == prevlines; copy prev dest row */ | |
| 3201 prevlined = lined - wpld; | |
| 3202 memcpy(lined, prevlined, 4 * wpld); | |
| 3203 } | |
| 3204 prevlines = lines; | |
| 3205 } | |
| 3206 | |
| 3207 LEPT_FREE(srow); | |
| 3208 LEPT_FREE(scol); | |
| 3209 return 0; | |
| 3210 } | |
| 3211 | |
| 3212 | |
| 3213 /*------------------------------------------------------------------* | |
| 3214 * Color and grayscale downsampling with (antialias) smoothing * | |
| 3215 *------------------------------------------------------------------*/ | |
| 3216 /*! | |
| 3217 * \brief scaleSmoothLow() | |
| 3218 * | |
| 3219 * <pre> | |
| 3220 * Notes: | |
| 3221 * (1) This function is called on 8 or 32 bpp src and dest images. | |
| 3222 * (2) size is the full width of the lowpass smoothing filter. | |
| 3223 * It is correlated with the reduction ratio, being the | |
| 3224 * nearest integer such that size is approximately equal to hs / hd. | |
| 3225 * </pre> | |
| 3226 */ | |
| 3227 static l_int32 | |
| 3228 scaleSmoothLow(l_uint32 *datad, | |
| 3229 l_int32 wd, | |
| 3230 l_int32 hd, | |
| 3231 l_int32 wpld, | |
| 3232 l_uint32 *datas, | |
| 3233 l_int32 ws, | |
| 3234 l_int32 hs, | |
| 3235 l_int32 d, | |
| 3236 l_int32 wpls, | |
| 3237 l_int32 size) | |
| 3238 { | |
| 3239 l_int32 i, j, m, n, xstart; | |
| 3240 l_int32 val, rval, gval, bval; | |
| 3241 l_int32 *srow, *scol; | |
| 3242 l_uint32 *lines, *lined, *line, *ppixel; | |
| 3243 l_uint32 pixel; | |
| 3244 l_float32 wratio, hratio, norm; | |
| 3245 | |
| 3246 /* Clear dest */ | |
| 3247 memset(datad, 0, 4LL * wpld * hd); | |
| 3248 | |
| 3249 /* Each dest pixel at (j,i) is computed as the average | |
| 3250 of size^2 corresponding src pixels. | |
| 3251 We store the UL corner location of the square of | |
| 3252 src pixels that correspond to dest pixel (j,i). | |
| 3253 The are labeled by the arrays srow[i] and scol[j]. */ | |
| 3254 if ((srow = (l_int32 *)LEPT_CALLOC(hd, sizeof(l_int32))) == NULL) | |
| 3255 return ERROR_INT("srow not made", __func__, 1); | |
| 3256 if ((scol = (l_int32 *)LEPT_CALLOC(wd, sizeof(l_int32))) == NULL) { | |
| 3257 LEPT_FREE(srow); | |
| 3258 return ERROR_INT("scol not made", __func__, 1); | |
| 3259 } | |
| 3260 | |
| 3261 norm = 1.f / (l_float32)(size * size); | |
| 3262 wratio = (l_float32)ws / (l_float32)wd; | |
| 3263 hratio = (l_float32)hs / (l_float32)hd; | |
| 3264 for (i = 0; i < hd; i++) | |
| 3265 srow[i] = L_MIN((l_int32)(hratio * i), hs - size); | |
| 3266 for (j = 0; j < wd; j++) | |
| 3267 scol[j] = L_MIN((l_int32)(wratio * j), ws - size); | |
| 3268 | |
| 3269 /* For each dest pixel, compute average */ | |
| 3270 if (d == 8) { | |
| 3271 for (i = 0; i < hd; i++) { | |
| 3272 lines = datas + srow[i] * wpls; | |
| 3273 lined = datad + i * wpld; | |
| 3274 for (j = 0; j < wd; j++) { | |
| 3275 xstart = scol[j]; | |
| 3276 val = 0; | |
| 3277 for (m = 0; m < size; m++) { | |
| 3278 line = lines + m * wpls; | |
| 3279 for (n = 0; n < size; n++) { | |
| 3280 val += GET_DATA_BYTE(line, xstart + n); | |
| 3281 } | |
| 3282 } | |
| 3283 val = (l_int32)((l_float32)val * norm); | |
| 3284 SET_DATA_BYTE(lined, j, val); | |
| 3285 } | |
| 3286 } | |
| 3287 } else { /* d == 32 */ | |
| 3288 for (i = 0; i < hd; i++) { | |
| 3289 lines = datas + srow[i] * wpls; | |
| 3290 lined = datad + i * wpld; | |
| 3291 for (j = 0; j < wd; j++) { | |
| 3292 xstart = scol[j]; | |
| 3293 rval = gval = bval = 0; | |
| 3294 for (m = 0; m < size; m++) { | |
| 3295 ppixel = lines + m * wpls + xstart; | |
| 3296 for (n = 0; n < size; n++) { | |
| 3297 pixel = *(ppixel + n); | |
| 3298 rval += (pixel >> L_RED_SHIFT) & 0xff; | |
| 3299 gval += (pixel >> L_GREEN_SHIFT) & 0xff; | |
| 3300 bval += (pixel >> L_BLUE_SHIFT) & 0xff; | |
| 3301 } | |
| 3302 } | |
| 3303 rval = (l_int32)((l_float32)rval * norm); | |
| 3304 gval = (l_int32)((l_float32)gval * norm); | |
| 3305 bval = (l_int32)((l_float32)bval * norm); | |
| 3306 composeRGBPixel(rval, gval, bval, lined + j); | |
| 3307 } | |
| 3308 } | |
| 3309 } | |
| 3310 | |
| 3311 LEPT_FREE(srow); | |
| 3312 LEPT_FREE(scol); | |
| 3313 return 0; | |
| 3314 } | |
| 3315 | |
| 3316 | |
| 3317 /*! | |
| 3318 * \brief scaleRGBToGray2Low() | |
| 3319 * | |
| 3320 * <pre> | |
| 3321 * Notes: | |
| 3322 * (1) This function is called with 32 bpp RGB src and 8 bpp, | |
| 3323 * half-resolution dest. The weights should add to 1.0. | |
| 3324 * </pre> | |
| 3325 */ | |
| 3326 static void | |
| 3327 scaleRGBToGray2Low(l_uint32 *datad, | |
| 3328 l_int32 wd, | |
| 3329 l_int32 hd, | |
| 3330 l_int32 wpld, | |
| 3331 l_uint32 *datas, | |
| 3332 l_int32 wpls, | |
| 3333 l_float32 rwt, | |
| 3334 l_float32 gwt, | |
| 3335 l_float32 bwt) | |
| 3336 { | |
| 3337 l_int32 i, j, val, rval, gval, bval; | |
| 3338 l_uint32 *lines, *lined; | |
| 3339 l_uint32 pixel; | |
| 3340 | |
| 3341 rwt *= 0.25; | |
| 3342 gwt *= 0.25; | |
| 3343 bwt *= 0.25; | |
| 3344 for (i = 0; i < hd; i++) { | |
| 3345 lines = datas + 2 * i * wpls; | |
| 3346 lined = datad + i * wpld; | |
| 3347 for (j = 0; j < wd; j++) { | |
| 3348 /* Sum each of the color components from 4 src pixels */ | |
| 3349 pixel = *(lines + 2 * j); | |
| 3350 rval = (pixel >> L_RED_SHIFT) & 0xff; | |
| 3351 gval = (pixel >> L_GREEN_SHIFT) & 0xff; | |
| 3352 bval = (pixel >> L_BLUE_SHIFT) & 0xff; | |
| 3353 pixel = *(lines + 2 * j + 1); | |
| 3354 rval += (pixel >> L_RED_SHIFT) & 0xff; | |
| 3355 gval += (pixel >> L_GREEN_SHIFT) & 0xff; | |
| 3356 bval += (pixel >> L_BLUE_SHIFT) & 0xff; | |
| 3357 pixel = *(lines + wpls + 2 * j); | |
| 3358 rval += (pixel >> L_RED_SHIFT) & 0xff; | |
| 3359 gval += (pixel >> L_GREEN_SHIFT) & 0xff; | |
| 3360 bval += (pixel >> L_BLUE_SHIFT) & 0xff; | |
| 3361 pixel = *(lines + wpls + 2 * j + 1); | |
| 3362 rval += (pixel >> L_RED_SHIFT) & 0xff; | |
| 3363 gval += (pixel >> L_GREEN_SHIFT) & 0xff; | |
| 3364 bval += (pixel >> L_BLUE_SHIFT) & 0xff; | |
| 3365 /* Generate the dest byte as a weighted sum of the averages */ | |
| 3366 val = (l_int32)(rwt * rval + gwt * gval + bwt * bval); | |
| 3367 SET_DATA_BYTE(lined, j, val); | |
| 3368 } | |
| 3369 } | |
| 3370 } | |
| 3371 | |
| 3372 | |
| 3373 /*------------------------------------------------------------------* | |
| 3374 * General area mapped gray scaling * | |
| 3375 *------------------------------------------------------------------*/ | |
| 3376 /*! | |
| 3377 * \brief scaleColorAreaMapLow() | |
| 3378 * | |
| 3379 * <pre> | |
| 3380 * Notes: | |
| 3381 * (1) This should only be used for downscaling. | |
| 3382 * We choose to divide each pixel into 16 x 16 sub-pixels. | |
| 3383 * This is much slower than scaleSmoothLow(), but it gives a | |
| 3384 * better representation, esp. for downscaling factors between | |
| 3385 * 1.5 and 5. All src pixels are subdivided into 256 sub-pixels, | |
| 3386 * and are weighted by the number of sub-pixels covered by | |
| 3387 * the dest pixel. This is about 2x slower than scaleSmoothLow(), | |
| 3388 * but the results are significantly better on small text. | |
| 3389 * </pre> | |
| 3390 */ | |
| 3391 static void | |
| 3392 scaleColorAreaMapLow(l_uint32 *datad, | |
| 3393 l_int32 wd, | |
| 3394 l_int32 hd, | |
| 3395 l_int32 wpld, | |
| 3396 l_uint32 *datas, | |
| 3397 l_int32 ws, | |
| 3398 l_int32 hs, | |
| 3399 l_int32 wpls) | |
| 3400 { | |
| 3401 l_int32 i, j, k, m, wm2, hm2; | |
| 3402 l_int32 area00, area10, area01, area11, areal, arear, areat, areab; | |
| 3403 l_int32 xu, yu; /* UL corner in src image, to 1/16 of a pixel */ | |
| 3404 l_int32 xl, yl; /* LR corner in src image, to 1/16 of a pixel */ | |
| 3405 l_int32 xup, yup, xuf, yuf; /* UL src pixel: integer and fraction */ | |
| 3406 l_int32 xlp, ylp, xlf, ylf; /* LR src pixel: integer and fraction */ | |
| 3407 l_int32 delx, dely, area; | |
| 3408 l_int32 v00r, v00g, v00b; /* contrib. from UL src pixel */ | |
| 3409 l_int32 v01r, v01g, v01b; /* contrib. from LL src pixel */ | |
| 3410 l_int32 v10r, v10g, v10b; /* contrib from UR src pixel */ | |
| 3411 l_int32 v11r, v11g, v11b; /* contrib from LR src pixel */ | |
| 3412 l_int32 vinr, ving, vinb; /* contrib from all full interior src pixels */ | |
| 3413 l_int32 vmidr, vmidg, vmidb; /* contrib from side parts */ | |
| 3414 l_int32 rval, gval, bval; | |
| 3415 l_uint32 pixel00, pixel10, pixel01, pixel11, pixel; | |
| 3416 l_uint32 *lines, *lined; | |
| 3417 l_float32 scx, scy; | |
| 3418 | |
| 3419 /* (scx, scy) are scaling factors that are applied to the | |
| 3420 * dest coords to get the corresponding src coords. | |
| 3421 * We need them because we iterate over dest pixels | |
| 3422 * and must find the corresponding set of src pixels. */ | |
| 3423 scx = 16.f * (l_float32)ws / (l_float32)wd; | |
| 3424 scy = 16.f * (l_float32)hs / (l_float32)hd; | |
| 3425 wm2 = ws - 2; | |
| 3426 hm2 = hs - 2; | |
| 3427 | |
| 3428 /* Iterate over the destination pixels */ | |
| 3429 for (i = 0; i < hd; i++) { | |
| 3430 yu = (l_int32)(scy * i); | |
| 3431 yl = (l_int32)(scy * (i + 1.0)); | |
| 3432 yup = yu >> 4; | |
| 3433 yuf = yu & 0x0f; | |
| 3434 ylp = yl >> 4; | |
| 3435 ylf = yl & 0x0f; | |
| 3436 dely = ylp - yup; | |
| 3437 lined = datad + i * wpld; | |
| 3438 lines = datas + yup * wpls; | |
| 3439 for (j = 0; j < wd; j++) { | |
| 3440 xu = (l_int32)(scx * j); | |
| 3441 xl = (l_int32)(scx * (j + 1.0)); | |
| 3442 xup = xu >> 4; | |
| 3443 xuf = xu & 0x0f; | |
| 3444 xlp = xl >> 4; | |
| 3445 xlf = xl & 0x0f; | |
| 3446 delx = xlp - xup; | |
| 3447 | |
| 3448 /* If near the edge, just use a src pixel value */ | |
| 3449 if (xlp > wm2 || ylp > hm2) { | |
| 3450 *(lined + j) = *(lines + xup); | |
| 3451 continue; | |
| 3452 } | |
| 3453 | |
| 3454 /* Area summed over, in subpixels. This varies | |
| 3455 * due to the quantization, so we can't simply take | |
| 3456 * the area to be a constant: area = scx * scy. */ | |
| 3457 area = ((16 - xuf) + 16 * (delx - 1) + xlf) * | |
| 3458 ((16 - yuf) + 16 * (dely - 1) + ylf); | |
| 3459 | |
| 3460 /* Do area map summation */ | |
| 3461 pixel00 = *(lines + xup); | |
| 3462 pixel10 = *(lines + xlp); | |
| 3463 pixel01 = *(lines + dely * wpls + xup); | |
| 3464 pixel11 = *(lines + dely * wpls + xlp); | |
| 3465 area00 = (16 - xuf) * (16 - yuf); | |
| 3466 area10 = xlf * (16 - yuf); | |
| 3467 area01 = (16 - xuf) * ylf; | |
| 3468 area11 = xlf * ylf; | |
| 3469 v00r = area00 * ((pixel00 >> L_RED_SHIFT) & 0xff); | |
| 3470 v00g = area00 * ((pixel00 >> L_GREEN_SHIFT) & 0xff); | |
| 3471 v00b = area00 * ((pixel00 >> L_BLUE_SHIFT) & 0xff); | |
| 3472 v10r = area10 * ((pixel10 >> L_RED_SHIFT) & 0xff); | |
| 3473 v10g = area10 * ((pixel10 >> L_GREEN_SHIFT) & 0xff); | |
| 3474 v10b = area10 * ((pixel10 >> L_BLUE_SHIFT) & 0xff); | |
| 3475 v01r = area01 * ((pixel01 >> L_RED_SHIFT) & 0xff); | |
| 3476 v01g = area01 * ((pixel01 >> L_GREEN_SHIFT) & 0xff); | |
| 3477 v01b = area01 * ((pixel01 >> L_BLUE_SHIFT) & 0xff); | |
| 3478 v11r = area11 * ((pixel11 >> L_RED_SHIFT) & 0xff); | |
| 3479 v11g = area11 * ((pixel11 >> L_GREEN_SHIFT) & 0xff); | |
| 3480 v11b = area11 * ((pixel11 >> L_BLUE_SHIFT) & 0xff); | |
| 3481 vinr = ving = vinb = 0; | |
| 3482 for (k = 1; k < dely; k++) { /* for full src pixels */ | |
| 3483 for (m = 1; m < delx; m++) { | |
| 3484 pixel = *(lines + k * wpls + xup + m); | |
| 3485 vinr += 256 * ((pixel >> L_RED_SHIFT) & 0xff); | |
| 3486 ving += 256 * ((pixel >> L_GREEN_SHIFT) & 0xff); | |
| 3487 vinb += 256 * ((pixel >> L_BLUE_SHIFT) & 0xff); | |
| 3488 } | |
| 3489 } | |
| 3490 vmidr = vmidg = vmidb = 0; | |
| 3491 areal = (16 - xuf) * 16; | |
| 3492 arear = xlf * 16; | |
| 3493 areat = 16 * (16 - yuf); | |
| 3494 areab = 16 * ylf; | |
| 3495 for (k = 1; k < dely; k++) { /* for left side */ | |
| 3496 pixel = *(lines + k * wpls + xup); | |
| 3497 vmidr += areal * ((pixel >> L_RED_SHIFT) & 0xff); | |
| 3498 vmidg += areal * ((pixel >> L_GREEN_SHIFT) & 0xff); | |
| 3499 vmidb += areal * ((pixel >> L_BLUE_SHIFT) & 0xff); | |
| 3500 } | |
| 3501 for (k = 1; k < dely; k++) { /* for right side */ | |
| 3502 pixel = *(lines + k * wpls + xlp); | |
| 3503 vmidr += arear * ((pixel >> L_RED_SHIFT) & 0xff); | |
| 3504 vmidg += arear * ((pixel >> L_GREEN_SHIFT) & 0xff); | |
| 3505 vmidb += arear * ((pixel >> L_BLUE_SHIFT) & 0xff); | |
| 3506 } | |
| 3507 for (m = 1; m < delx; m++) { /* for top side */ | |
| 3508 pixel = *(lines + xup + m); | |
| 3509 vmidr += areat * ((pixel >> L_RED_SHIFT) & 0xff); | |
| 3510 vmidg += areat * ((pixel >> L_GREEN_SHIFT) & 0xff); | |
| 3511 vmidb += areat * ((pixel >> L_BLUE_SHIFT) & 0xff); | |
| 3512 } | |
| 3513 for (m = 1; m < delx; m++) { /* for bottom side */ | |
| 3514 pixel = *(lines + dely * wpls + xup + m); | |
| 3515 vmidr += areab * ((pixel >> L_RED_SHIFT) & 0xff); | |
| 3516 vmidg += areab * ((pixel >> L_GREEN_SHIFT) & 0xff); | |
| 3517 vmidb += areab * ((pixel >> L_BLUE_SHIFT) & 0xff); | |
| 3518 } | |
| 3519 | |
| 3520 /* Sum all the contributions */ | |
| 3521 rval = (v00r + v01r + v10r + v11r + vinr + vmidr + 128) / area; | |
| 3522 gval = (v00g + v01g + v10g + v11g + ving + vmidg + 128) / area; | |
| 3523 bval = (v00b + v01b + v10b + v11b + vinb + vmidb + 128) / area; | |
| 3524 #if DEBUG_OVERFLOW | |
| 3525 if (rval > 255) lept_stderr("rval ovfl: %d\n", rval); | |
| 3526 if (gval > 255) lept_stderr("gval ovfl: %d\n", gval); | |
| 3527 if (bval > 255) lept_stderr("bval ovfl: %d\n", bval); | |
| 3528 #endif /* DEBUG_OVERFLOW */ | |
| 3529 composeRGBPixel(rval, gval, bval, lined + j); | |
| 3530 } | |
| 3531 } | |
| 3532 } | |
| 3533 | |
| 3534 | |
| 3535 /*! | |
| 3536 * \brief scaleGrayAreaMapLow() | |
| 3537 * | |
| 3538 * <pre> | |
| 3539 * Notes: | |
| 3540 * (1) This should only be used for downscaling. | |
| 3541 * We choose to divide each pixel into 16 x 16 sub-pixels. | |
| 3542 * This is about 2x slower than scaleSmoothLow(), but the results | |
| 3543 * are significantly better on small text, esp. for downscaling | |
| 3544 * factors between 1.5 and 5. All src pixels are subdivided | |
| 3545 * into 256 sub-pixels, and are weighted by the number of | |
| 3546 * sub-pixels covered by the dest pixel. | |
| 3547 * </pre> | |
| 3548 */ | |
| 3549 static void | |
| 3550 scaleGrayAreaMapLow(l_uint32 *datad, | |
| 3551 l_int32 wd, | |
| 3552 l_int32 hd, | |
| 3553 l_int32 wpld, | |
| 3554 l_uint32 *datas, | |
| 3555 l_int32 ws, | |
| 3556 l_int32 hs, | |
| 3557 l_int32 wpls) | |
| 3558 { | |
| 3559 l_int32 i, j, k, m, wm2, hm2; | |
| 3560 l_int32 xu, yu; /* UL corner in src image, to 1/16 of a pixel */ | |
| 3561 l_int32 xl, yl; /* LR corner in src image, to 1/16 of a pixel */ | |
| 3562 l_int32 xup, yup, xuf, yuf; /* UL src pixel: integer and fraction */ | |
| 3563 l_int32 xlp, ylp, xlf, ylf; /* LR src pixel: integer and fraction */ | |
| 3564 l_int32 delx, dely, area; | |
| 3565 l_int32 v00; /* contrib. from UL src pixel */ | |
| 3566 l_int32 v01; /* contrib. from LL src pixel */ | |
| 3567 l_int32 v10; /* contrib from UR src pixel */ | |
| 3568 l_int32 v11; /* contrib from LR src pixel */ | |
| 3569 l_int32 vin; /* contrib from all full interior src pixels */ | |
| 3570 l_int32 vmid; /* contrib from side parts that are full in 1 direction */ | |
| 3571 l_int32 val; | |
| 3572 l_uint32 *lines, *lined; | |
| 3573 l_float32 scx, scy; | |
| 3574 | |
| 3575 /* (scx, scy) are scaling factors that are applied to the | |
| 3576 * dest coords to get the corresponding src coords. | |
| 3577 * We need them because we iterate over dest pixels | |
| 3578 * and must find the corresponding set of src pixels. */ | |
| 3579 scx = 16.f * (l_float32)ws / (l_float32)wd; | |
| 3580 scy = 16.f * (l_float32)hs / (l_float32)hd; | |
| 3581 wm2 = ws - 2; | |
| 3582 hm2 = hs - 2; | |
| 3583 | |
| 3584 /* Iterate over the destination pixels */ | |
| 3585 for (i = 0; i < hd; i++) { | |
| 3586 yu = (l_int32)(scy * i); | |
| 3587 yl = (l_int32)(scy * (i + 1.0)); | |
| 3588 yup = yu >> 4; | |
| 3589 yuf = yu & 0x0f; | |
| 3590 ylp = yl >> 4; | |
| 3591 ylf = yl & 0x0f; | |
| 3592 dely = ylp - yup; | |
| 3593 lined = datad + i * wpld; | |
| 3594 lines = datas + yup * wpls; | |
| 3595 for (j = 0; j < wd; j++) { | |
| 3596 xu = (l_int32)(scx * j); | |
| 3597 xl = (l_int32)(scx * (j + 1.0)); | |
| 3598 xup = xu >> 4; | |
| 3599 xuf = xu & 0x0f; | |
| 3600 xlp = xl >> 4; | |
| 3601 xlf = xl & 0x0f; | |
| 3602 delx = xlp - xup; | |
| 3603 | |
| 3604 /* If near the edge, just use a src pixel value */ | |
| 3605 if (xlp > wm2 || ylp > hm2) { | |
| 3606 SET_DATA_BYTE(lined, j, GET_DATA_BYTE(lines, xup)); | |
| 3607 continue; | |
| 3608 } | |
| 3609 | |
| 3610 /* Area summed over, in subpixels. This varies | |
| 3611 * due to the quantization, so we can't simply take | |
| 3612 * the area to be a constant: area = scx * scy. */ | |
| 3613 area = ((16 - xuf) + 16 * (delx - 1) + xlf) * | |
| 3614 ((16 - yuf) + 16 * (dely - 1) + ylf); | |
| 3615 | |
| 3616 /* Do area map summation */ | |
| 3617 v00 = (16 - xuf) * (16 - yuf) * GET_DATA_BYTE(lines, xup); | |
| 3618 v10 = xlf * (16 - yuf) * GET_DATA_BYTE(lines, xlp); | |
| 3619 v01 = (16 - xuf) * ylf * GET_DATA_BYTE(lines + dely * wpls, xup); | |
| 3620 v11 = xlf * ylf * GET_DATA_BYTE(lines + dely * wpls, xlp); | |
| 3621 for (vin = 0, k = 1; k < dely; k++) { /* for full src pixels */ | |
| 3622 for (m = 1; m < delx; m++) { | |
| 3623 vin += 256 * GET_DATA_BYTE(lines + k * wpls, xup + m); | |
| 3624 } | |
| 3625 } | |
| 3626 for (vmid = 0, k = 1; k < dely; k++) /* for left side */ | |
| 3627 vmid += (16 - xuf) * 16 * GET_DATA_BYTE(lines + k * wpls, xup); | |
| 3628 for (k = 1; k < dely; k++) /* for right side */ | |
| 3629 vmid += xlf * 16 * GET_DATA_BYTE(lines + k * wpls, xlp); | |
| 3630 for (m = 1; m < delx; m++) /* for top side */ | |
| 3631 vmid += 16 * (16 - yuf) * GET_DATA_BYTE(lines, xup + m); | |
| 3632 for (m = 1; m < delx; m++) /* for bottom side */ | |
| 3633 vmid += 16 * ylf * GET_DATA_BYTE(lines + dely * wpls, xup + m); | |
| 3634 val = (v00 + v01 + v10 + v11 + vin + vmid + 128) / area; | |
| 3635 #if DEBUG_OVERFLOW | |
| 3636 if (val > 255) lept_stderr("val overflow: %d\n", val); | |
| 3637 #endif /* DEBUG_OVERFLOW */ | |
| 3638 SET_DATA_BYTE(lined, j, val); | |
| 3639 } | |
| 3640 } | |
| 3641 } | |
| 3642 | |
| 3643 | |
| 3644 /*------------------------------------------------------------------* | |
| 3645 * 2x area mapped downscaling * | |
| 3646 *------------------------------------------------------------------*/ | |
| 3647 /*! | |
| 3648 * \brief scaleAreaMapLow2() | |
| 3649 * | |
| 3650 * <pre> | |
| 3651 * Notes: | |
| 3652 * (1) This function is called with either 8 bpp gray or 32 bpp RGB. | |
| 3653 * The result is a 2x reduced dest. | |
| 3654 * </pre> | |
| 3655 */ | |
| 3656 static void | |
| 3657 scaleAreaMapLow2(l_uint32 *datad, | |
| 3658 l_int32 wd, | |
| 3659 l_int32 hd, | |
| 3660 l_int32 wpld, | |
| 3661 l_uint32 *datas, | |
| 3662 l_int32 d, | |
| 3663 l_int32 wpls) | |
| 3664 { | |
| 3665 l_int32 i, j, val, rval, gval, bval; | |
| 3666 l_uint32 *lines, *lined; | |
| 3667 l_uint32 pixel; | |
| 3668 | |
| 3669 if (d == 8) { | |
| 3670 for (i = 0; i < hd; i++) { | |
| 3671 lines = datas + 2 * i * wpls; | |
| 3672 lined = datad + i * wpld; | |
| 3673 for (j = 0; j < wd; j++) { | |
| 3674 /* Average each dest pixel using 4 src pixels */ | |
| 3675 val = GET_DATA_BYTE(lines, 2 * j); | |
| 3676 val += GET_DATA_BYTE(lines, 2 * j + 1); | |
| 3677 val += GET_DATA_BYTE(lines + wpls, 2 * j); | |
| 3678 val += GET_DATA_BYTE(lines + wpls, 2 * j + 1); | |
| 3679 val >>= 2; | |
| 3680 SET_DATA_BYTE(lined, j, val); | |
| 3681 } | |
| 3682 } | |
| 3683 } else { /* d == 32 */ | |
| 3684 for (i = 0; i < hd; i++) { | |
| 3685 lines = datas + 2 * i * wpls; | |
| 3686 lined = datad + i * wpld; | |
| 3687 for (j = 0; j < wd; j++) { | |
| 3688 /* Average each of the color components from 4 src pixels */ | |
| 3689 pixel = *(lines + 2 * j); | |
| 3690 rval = (pixel >> L_RED_SHIFT) & 0xff; | |
| 3691 gval = (pixel >> L_GREEN_SHIFT) & 0xff; | |
| 3692 bval = (pixel >> L_BLUE_SHIFT) & 0xff; | |
| 3693 pixel = *(lines + 2 * j + 1); | |
| 3694 rval += (pixel >> L_RED_SHIFT) & 0xff; | |
| 3695 gval += (pixel >> L_GREEN_SHIFT) & 0xff; | |
| 3696 bval += (pixel >> L_BLUE_SHIFT) & 0xff; | |
| 3697 pixel = *(lines + wpls + 2 * j); | |
| 3698 rval += (pixel >> L_RED_SHIFT) & 0xff; | |
| 3699 gval += (pixel >> L_GREEN_SHIFT) & 0xff; | |
| 3700 bval += (pixel >> L_BLUE_SHIFT) & 0xff; | |
| 3701 pixel = *(lines + wpls + 2 * j + 1); | |
| 3702 rval += (pixel >> L_RED_SHIFT) & 0xff; | |
| 3703 gval += (pixel >> L_GREEN_SHIFT) & 0xff; | |
| 3704 bval += (pixel >> L_BLUE_SHIFT) & 0xff; | |
| 3705 composeRGBPixel(rval >> 2, gval >> 2, bval >> 2, &pixel); | |
| 3706 *(lined + j) = pixel; | |
| 3707 } | |
| 3708 } | |
| 3709 } | |
| 3710 } | |
| 3711 | |
| 3712 | |
| 3713 /*------------------------------------------------------------------* | |
| 3714 * Binary scaling by closest pixel sampling * | |
| 3715 *------------------------------------------------------------------*/ | |
| 3716 /* | |
| 3717 * \brief scaleBinaryLow() | |
| 3718 * | |
| 3719 * <pre> | |
| 3720 * Notes: | |
| 3721 * (1) The dest must be cleared prior to this operation, | |
| 3722 * and we clear it here in the low-level code. | |
| 3723 * (2) We reuse dest pixels and dest pixel rows whenever | |
| 3724 * possible for upscaling; downscaling is done by | |
| 3725 * strict subsampling. | |
| 3726 * </pre> | |
| 3727 */ | |
| 3728 static l_int32 | |
| 3729 scaleBinaryLow(l_uint32 *datad, | |
| 3730 l_int32 wd, | |
| 3731 l_int32 hd, | |
| 3732 l_int32 wpld, | |
| 3733 l_uint32 *datas, | |
| 3734 l_int32 ws, | |
| 3735 l_int32 hs, | |
| 3736 l_int32 wpls, | |
| 3737 l_float32 shiftx, | |
| 3738 l_float32 shifty) | |
| 3739 { | |
| 3740 l_int32 i, j; | |
| 3741 l_int32 xs, prevxs, sval; | |
| 3742 l_int32 *srow, *scol; | |
| 3743 l_uint32 *lines, *prevlines, *lined, *prevlined; | |
| 3744 l_float32 wratio, hratio; | |
| 3745 | |
| 3746 /* Clear dest */ | |
| 3747 memset(datad, 0, 4LL * hd * wpld); | |
| 3748 | |
| 3749 /* The source row corresponding to dest row i ==> srow[i] | |
| 3750 * The source col corresponding to dest col j ==> scol[j] */ | |
| 3751 if ((srow = (l_int32 *)LEPT_CALLOC(hd, sizeof(l_int32))) == NULL) | |
| 3752 return ERROR_INT("srow not made", __func__, 1); | |
| 3753 if ((scol = (l_int32 *)LEPT_CALLOC(wd, sizeof(l_int32))) == NULL) { | |
| 3754 LEPT_FREE(srow); | |
| 3755 return ERROR_INT("scol not made", __func__, 1); | |
| 3756 } | |
| 3757 | |
| 3758 wratio = (l_float32)ws / (l_float32)wd; | |
| 3759 hratio = (l_float32)hs / (l_float32)hd; | |
| 3760 for (i = 0; i < hd; i++) | |
| 3761 srow[i] = L_MIN((l_int32)(hratio * i + shifty), hs - 1); | |
| 3762 for (j = 0; j < wd; j++) | |
| 3763 scol[j] = L_MIN((l_int32)(wratio * j + shiftx), ws - 1); | |
| 3764 | |
| 3765 prevlines = NULL; | |
| 3766 prevxs = -1; | |
| 3767 sval = 0; | |
| 3768 for (i = 0; i < hd; i++) { | |
| 3769 lines = datas + srow[i] * wpls; | |
| 3770 lined = datad + i * wpld; | |
| 3771 if (lines != prevlines) { /* make dest from new source row */ | |
| 3772 for (j = 0; j < wd; j++) { | |
| 3773 xs = scol[j]; | |
| 3774 if (xs != prevxs) { /* get dest pix from source col */ | |
| 3775 if ((sval = GET_DATA_BIT(lines, xs))) | |
| 3776 SET_DATA_BIT(lined, j); | |
| 3777 prevxs = xs; | |
| 3778 } else { /* copy prev dest pix, if set */ | |
| 3779 if (sval) | |
| 3780 SET_DATA_BIT(lined, j); | |
| 3781 } | |
| 3782 } | |
| 3783 } else { /* lines == prevlines; copy prev dest row */ | |
| 3784 prevlined = lined - wpld; | |
| 3785 memcpy(lined, prevlined, 4 * wpld); | |
| 3786 } | |
| 3787 prevlines = lines; | |
| 3788 } | |
| 3789 | |
| 3790 LEPT_FREE(srow); | |
| 3791 LEPT_FREE(scol); | |
| 3792 return 0; | |
| 3793 } |
