comparison mupdf-source/thirdparty/leptonica/src/rop.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 rop.c
29 * <pre>
30 * General rasterop
31 * l_int32 pixRasterop()
32 *
33 * In-place full band translation
34 * l_int32 pixRasteropVip()
35 * l_int32 pixRasteropHip()
36 *
37 * Full image translation (general and in-place)
38 * l_int32 pixTranslate()
39 * l_int32 pixRasteropIP()
40 *
41 * Full image rasterop with no translation
42 * l_int32 pixRasteropFullImage()
43 *
44 * Checking for invalid crop box
45 * static l_int32 checkRasteropCrop()
46 * </pre>
47 */
48
49 #ifdef HAVE_CONFIG_H
50 #include <config_auto.h>
51 #endif /* HAVE_CONFIG_H */
52
53 #include <string.h>
54 #include "allheaders.h"
55
56 static l_int32 checkRasteropCrop(l_int32 pixw, l_int32 pixh, l_int32 dx,
57 l_int32 dy, l_int32 dw, l_int32 dh);
58
59
60 /*--------------------------------------------------------------------*
61 * General rasterop (basic pix interface) *
62 *--------------------------------------------------------------------*/
63 /*!
64 * \brief pixRasterop()
65 *
66 * \param[in] pixd dest pix
67 * \param[in] dx x val of UL corner of dest rectangle
68 * \param[in] dy y val of UL corner of dest rectangle
69 * \param[in] dw width of dest rectangle
70 * \param[in] dh height of dest rectangle
71 * \param[in] op op code
72 * \param[in] pixs src pix
73 * \param[in] sx x val of UL corner of src rectangle
74 * \param[in] sy y val of UL corner of src rectangle
75 * \return 0 if OK; 1 on error.
76 *
77 * <pre>
78 * Notes:
79 * (1) This has the standard set of 9 args for rasterop.
80 * This function is your friend; it is worth memorizing!
81 * (2) If the operation involves only dest, this calls
82 * rasteropUniLow(). Otherwise, checks depth of the
83 * src and dest, and if they match, calls rasteropLow().
84 * (3) For the two-image operation, where both pixs and pixd
85 * are defined, they are typically different images. However
86 * there are cases, such as pixSetMirroredBorder(), where
87 * in-place operations can be done, blitting pixels from
88 * one part of pixd to another. Consequently, we permit
89 * such operations. If you use them, be sure that there
90 * is no overlap between the source and destination rectangles
91 * in pixd (!)
92 *
93 * Background:
94 * -----------
95 *
96 * There are 18 operations, described by the op codes in pix.h.
97 *
98 * One, PIX_DST, is a no-op.
99 *
100 * Three, PIX_CLR, PIX_SET, and PIX_NOT(PIX_DST) operate only on the dest.
101 * These are handled by the low-level rasteropUniLow().
102 *
103 * The other 14 involve both the src and the dest, and depend on
104 * the bit values of either just the src or the bit values of both
105 * src and dest. They are handled by rasteropLow():
106 *
107 * PIX_SRC s
108 * PIX_NOT(PIX_SRC) ~s
109 * PIX_SRC | PIX_DST s | d
110 * PIX_SRC & PIX_DST s & d
111 * PIX_SRC ^ PIX_DST s ^ d
112 * PIX_NOT(PIX_SRC) | PIX_DST ~s | d
113 * PIX_NOT(PIX_SRC) & PIX_DST ~s & d
114 * PIX_NOT(PIX_SRC) ^ PIX_DST ~s ^ d
115 * PIX_SRC | PIX_NOT(PIX_DST) s | ~d
116 * PIX_SRC & PIX_NOT(PIX_DST) s & ~d
117 * PIX_SRC ^ PIX_NOT(PIX_DST) s ^ ~d
118 * PIX_NOT(PIX_SRC | PIX_DST) ~(s | d)
119 * PIX_NOT(PIX_SRC & PIX_DST) ~(s & d)
120 * PIX_NOT(PIX_SRC ^ PIX_DST) ~(s ^ d)
121 *
122 * Each of these is implemented with one of three low-level
123 * functions, depending on the alignment of the left edge
124 * of the src and dest rectangles:
125 * * a fastest implementation if both left edges are
126 * (32-bit) word aligned
127 * * a very slightly slower implementation if both left
128 * edges have the same relative (32-bit) word alignment
129 * * the general routine that is invoked when
130 * both left edges have different word alignment
131 *
132 * Of the 14 binary rasterops above, only 12 are unique
133 * logical combinations (out of a possible 16) of src
134 * and dst bits:
135 *
136 * (sd) (11) (10) (01) (00)
137 * -----------------------------------------------
138 * s 1 1 0 0
139 * ~s 0 1 0 1
140 * s | d 1 1 1 0
141 * s & d 1 0 0 0
142 * s ^ d 0 1 1 0
143 * ~s | d 1 0 1 1
144 * ~s & d 0 0 1 0
145 * ~s ^ d 1 0 0 1
146 * s | ~d 1 1 0 1
147 * s & ~d 0 1 0 0
148 * s ^ ~d 1 0 0 1
149 * ~(s | d) 0 0 0 1
150 * ~(s & d) 0 1 1 1
151 * ~(s ^ d) 1 0 0 1
152 *
153 * Note that the following three operations are equivalent:
154 * ~(s ^ d)
155 * ~s ^ d
156 * s ^ ~d
157 * and in the implementation, we call them out with the first form;
158 * namely, ~(s ^ d).
159 *
160 * Of the 16 possible binary combinations of src and dest bits,
161 * the remaining 4 unique ones are independent of the src bit.
162 * They depend on either just the dest bit or on neither
163 * the src nor dest bits:
164 *
165 * d 1 0 1 0 (indep. of s)
166 * ~d 0 1 0 1 (indep. of s)
167 * CLR 0 0 0 0 (indep. of both s & d)
168 * SET 1 1 1 1 (indep. of both s & d)
169 *
170 * As mentioned above, three of these are implemented by
171 * rasteropUniLow(), and one is a no-op.
172 *
173 * How can these operation codes be represented by bits
174 * in such a way that when the basic operations are performed
175 * on the bits the results are unique for unique
176 * operations, and mimic the logic table given above?
177 *
178 * The answer is to choose a particular order of the pairings:
179 * (sd) (11) (10) (01) (00)
180 * (which happens to be the same as in the above table)
181 * and to translate the result into 4-bit representations
182 * of s and d. For example, the Sun rasterop choice
183 * (omitting the extra bit for clipping) is
184 *
185 * PIX_SRC 0xc
186 * PIX_DST 0xa
187 *
188 * This corresponds to our pairing order given above:
189 * (sd) (11) (10) (01) (00)
190 * where for s = 1 we get the bit pattern
191 * PIX_SRC: 1 1 0 0 (0xc)
192 * and for d = 1 we get the pattern
193 * PIX_DST: 1 0 1 0 (0xa)
194 *
195 * OK, that's the pairing order that Sun chose. How many different
196 * ways can we assign bit patterns to PIX_SRC and PIX_DST to get
197 * the boolean ops to work out? Any of the 4 pairs can be put
198 * in the first position, any of the remaining 3 pairs can go
199 * in the second; and one of the remaining 2 pairs can go the the third.
200 * There is a total of 4*3*2 = 24 ways these pairs can be permuted.
201 * </pre>
202 */
203 l_ok
204 pixRasterop(PIX *pixd,
205 l_int32 dx,
206 l_int32 dy,
207 l_int32 dw,
208 l_int32 dh,
209 l_int32 op,
210 PIX *pixs,
211 l_int32 sx,
212 l_int32 sy)
213 {
214 l_int32 dpw, dph, dpd, spw, sph, spd;
215
216 if (!pixd)
217 return ERROR_INT("pixd not defined", __func__, 1);
218
219 if (op == PIX_DST) /* no-op */
220 return 0;
221
222 pixGetDimensions(pixd, &dpw, &dph, &dpd);
223 #if 0
224 if (checkRasteropCrop(dpw, dph, dx, dy, dw, dh)) {
225 L_WARNING("dest crop box out of bounds\n", __func__);
226 return 1;
227 }
228 #endif
229
230 /* Check if operation is only on dest */
231 if (op == PIX_CLR || op == PIX_SET || op == PIX_NOT(PIX_DST)) {
232 rasteropUniLow(pixGetData(pixd), dpw, dph, dpd, pixGetWpl(pixd),
233 dx, dy, dw, dh, op);
234 return 0;
235 }
236
237 /* Two-image rasterop; the depths must match */
238 if (!pixs)
239 return ERROR_INT("pixs not defined", __func__, 1);
240 pixGetDimensions(pixs, &spw, &sph, &spd);
241 if (dpd != spd)
242 return ERROR_INT("depths of pixs and pixd differ", __func__, 1);
243 #if 0
244 if (checkRasteropCrop(spw, sph, sx, sy, dw, dh)) {
245 L_WARNING("source crop box out of bounds\n", __func__);
246 return 1;
247 }
248 #endif
249
250 rasteropLow(pixGetData(pixd), dpw, dph, dpd, pixGetWpl(pixd),
251 dx, dy, dw, dh, op,
252 pixGetData(pixs), spw, sph, pixGetWpl(pixs), sx, sy);
253 return 0;
254 }
255
256
257 /*--------------------------------------------------------------------*
258 * In-place full band translation *
259 *--------------------------------------------------------------------*/
260 /*!
261 * \brief pixRasteropVip()
262 *
263 * \param[in] pixd in-place
264 * \param[in] bx left edge of vertical band
265 * \param[in] bw width of vertical band
266 * \param[in] vshift vertical shift of band; vshift > 0 is down
267 * \param[in] incolor L_BRING_IN_WHITE, L_BRING_IN_BLACK
268 * \return 0 if OK; 1 on error
269 *
270 * <pre>
271 * Notes:
272 * (1) This rasterop translates a vertical band of the
273 * image either up or down, bringing in either white
274 * or black pixels from outside the image.
275 * (2) The vertical band extends the full height of pixd.
276 * (3) If a colormap exists, the nearest color to white or black
277 * is brought in.
278 * </pre>
279 */
280 l_ok
281 pixRasteropVip(PIX *pixd,
282 l_int32 bx,
283 l_int32 bw,
284 l_int32 vshift,
285 l_int32 incolor)
286 {
287 l_int32 w, h, d, index, op;
288 PIX *pixt;
289 PIXCMAP *cmap;
290
291 if (!pixd)
292 return ERROR_INT("pixd not defined", __func__, 1);
293 if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
294 return ERROR_INT("invalid value for incolor", __func__, 1);
295 if (bw <= 0)
296 return ERROR_INT("bw must be > 0", __func__, 1);
297
298 if (vshift == 0)
299 return 0;
300
301 pixGetDimensions(pixd, &w, &h, &d);
302 rasteropVipLow(pixGetData(pixd), w, h, d, pixGetWpl(pixd), bx, bw, vshift);
303
304 cmap = pixGetColormap(pixd);
305 if (!cmap) {
306 if ((d == 1 && incolor == L_BRING_IN_BLACK) ||
307 (d > 1 && incolor == L_BRING_IN_WHITE))
308 op = PIX_SET;
309 else
310 op = PIX_CLR;
311
312 /* Set the pixels brought in at top or bottom */
313 if (vshift > 0)
314 pixRasterop(pixd, bx, 0, bw, vshift, op, NULL, 0, 0);
315 else /* vshift < 0 */
316 pixRasterop(pixd, bx, h + vshift, bw, -vshift, op, NULL, 0, 0);
317 return 0;
318 }
319
320 /* Get the nearest index and fill with that */
321 if (incolor == L_BRING_IN_BLACK)
322 pixcmapGetRankIntensity(cmap, 0.0, &index);
323 else /* white */
324 pixcmapGetRankIntensity(cmap, 1.0, &index);
325 pixt = pixCreate(bw, L_ABS(vshift), d);
326 pixSetAllArbitrary(pixt, index);
327 if (vshift > 0)
328 pixRasterop(pixd, bx, 0, bw, vshift, PIX_SRC, pixt, 0, 0);
329 else /* vshift < 0 */
330 pixRasterop(pixd, bx, h + vshift, bw, -vshift, PIX_SRC, pixt, 0, 0);
331 pixDestroy(&pixt);
332 return 0;
333 }
334
335
336 /*!
337 * \brief pixRasteropHip()
338 *
339 * \param[in] pixd in-place operation
340 * \param[in] by top of horizontal band
341 * \param[in] bh height of horizontal band
342 * \param[in] hshift horizontal shift of band; hshift > 0 is to right
343 * \param[in] incolor L_BRING_IN_WHITE, L_BRING_IN_BLACK
344 * \return 0 if OK; 1 on error
345 *
346 * <pre>
347 * Notes:
348 * (1) This rasterop translates a horizontal band of the
349 * image either left or right, bringing in either white
350 * or black pixels from outside the image.
351 * (2) The horizontal band extends the full width of pixd.
352 * (3) If a colormap exists, the nearest color to white or black
353 * is brought in.
354 * </pre>
355 */
356 l_ok
357 pixRasteropHip(PIX *pixd,
358 l_int32 by,
359 l_int32 bh,
360 l_int32 hshift,
361 l_int32 incolor)
362 {
363 l_int32 w, h, d, index, op;
364 PIX *pixt;
365 PIXCMAP *cmap;
366
367 if (!pixd)
368 return ERROR_INT("pixd not defined", __func__, 1);
369 if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
370 return ERROR_INT("invalid value for incolor", __func__, 1);
371 if (bh <= 0)
372 return ERROR_INT("bh must be > 0", __func__, 1);
373
374 if (hshift == 0)
375 return 0;
376
377 pixGetDimensions(pixd, &w, &h, &d);
378 rasteropHipLow(pixGetData(pixd), h, d, pixGetWpl(pixd), by, bh, hshift);
379
380 cmap = pixGetColormap(pixd);
381 if (!cmap) {
382 if ((d == 1 && incolor == L_BRING_IN_BLACK) ||
383 (d > 1 && incolor == L_BRING_IN_WHITE))
384 op = PIX_SET;
385 else
386 op = PIX_CLR;
387
388 /* Set the pixels brought in at left or right */
389 if (hshift > 0)
390 pixRasterop(pixd, 0, by, hshift, bh, op, NULL, 0, 0);
391 else /* hshift < 0 */
392 pixRasterop(pixd, w + hshift, by, -hshift, bh, op, NULL, 0, 0);
393 return 0;
394 }
395
396 /* Get the nearest index and fill with that */
397 if (incolor == L_BRING_IN_BLACK)
398 pixcmapGetRankIntensity(cmap, 0.0, &index);
399 else /* white */
400 pixcmapGetRankIntensity(cmap, 1.0, &index);
401 pixt = pixCreate(L_ABS(hshift), bh, d);
402 pixSetAllArbitrary(pixt, index);
403 if (hshift > 0)
404 pixRasterop(pixd, 0, by, hshift, bh, PIX_SRC, pixt, 0, 0);
405 else /* hshift < 0 */
406 pixRasterop(pixd, w + hshift, by, -hshift, bh, PIX_SRC, pixt, 0, 0);
407 pixDestroy(&pixt);
408 return 0;
409 }
410
411
412 /*--------------------------------------------------------------------*
413 * Full image translation (general and in-place) *
414 *--------------------------------------------------------------------*/
415 /*!
416 * \brief pixTranslate()
417 *
418 * \param[in] pixd [optional] destination: this can be null,
419 * equal to pixs, or different from pixs
420 * \param[in] pixs
421 * \param[in] hshift horizontal shift; hshift > 0 is to right
422 * \param[in] vshift vertical shift; vshift > 0 is down
423 * \param[in] incolor L_BRING_IN_WHITE, L_BRING_IN_BLACK
424 * \return pixd, or NULL on error.
425 *
426 * <pre>
427 * Notes:
428 * (1) The general pattern is:
429 * pixd = pixTranslate(pixd, pixs, ...);
430 * For clarity, when you know the case, use one of these:
431 * pixd = pixTranslate(NULL, pixs, ...); // new
432 * pixTranslate(pixs, pixs, ...); // in-place
433 * pixTranslate(pixd, pixs, ...); // to existing pixd
434 * (2) If an existing pixd is not the same size as pixs, the
435 * image data will be reallocated.
436 * </pre>
437 */
438 PIX *
439 pixTranslate(PIX *pixd,
440 PIX *pixs,
441 l_int32 hshift,
442 l_int32 vshift,
443 l_int32 incolor)
444 {
445 if (!pixs)
446 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
447
448 /* Prepare pixd for in-place operation */
449 if ((pixd = pixCopy(pixd, pixs)) == NULL)
450 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
451
452 pixRasteropIP(pixd, hshift, vshift, incolor);
453 return pixd;
454 }
455
456
457 /*!
458 * \brief pixRasteropIP()
459 *
460 * \param[in] pixd in-place translation
461 * \param[in] hshift horizontal shift; hshift > 0 is to right
462 * \param[in] vshift vertical shift; vshift > 0 is down
463 * \param[in] incolor L_BRING_IN_WHITE, L_BRING_IN_BLACK
464 * \return 0 if OK; 1 on error
465 */
466 l_ok
467 pixRasteropIP(PIX *pixd,
468 l_int32 hshift,
469 l_int32 vshift,
470 l_int32 incolor)
471 {
472 l_int32 w, h;
473
474 if (!pixd)
475 return ERROR_INT("pixd not defined", __func__, 1);
476
477 pixGetDimensions(pixd, &w, &h, NULL);
478 pixRasteropHip(pixd, 0, h, hshift, incolor);
479 pixRasteropVip(pixd, 0, w, vshift, incolor);
480
481 return 0;
482 }
483
484
485 /*--------------------------------------------------------------------*
486 * Full image rasterop with no shifts *
487 *--------------------------------------------------------------------*/
488 /*!
489 * \brief pixRasteropFullImage()
490 *
491 * \param[in] pixd
492 * \param[in] pixs
493 * \param[in] op any of the op-codes
494 * \return 0 if OK; 1 on error
495 *
496 * <pre>
497 * Notes:
498 * ~ this is a wrapper for a common 2-image raster operation
499 * ~ both pixs and pixd must be defined
500 * ~ the operation is performed with aligned UL corners of pixs and pixd
501 * ~ the operation clips to the smallest pix; if the width or height
502 * of pixd is larger than pixs, some pixels in pixd will be unchanged
503 * </pre>
504 */
505 l_ok
506 pixRasteropFullImage(PIX *pixd,
507 PIX *pixs,
508 l_int32 op)
509 {
510 if (!pixd)
511 return ERROR_INT("pixd not defined", __func__, 1);
512 if (!pixs)
513 return ERROR_INT("pixs not defined", __func__, 1);
514
515 pixRasterop(pixd, 0, 0, pixGetWidth(pixd), pixGetHeight(pixd), op,
516 pixs, 0, 0);
517 return 0;
518 }
519
520
521 /*--------------------------------------------------------------------*
522 * Checking for invalid crop box *
523 *--------------------------------------------------------------------*/
524 /*!
525 * \brief checkRasteropCrop()
526 *
527 * \param[in] pixw, pixh pix dimensions
528 * \param[in] x, y, w, h crop box parameters
529 * \return 0 if OK, 1 if the crop box does not intersect with the pix.
530 *
531 * <pre>
532 * Notes:
533 * (1) The widths and heights must all be positive, but %x and %y
534 * can take on any value.
535 * (2) This works for checking both the source and dest regions.
536 * (3) This has been used to verify rasteropLow() cropping is correct.
537 * It is not needed for pre-filtering in pixRasterop().
538 * </pre>
539 */
540 static l_int32
541 checkRasteropCrop(l_int32 pixw,
542 l_int32 pixh,
543 l_int32 x,
544 l_int32 y,
545 l_int32 w,
546 l_int32 h)
547 {
548 if (pixw < 1 || pixh < 1 || w < 1 || h < 1)
549 return ERROR_INT("dimension is <= 0", __func__, 1);
550
551 if (x + w <= 0 || y + h <= 0)
552 return ERROR_INT("box to left or above pix", __func__, 1);
553
554 if (x >= pixw || y >= pixh)
555 return ERROR_INT("box to right or below pix", __func__, 1);
556
557 return 0;
558 }