• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*====================================================================*
2  -  Copyright (C) 2001 Leptonica.  All rights reserved.
3  -  This software is distributed in the hope that it will be
4  -  useful, but with NO WARRANTY OF ANY KIND.
5  -  No author or distributor accepts responsibility to anyone for the
6  -  consequences of using this software, or for whether it serves any
7  -  particular purpose or works at all, unless he or she says so in
8  -  writing.  Everyone is granted permission to copy, modify and
9  -  redistribute this source code, for commercial or non-commercial
10  -  purposes, with the following restrictions: (1) the origin of this
11  -  source code must not be misrepresented; (2) modified versions must
12  -  be plainly marked as such; and (3) this notice may not be removed
13  -  or altered from any source or modified source distribution.
14  *====================================================================*/
15 
16 /*
17  *  fpix2.c
18  *
19  *    This file has these FPix utilities:
20  *       - interconversion with pix
21  *       - border functions
22  *       - simple rasterop (source --> dest)
23  *
24  *    Interconversions between Pix and FPix
25  *          FPIX          *pixConvertToFPix()
26  *          PIX           *fpixConvertToPix()
27  *          PIX           *fpixDisplayMaxDynamicRange()  [useful for debugging]
28  *
29  *    Border functions
30  *          FPIX          *fpixAddBorder()
31  *          FPIX          *fpixRemoveBorder()
32  *          FPIX          *fpixAddMirroredBorder()
33  *
34  *    Simple rasterop
35  *          l_int32        fpixRasterop()
36  *
37  *    Arithmetic operations
38  *          FPIX          *fpixLinearCombination()
39  *          l_int32        fpixAddMultConstant()
40  */
41 
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include "allheaders.h"
45 
46 
47 /*--------------------------------------------------------------------*
48  *                     FPix  <-->  Pix conversions                    *
49  *--------------------------------------------------------------------*/
50 /*!
51  *  pixConvertToFPix()
52  *
53  *      Input:  pix (1, 2, 4, 8, 16 or 32 bpp)
54  *              ncomps (number of components: 3 for RGB, 1 otherwise)
55  *      Return: fpix, or null on error
56  *
57  *  Notes:
58  *      (1) If colormapped, remove to grayscale.
59  *      (2) If 32 bpp and @ncomps == 3, this is RGB; convert to luminance.
60  *          In all other cases the src image is treated as having a single
61  *          component of pixel values.
62  */
63 FPIX *
pixConvertToFPix(PIX * pixs,l_int32 ncomps)64 pixConvertToFPix(PIX     *pixs,
65                  l_int32  ncomps)
66 {
67 l_int32     w, h, d, i, j, val, wplt, wpld;
68 l_uint32    uval;
69 l_uint32   *datat, *linet;
70 l_float32  *datad, *lined;
71 PIX        *pixt;
72 FPIX       *fpixd;
73 
74     PROCNAME("pixConvertToFPix");
75 
76     if (!pixs)
77         return (FPIX *)ERROR_PTR("pixs not defined", procName, NULL);
78 
79     if (pixGetColormap(pixs))
80         pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
81     else if (pixGetDepth(pixs) == 32 && ncomps == 3)
82         pixt = pixConvertRGBToLuminance(pixs);
83     else
84         pixt = pixClone(pixs);
85 
86     pixGetDimensions(pixt, &w, &h, &d);
87     if ((fpixd = fpixCreate(w, h)) == NULL)
88         return (FPIX *)ERROR_PTR("fpixd not made", procName, NULL);
89     datat = pixGetData(pixt);
90     wplt = pixGetWpl(pixt);
91     datad = fpixGetData(fpixd);
92     wpld = fpixGetWpl(fpixd);
93     for (i = 0; i < h; i++) {
94         linet = datat + i * wplt;
95         lined = datad + i * wpld;
96         if (d == 1) {
97             for (j = 0; j < w; j++) {
98                 val = GET_DATA_BIT(linet, j);
99                 lined[j] = (l_float32)val;
100             }
101         }
102         else if (d == 2) {
103             for (j = 0; j < w; j++) {
104                 val = GET_DATA_DIBIT(linet, j);
105                 lined[j] = (l_float32)val;
106             }
107         }
108         else if (d == 4) {
109             for (j = 0; j < w; j++) {
110                 val = GET_DATA_QBIT(linet, j);
111                 lined[j] = (l_float32)val;
112             }
113         }
114         else if (d == 8) {
115             for (j = 0; j < w; j++) {
116                 val = GET_DATA_BYTE(linet, j);
117                 lined[j] = (l_float32)val;
118             }
119         }
120         else if (d == 16) {
121             for (j = 0; j < w; j++) {
122                 val = GET_DATA_TWO_BYTES(linet, j);
123                 lined[j] = (l_float32)val;
124             }
125         }
126         else if (d == 32) {
127             for (j = 0; j < w; j++) {
128                 uval = GET_DATA_FOUR_BYTES(linet, j);
129                 lined[j] = (l_float32)uval;
130             }
131         }
132     }
133 
134     pixDestroy(&pixt);
135     return fpixd;
136 }
137 
138 
139 /*!
140  *  fpixConvertToPix()
141  *
142  *      Input:  fpixs
143  *              outdepth (0, 8, 16 or 32 bpp)
144  *              negvals (L_CLIP_TO_ZERO, L_TAKE_ABSVAL)
145  *              errorflag (1 to output error stats; 0 otherwise)
146  *      Return: pixd, or null on error
147  *
148  *  Notes:
149  *      (1) Use @outdepth = 0 to programmatically determine the
150  *          output depth.  If no values are greater than 255,
151  *          it will set outdepth = 8; otherwise to 16 or 32.
152  *      (2) Because we are converting a float to an unsigned int
153  *          with a specified dynamic range (8, 16 or 32 bits), errors
154  *          can occur.  If errorflag == TRUE, output the number
155  *          of values out of range, both negative and positive.
156  *      (3) If a pixel value is positive and out of range, clip to
157  *          the maximum value represented at the outdepth of 8, 16
158  *          or 32 bits.
159  */
160 PIX *
fpixConvertToPix(FPIX * fpixs,l_int32 outdepth,l_int32 negvals,l_int32 errorflag)161 fpixConvertToPix(FPIX    *fpixs,
162                  l_int32  outdepth,
163                  l_int32  negvals,
164                  l_int32  errorflag)
165 {
166 l_int32     w, h, i, j, wpls, wpld, maxval;
167 l_uint32    vald;
168 l_float32   val;
169 l_float32  *datas, *lines;
170 l_uint32   *datad, *lined;
171 PIX        *pixd;
172 
173     PROCNAME("fpixConvertToPix");
174 
175     if (!fpixs)
176         return (PIX *)ERROR_PTR("fpixs not defined", procName, NULL);
177     if (negvals != L_CLIP_TO_ZERO && negvals != L_TAKE_ABSVAL)
178         return (PIX *)ERROR_PTR("invalid negvals", procName, NULL);
179     if (outdepth != 0 && outdepth != 8 && outdepth != 16 && outdepth != 32)
180         return (PIX *)ERROR_PTR("outdepth not in {0,8,16,32}", procName, NULL);
181 
182     fpixGetDimensions(fpixs, &w, &h);
183     datas = fpixGetData(fpixs);
184     wpls = fpixGetWpl(fpixs);
185 
186         /* Adaptive determination of output depth */
187     if (outdepth == 0) {
188         outdepth = 8;
189         for (i = 0; i < h; i++) {
190             lines = datas + i * wpls;
191             for (j = 0; j < w; j++) {
192                 if (lines[j] > 65535.5) {
193                     outdepth = 32;
194                     break;
195                 }
196                 if (lines[j] > 255.5)
197                     outdepth = 16;
198             }
199             if (outdepth == 32) break;
200         }
201     }
202     maxval = (1 << outdepth) - 1;
203 
204         /* Gather statistics if @errorflag = TRUE */
205     if (errorflag) {
206         l_int32  negs = 0;
207         l_int32  overvals = 0;
208         for (i = 0; i < h; i++) {
209             lines = datas + i * wpls;
210             for (j = 0; j < w; j++) {
211                 val = lines[j];
212                 if (val < 0.0)
213                     negs++;
214                 else if (val > maxval)
215                     overvals++;
216             }
217         }
218         if (negs > 0)
219             L_ERROR_INT("Number of negative values: %d", procName, negs);
220         if (overvals > 0)
221             L_ERROR_INT("Number of too-large values: %d", procName, overvals);
222     }
223 
224         /* Make the pix and convert the data */
225     if ((pixd = pixCreate(w, h, outdepth)) == NULL)
226         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
227     datad = pixGetData(pixd);
228     wpld = pixGetWpl(pixd);
229     for (i = 0; i < h; i++) {
230 	lines = datas + i * wpls;
231 	lined = datad + i * wpld;
232 	for (j = 0; j < w; j++) {
233 	    val = lines[j];
234             if (val >= 0.0)
235                 vald = (l_uint32)(val + 0.5);
236             else {  /* val < 0.0 */
237                 if (negvals == L_CLIP_TO_ZERO)
238                     vald = 0;
239                 else
240                     vald = (l_uint32)(-val + 0.5);
241             }
242             if (vald > maxval)
243                 vald = maxval;
244             if (outdepth == 8)
245                 SET_DATA_BYTE(lined, j, vald);
246             else if (outdepth == 16)
247                 SET_DATA_TWO_BYTES(lined, j, vald);
248             else  /* outdepth == 32 */
249                 SET_DATA_FOUR_BYTES(lined, j, vald);
250         }
251     }
252 
253     return pixd;
254 }
255 
256 
257 /*!
258  *  fpixDisplayMaxDynamicRange()
259  *
260  *      Input:  fpixs
261  *      Return: pixd (8 bpp), or null on error
262  */
263 PIX *
fpixDisplayMaxDynamicRange(FPIX * fpixs)264 fpixDisplayMaxDynamicRange(FPIX  *fpixs)
265 {
266 l_uint8     dval;
267 l_int32     i, j, w, h, wpls, wpld;
268 l_float32   factor, sval, maxval;
269 l_float32  *lines, *datas;
270 l_uint32   *lined, *datad;
271 PIX        *pixd;
272 
273     PROCNAME("fpixDisplayMaxDynamicRange");
274 
275     if (!fpixs)
276         return (PIX *)ERROR_PTR("fpixs not defined", procName, NULL);
277 
278     fpixGetDimensions(fpixs, &w, &h);
279     datas = fpixGetData(fpixs);
280     wpls = fpixGetWpl(fpixs);
281 
282     maxval = 0.0;
283     for (i = 0; i < h; i++) {
284         lines = datas + i * wpls;
285         for (j = 0; j < w; j++) {
286             sval = *(lines + j);
287             if (sval > maxval)
288                 maxval = sval;
289         }
290     }
291 
292     pixd = pixCreate(w, h, 8);
293     if (maxval == 0.0)
294         return pixd;  /* all pixels are 0 */
295 
296     datad = pixGetData(pixd);
297     wpld = pixGetWpl(pixd);
298     factor = 255. / maxval;
299     for (i = 0; i < h; i++) {
300 	lines = datas + i * wpls;
301 	lined = datad + i * wpld;
302 	for (j = 0; j < w; j++) {
303 	    sval = *(lines + j);
304 	    if (sval < 0.0) sval = 0.0;
305 	    dval = (l_uint8)(factor * sval + 0.5);
306 	    SET_DATA_BYTE(lined, j, dval);
307 	}
308     }
309 
310     return pixd;
311 }
312 
313 
314 /*--------------------------------------------------------------------*
315  *                          Border functions                          *
316  *--------------------------------------------------------------------*/
317 /*!
318  *  fpixAddBorder()
319  *
320  *      Input:  fpixs
321  *              left, right, top, bot (pixels on each side to be added)
322  *      Return: fpixd, or null on error
323  *
324  *  Notes:
325  *      (1) Adds border of '0' 32-bit pixels
326  */
327 FPIX *
fpixAddBorder(FPIX * fpixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot)328 fpixAddBorder(FPIX    *fpixs,
329               l_int32  left,
330               l_int32  right,
331               l_int32  top,
332               l_int32  bot)
333 {
334 l_int32  ws, hs, wd, hd;
335 FPIX    *fpixd;
336 
337     PROCNAME("fpixAddBorder");
338 
339     if (!fpixs)
340         return (FPIX *)ERROR_PTR("fpixs not defined", procName, NULL);
341 
342     if (left <= 0 && right <= 0 && top <= 0 && bot <= 0)
343         return fpixCopy(NULL, fpixs);
344     fpixGetDimensions(fpixs, &ws, &hs);
345     wd = ws + left + right;
346     hd = hs + top + bot;
347     if ((fpixd = fpixCreate(wd, hd)) == NULL)
348         return (FPIX *)ERROR_PTR("fpixd not made", procName, NULL);
349 
350     fpixCopyResolution(fpixd, fpixs);
351     fpixRasterop(fpixd, left, top, ws, hs, fpixs, 0, 0);
352     return fpixd;
353 }
354 
355 
356 /*!
357  *  fpixRemoveBorder()
358  *
359  *      Input:  fpixs
360  *              left, right, top, bot (pixels on each side to be removed)
361  *      Return: fpixd, or null on error
362  */
363 FPIX *
fpixRemoveBorder(FPIX * fpixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot)364 fpixRemoveBorder(FPIX    *fpixs,
365                  l_int32  left,
366                  l_int32  right,
367                  l_int32  top,
368                  l_int32  bot)
369 {
370 l_int32  ws, hs, wd, hd;
371 FPIX    *fpixd;
372 
373     PROCNAME("fpixRemoveBorder");
374 
375     if (!fpixs)
376         return (FPIX *)ERROR_PTR("fpixs not defined", procName, NULL);
377 
378     if (left <= 0 && right <= 0 && top <= 0 && bot <= 0)
379         return fpixCopy(NULL, fpixs);
380     fpixGetDimensions(fpixs, &ws, &hs);
381     wd = ws - left - right;
382     hd = hs - top - bot;
383     if (wd <= 0 || hd <= 0)
384         return (FPIX *)ERROR_PTR("width & height not both > 0", procName, NULL);
385     if ((fpixd = fpixCreate(wd, hd)) == NULL)
386         return (FPIX *)ERROR_PTR("fpixd not made", procName, NULL);
387 
388     fpixCopyResolution(fpixd, fpixs);
389     fpixRasterop(fpixd, 0, 0, wd, hd, fpixs, left, top);
390     return fpixd;
391 }
392 
393 
394 
395 /*!
396  *  fpixAddMirroredBorder()
397  *
398  *      Input:  fpixs
399  *              left, right, top, bot (pixels on each side to be added)
400  *      Return: fpixd, or null on error
401  *
402  *  Notes:
403  *      (1) See pixAddMirroredBorder() for situations of usage.
404  */
405 FPIX *
fpixAddMirroredBorder(FPIX * fpixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot)406 fpixAddMirroredBorder(FPIX    *fpixs,
407                       l_int32  left,
408                       l_int32  right,
409                       l_int32  top,
410                       l_int32  bot)
411 {
412 l_int32  i, j, w, h;
413 FPIX    *fpixd;
414 
415     PROCNAME("fpixAddMirroredBorder");
416 
417     if (!fpixs)
418         return (FPIX *)ERROR_PTR("fpixs not defined", procName, NULL);
419 
420     fpixd = fpixAddBorder(fpixs, left, right, top, bot);
421     fpixGetDimensions(fpixs, &w, &h);
422     for (j = 0; j < left; j++)
423         fpixRasterop(fpixd, left - 1 - j, top, 1, h,
424                      fpixd, left + j, top);
425     for (j = 0; j < right; j++)
426         fpixRasterop(fpixd, left + w + j, top, 1, h,
427                      fpixd, left + w - 1 - j, top);
428     for (i = 0; i < top; i++)
429         fpixRasterop(fpixd, 0, top - 1 - i, left + w + right, 1,
430                      fpixd, 0, top + i);
431     for (i = 0; i < bot; i++)
432         fpixRasterop(fpixd, 0, top + h + i, left + w + right, 1,
433                      fpixd, 0, top + h - 1 - i);
434 
435     return fpixd;
436 }
437 
438 
439 /*--------------------------------------------------------------------*
440  *                          Simple rasterop                           *
441  *--------------------------------------------------------------------*/
442 /*!
443  *  fpixRasterop()
444  *
445  *      Input:  fpixd  (dest fpix)
446  *              dx     (x val of UL corner of dest rectangle)
447  *              dy     (y val of UL corner of dest rectangle)
448  *              dw     (width of dest rectangle)
449  *              dh     (height of dest rectangle)
450  *              fpixs  (src fpix)
451  *              sx     (x val of UL corner of src rectangle)
452  *              sy     (y val of UL corner of src rectangle)
453  *      Return: 0 if OK; 1 on error.
454  *
455  *  Notes:
456  *      (1) This is similiar in structure to pixRasterop(), except
457  *          it only allows copying from the source into the destination.
458  *          For that reason, no op code is necessary.  Additionally,
459  *          all pixels are 32 bit words (float values), which makes
460  *          the copy very simple.
461  *      (2) Clipping of both src and dest fpix are done automatically.
462  *      (3) This allows in-place copying, without checking to see if
463  *          the result is valid:  use for in-place with caution!
464  */
465 l_int32
fpixRasterop(FPIX * fpixd,l_int32 dx,l_int32 dy,l_int32 dw,l_int32 dh,FPIX * fpixs,l_int32 sx,l_int32 sy)466 fpixRasterop(FPIX    *fpixd,
467              l_int32  dx,
468              l_int32  dy,
469              l_int32  dw,
470              l_int32  dh,
471              FPIX    *fpixs,
472              l_int32  sx,
473              l_int32  sy)
474 {
475 l_int32     fsw, fsh, fdw, fdh, dhangw, shangw, dhangh, shangh;
476 l_int32     i, j, wpls, wpld;
477 l_float32  *datas, *datad, *lines, *lined;
478 
479     PROCNAME("fpixRasterop");
480 
481     if (!fpixs)
482         return ERROR_INT("fpixs not defined", procName, 1);
483     if (!fpixd)
484         return ERROR_INT("fpixd not defined", procName, 1);
485 
486     /* -------------------------------------------------------- *
487      *      Clip to maximum rectangle with both src and dest    *
488      * -------------------------------------------------------- */
489     fpixGetDimensions(fpixs, &fsw, &fsh);
490     fpixGetDimensions(fpixd, &fdw, &fdh);
491 
492         /* First clip horizontally (sx, dx, dw) */
493     if (dx < 0) {
494         sx -= dx;  /* increase sx */
495         dw += dx;  /* reduce dw */
496         dx = 0;
497     }
498     if (sx < 0) {
499         dx -= sx;  /* increase dx */
500         dw += sx;  /* reduce dw */
501         sx = 0;
502     }
503     dhangw = dx + dw - fdw;  /* rect overhang of dest to right */
504     if (dhangw > 0)
505         dw -= dhangw;  /* reduce dw */
506     shangw = sx + dw - fsw;   /* rect overhang of src to right */
507     if (shangw > 0)
508         dw -= shangw;  /* reduce dw */
509 
510         /* Then clip vertically (sy, dy, dh) */
511     if (dy < 0) {
512         sy -= dy;  /* increase sy */
513         dh += dy;  /* reduce dh */
514         dy = 0;
515     }
516     if (sy < 0) {
517         dy -= sy;  /* increase dy */
518         dh += sy;  /* reduce dh */
519         sy = 0;
520     }
521     dhangh = dy + dh - fdh;  /* rect overhang of dest below */
522     if (dhangh > 0)
523         dh -= dhangh;  /* reduce dh */
524     shangh = sy + dh - fsh;  /* rect overhang of src below */
525     if (shangh > 0)
526         dh -= shangh;  /* reduce dh */
527 
528         /* if clipped entirely, quit */
529     if ((dw <= 0) || (dh <= 0))
530         return 0;
531 
532     /* -------------------------------------------------------- *
533      *                    Copy block of data                    *
534      * -------------------------------------------------------- */
535     datas = fpixGetData(fpixs);
536     datad = fpixGetData(fpixd);
537     wpls = fpixGetWpl(fpixs);
538     wpld = fpixGetWpl(fpixd);
539     datas += sy * wpls + sx;  /* at UL corner of block */
540     datad += dy * wpld + dx;  /* at UL corner of block */
541     for (i = 0; i < dh; i++) {
542         lines = datas + i * wpls;
543         lined = datad + i * wpld;
544         for (j = 0; j < dw; j++) {
545             *lined = *lines;
546             lines++;
547             lined++;
548         }
549     }
550 
551     return 0;
552 }
553 
554 
555 /*--------------------------------------------------------------------*
556  *                        Arithmetic operations                       *
557  *--------------------------------------------------------------------*/
558 /*!
559  *  fpixLinearCombo()
560  *
561  *      Input:  fpixd (<optional>; this can be null, equal to fpixs1, or
562  *                     different from fpixs1)
563  *              fpixs1 (can be == to fpixd)
564  *              fpixs2
565  *      Return: pixd always
566  *
567  *  Notes:
568  *      (1) Computes pixelwise linear combination: a * src1 + b * src2
569  *      (2) Alignment is to UL corner.
570  *      (3) There are 3 cases.  The result can go to a new dest,
571  *          in-place to fpixs1, or to an existing input dest:
572  *          * fpixd == null:   (src1 + src2) --> new fpixd
573  *          * fpixd == fpixs1:  (src1 + src2) --> src1  (in-place)
574  *          * fpixd != fpixs1: (src1 + src2) --> input fpixd
575  *      (4) fpixs2 must be different from both fpixd and fpixs1.
576  */
577 FPIX *
fpixLinearCombination(FPIX * fpixd,FPIX * fpixs1,FPIX * fpixs2,l_float32 a,l_float32 b)578 fpixLinearCombination(FPIX      *fpixd,
579                       FPIX      *fpixs1,
580                       FPIX      *fpixs2,
581                       l_float32  a,
582                       l_float32  b)
583 {
584 l_int32     i, j, ws, hs, w, h, wpls, wpld;
585 l_float32   val;
586 l_float32  *datas, *datad, *lines, *lined;
587 
588     PROCNAME("fpixLinearCombination");
589 
590     if (!fpixs1)
591         return (FPIX *)ERROR_PTR("fpixs1 not defined", procName, fpixd);
592     if (!fpixs2)
593         return (FPIX *)ERROR_PTR("fpixs2 not defined", procName, fpixd);
594     if (fpixs1 == fpixs2)
595         return (FPIX *)ERROR_PTR("fpixs1 == fpixs2", procName, fpixd);
596     if (fpixs2 == fpixd)
597         return (FPIX *)ERROR_PTR("fpixs2 == fpixd", procName, fpixd);
598 
599     if (fpixs1 != fpixd)
600         fpixd = fpixCopy(fpixd, fpixs1);
601 
602     datas = fpixGetData(fpixs2);
603     datad = fpixGetData(fpixd);
604     wpls = fpixGetWpl(fpixs2);
605     wpld = fpixGetWpl(fpixd);
606     fpixGetDimensions(fpixs2, &ws, &hs);
607     fpixGetDimensions(fpixd, &w, &h);
608     w = L_MIN(ws, w);
609     h = L_MIN(hs, h);
610     for (i = 0; i < h; i++) {
611         lines = datas + i * wpls;
612         lined = datad + i * wpld;
613         if (a == 1.0 && b == 1.0) {  /* sum */
614             for (j = 0; j < w; j++)
615                 *(lined + j) += *(lines + j);
616         }
617         else if (a == 1.0 && b == -1.0) {  /* diff */
618             for (j = 0; j < w; j++)
619                 *(lined + j) -= *(lines + j);
620         }
621         else if (a == -1.0 && b == 1.0) {  /* diff */
622             for (j = 0; j < w; j++) {
623                 val = *(lined + j);
624                 *(lined + j) = -val + *(lines + j);
625             }
626         }
627         else if (a == -1.0 && b == -1.0) {
628             for (j = 0; j < w; j++) {
629                 val = *(lined + j);
630                 *(lined + j) = -val - *(lines + j);
631             }
632         }
633         else {
634             for (j = 0; j < w; j++)
635                 *(lined + j) = a * lined[j] + b * lines[j];
636         }
637     }
638 
639     return fpixd;
640 }
641 
642 
643 /*!
644  *  fpixAddMultConstant()
645  *
646  *      Input:  fpix
647  *              addc  (use 0.0 to skip the operation)
648  *              multc (use 1.0 to skip the operation)
649  *      Return: 0 if OK, 1 on error
650  *
651  *  Notes:
652  *      (1) This is an in-place operation.
653  *      (2) It can be used to multiply each pixel by a constant,
654  *          and also to add a constant to each pixel.  Multiplication
655  *          is done first.
656  */
657 l_int32
fpixAddMultConstant(FPIX * fpix,l_float32 addc,l_float32 multc)658 fpixAddMultConstant(FPIX      *fpix,
659                     l_float32  addc,
660                     l_float32  multc)
661 {
662 l_int32     i, j, w, h, wpl;
663 l_float32   val;
664 l_float32  *line, *data;
665 
666     PROCNAME("fpixAddMultConstant");
667 
668     if (!fpix)
669         return ERROR_INT("fpix not defined", procName, 1);
670 
671     if (addc == 0.0 && multc == 1.0)
672         return 0;
673 
674     fpixGetDimensions(fpix, &w, &h);
675     data = fpixGetData(fpix);
676     wpl = fpixGetWpl(fpix);
677     for (i = 0; i < h; i++) {
678         line = data + i * wpl;
679         if (addc == 0.0) {
680             for (j = 0; j < w; j++)
681                 *(line + j) *= multc;
682         }
683         else if (multc == 1.0) {
684             for (j = 0; j < w; j++)
685                 *(line + j) += addc;
686         }
687         else  {
688             for (j = 0; j < w; j++) {
689                 val = *(line + j);
690                 *(line + j) = multc * val + addc;
691             }
692         }
693     }
694 
695     return 0;
696 }
697 
698 
699