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