1 /**********************************************************************
2 * File: imgs.c (Formerly images.c)
3 * Description: Main image manipulation functions.
4 * Author: Ray Smith
5 * Created: Thu Jun 07 16:25:02 BST 1990
6 *
7 * (C) Copyright 1990, Hewlett-Packard Ltd.
8 ** Licensed under the Apache License, Version 2.0 (the "License");
9 ** you may not use this file except in compliance with the License.
10 ** You may obtain a copy of the License at
11 ** http://www.apache.org/licenses/LICENSE-2.0
12 ** Unless required by applicable law or agreed to in writing, software
13 ** distributed under the License is distributed on an "AS IS" BASIS,
14 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 ** See the License for the specific language governing permissions and
16 ** limitations under the License.
17 *
18 **********************************************************************/
19
20 #include "mfcpch.h" //precompiled headers
21 #ifdef __MSW32__
22 #include <io.h>
23 #else
24 #include <unistd.h>
25 #endif
26 #include <string.h>
27 #ifdef __UNIX__
28 #include <assert.h>
29 #endif
30
31 // Include automatically generated configuration file if running autoconf.
32 #ifdef HAVE_CONFIG_H
33 #include "config_auto.h"
34 #endif
35
36 #ifdef HAVE_LIBLEPT
37 // Include leptonica library only if autoconf (or makefile etc) tell us to.
38 #include "allheaders.h"
39 #endif
40
41 #include "stderr.h"
42 #include "tprintf.h"
43 #include "imgerrs.h"
44 #include "memry.h"
45 #include "imgs.h"
46 #include "imgio.h"
47 #include "imgunpk.h"
48
49 #define FIXED_COLOURS 32 /*number of fixed colours */
50 #define MIN_4BIT 48 /*4bpp range */
51 #define MAX_4BIT 64
52 #define MIN_6BIT 64 /*6bpp range */
53 #define MAX_6BIT 128
54 #define BLACK_PIX 0
55
56 static uinT8 grey_scales[FIXED_COLOURS] = {
57 0, 255, 76, 227, 151, 179, 28, 104,
58 149, 72, 215, 67, 53, 44, 156, 137,
59 110, 153, 79, 181, 166, 218, 55, 81,
60 129, 105, 179, 149, 168, 69, 84, 126
61 };
62
63 #undef EXTERN
64 #define EXTERN
65
66 EXTERN INT_VAR (image_default_resolution, 300, "Image resolution dpi");
67
68 /**********************************************************************
69 * IMAGE
70 *
71 * Contructor for an IMAGE class. Makes the image definitely illegal.
72 **********************************************************************/
73
IMAGE()74 IMAGE::IMAGE() { //construct an image
75 bpp = 0; //all illegal
76 fd = -1;
77 image = NULL;
78 photo_interp = 1;
79 res = image_default_resolution;
80 }
81
82
83 /**********************************************************************
84 * IMAGE::operator=
85 *
86 * Assign an IMAGE to another. The dest becomes the owner of the memory.
87 **********************************************************************/
88
operator =(IMAGE & source)89 IMAGE & IMAGE::operator= ( //assignment
90 IMAGE & source //source image
91 ) {
92 destroy();
93 bpp = source.bpp;
94 photo_interp = source.photo_interp;
95 bps = source.bps;
96 bytespp = (bpp + 7) / 8;
97 lineskip = source.lineskip; //copy everything
98 captured = source.captured;
99 xsize = source.xsize;
100 ysize = source.ysize;
101 res = source.res;
102 image = source.image;
103 xdim = source.xdim;
104 bufheight = source.bufheight;
105 fd = source.fd;
106 reader = source.reader;
107 ymin = source.ymin;
108 ymax = source.ymax;
109
110 source.captured = TRUE; //source now captured
111 source.fd = -1;
112
113 return *this;
114 }
115
116
117 /**********************************************************************
118 * create
119 *
120 * Create an image (allocate memory) of a specific size and bpp.
121 **********************************************************************/
122
create(inT32 x,inT32 y,inT8 bits_per_pixel)123 inT8 IMAGE::create( //get rest of image
124 inT32 x, //x size required
125 inT32 y, //ysize required
126 inT8 bits_per_pixel //bpp required
127 ) {
128 uinT8 *pixels; //memory for image
129
130 xdim = check_legal_image_size (x, y, bits_per_pixel);
131 if (xdim < 0)
132 return -1;
133 pixels = (uinT8 *) alloc_big_zeros ((size_t) (xdim * y * sizeof (uinT8)));
134 if (pixels == NULL) {
135 MEMORY_OUT.error ("IMAGE::create", ABORT, "Size=(%d,%d)", xdim, y);
136 return -1;
137 }
138 //allocate to image
139 this->capture (pixels, x, y, bits_per_pixel);
140 captured = FALSE;
141 res = image_default_resolution;
142 return 0; //success
143 }
144
145
146 /**********************************************************************
147 * destroy
148 *
149 * Destroy an image, freeing memory and closing any open file.
150 **********************************************************************/
151
destroy()152 void IMAGE::destroy() { //get rid of image
153 if (image != NULL && !captured) {
154 free_big_mem(image);
155 }
156 image = NULL;
157 if (fd >= 0) {
158 close(fd);
159 fd = -1;
160 }
161 bpp = 0;
162 }
163
164
165 /**********************************************************************
166 * capture
167 *
168 * Assign a given memory area to an image to use as an image of
169 * given size and bpp.
170 **********************************************************************/
171
capture(uinT8 * pixels,inT32 x,inT32 y,inT8 bits_per_pixel)172 inT8 IMAGE::capture( //get rest of image
173 uinT8 *pixels, //image memory
174 inT32 x, //x size required
175 inT32 y, //ysize required
176 inT8 bits_per_pixel //bpp required
177 ) {
178 destroy();
179 xdim = check_legal_image_size (x, y, bits_per_pixel);
180 if (xdim < 0)
181 return -1;
182 xsize = x;
183 ysize = y;
184 bufheight = y;
185 bpp = bits_per_pixel;
186 bps = bpp == 24 ? 8 : bpp;
187 photo_interp = 1;
188 bytespp = (bpp + 7) / 8;
189 image = pixels; //assign image area
190 ymin = 0;
191 ymax = bufheight; //read it all
192 captured = TRUE;
193 res = image_default_resolution;
194 return 0; //success
195 }
196
197
198 /**********************************************************************
199 * pixel
200 *
201 * Get a single pixel out of the image.
202 **********************************************************************/
203
pixel(inT32 x,inT32 y)204 uinT8 IMAGE::pixel( //get rest of image
205 inT32 x, //x coord
206 inT32 y //y coord
207 ) {
208 if (x < 0)
209 x = 0; //silently clip
210 else if (x >= xsize)
211 x = xsize - 1;
212 if (y < 0)
213 y = 0;
214 else if (y >= ysize)
215 y = ysize - 1;
216 check_legal_access (x, y, 1);
217 switch (bpp) {
218 case 5:
219 case 6:
220 case 8:
221 return image[(ymax - 1 - y) * xdim + x];
222 case 4:
223 return bpp4table[image[(ymax - 1 - y) * xdim + x / 2]][x & 1];
224 case 2:
225 return bpp2table[image[(ymax - 1 - y) * xdim + x / 4]][x & 3];
226 case 1:
227 return bpp1table[image[(ymax - 1 - y) * xdim + x / 8]][x & 7];
228 default:
229 tprintf ("Unexpected bits per pixel %d\n", bpp);
230 return 0;
231 }
232 }
233
234
235 /**********************************************************************
236 * check_legal_image_size
237 *
238 * Check that the supplied image sizes are legal. If they are,
239 * the xdim is returned, else -1.
240 **********************************************************************/
241
check_legal_image_size(inT32 x,inT32 y,inT8 bits_per_pixel)242 inT32 check_legal_image_size( //get rest of image
243 inT32 x, //x size required
244 inT32 y, //ysize required
245 inT8 bits_per_pixel //bpp required
246 ) {
247 if (x <= 0 || y <= 0) {
248 BADIMAGESIZE.error ("check_legal_image_size", TESSLOG, "(%d,%d)", x, y);
249 return -1; //failed
250 }
251 if (bits_per_pixel != 1 && bits_per_pixel != 2
252 && bits_per_pixel != 4 && bits_per_pixel != 5
253 && bits_per_pixel != 6 && bits_per_pixel != 8 && bits_per_pixel != 24
254 && bits_per_pixel != 32) {
255 BADBPP.error ("check_legal_image_size", TESSLOG, "%d", bits_per_pixel);
256 return -1;
257 }
258 //bytes per line
259 return COMPUTE_IMAGE_XDIM (x, bits_per_pixel);
260 }
261
262
263 /**********************************************************************
264 * copy_sub_image
265 *
266 * Copy a portion of one image to a portion of another image.
267 * If the bpps are different, the position of the most significant
268 * bit is preserved.
269 **********************************************************************/
270
copy_sub_image(IMAGE * source,inT32 xstart,inT32 ystart,inT32 xext,inT32 yext,IMAGE * dest,inT32 xdest,inT32 ydest,BOOL8 adjust_grey)271 DLLSYM void copy_sub_image( //copy rectangle
272 IMAGE *source, //source image
273 inT32 xstart, //start coords
274 inT32 ystart,
275 inT32 xext, //extent to copy
276 inT32 yext,
277 IMAGE *dest, //destination image
278 inT32 xdest, //destination coords
279 inT32 ydest,
280 BOOL8 adjust_grey //shift to new bpp
281 ) {
282 IMAGELINE copyline; //copy of line
283 uinT8 *copy; //source pointer
284 inT8 shift; //shift factor
285 inT32 pixel; //pixel index
286 inT32 y; //line index
287 inT32 yoffset; //current adjusted offset
288 inT32 bytesize; //no of bytes to copy
289 inT32 srcppb; //pixels per byte
290 BOOL8 aligned;
291
292 if (xstart < 0 || ystart < 0 || xdest < 0 || ydest < 0)
293 return;
294 if (xext <= 0)
295 xext = source->xsize; //default to all
296 if (xext > source->xsize - xstart)
297 //clip to smallest
298 xext = source->xsize - xstart;
299 if (xext > dest->xsize - xdest)
300 xext = dest->xsize - xdest;
301 if (yext <= 0)
302 yext = source->ysize; //default to all
303 if (yext > source->ysize - ystart)
304 //clip to smallest
305 yext = source->ysize - ystart;
306 if (yext > dest->ysize - ydest)
307 yext = dest->ysize - ydest;
308 if (xext <= 0 || yext <= 0)
309 return; //nothing to do
310
311 srcppb = 8 / source->bpp; //pixels per byte
312 if (source->bpp == dest->bpp || !adjust_grey)
313 shift = 0; //no adjustment
314 else {
315 shift = source->bps - dest->bps;
316 if (shift < 0)
317 shift = -shift; //keep positive
318 }
319 aligned = source->bpp == dest->bpp;
320 if (aligned && srcppb != 0) {
321 aligned = xstart % srcppb == 0
322 && xdest % srcppb == 0
323 && (xext % srcppb == 0 || xdest + xext == dest->xsize);
324 }
325 for (y = 0; y < yext; y++) {
326 if (ystart >= ydest)
327 yoffset = y; //top down
328 else
329 yoffset = yext - y - 1; //bottom up
330 source->check_legal_access (xstart, ystart + yoffset, xext);
331 dest->check_legal_access (xdest, ydest + yoffset, xext);
332 if (aligned) {
333 bytesize = COMPUTE_IMAGE_XDIM (xext, source->bpp);
334 //get bytes per line
335 if (srcppb == 0)
336 //do cheap move
337 memmove (dest->image + (dest->ymax - 1 - ydest - yoffset) * dest->xdim + xdest * 3, source->image + (source->ymax - 1 - ystart - yoffset) * source->xdim + xstart * 3, (unsigned) bytesize);
338 else
339 //do cheap move
340 memmove (dest->image + (dest->ymax - 1 - ydest - yoffset) * dest->xdim + xdest / srcppb, source->image + (source->ymax - 1 - ystart - yoffset) * source->xdim + xstart / srcppb, (unsigned) bytesize);
341 }
342 else {
343 if (shift == 0) {
344 source->fast_get_line (xstart, ystart + yoffset, xext,
345 ©line);
346 }
347 else if (source->bpp < dest->bpp) {
348 source->get_line (xstart, ystart + yoffset, xext, ©line, 0);
349 if (source->bpp <= shift
350 && (source->bpp == 1 || source->bpp == 4)) {
351 if (source->bpp == 1) {
352 for (pixel = 0, copy = copyline.pixels; pixel < xext;
353 pixel++, copy++)
354 if (*copy)
355 *copy = 0xff;
356 }
357 else {
358 for (pixel = 0, copy = copyline.pixels; pixel < xext;
359 pixel++, copy++)
360 //scale up
361 *copy = (*copy << shift) | *copy;
362 }
363 }
364 else {
365 for (pixel = 0, copy = copyline.pixels; pixel < xext;
366 pixel++)
367 *copy++ <<= shift; //scale up
368 }
369 }
370 else {
371 source->get_line (xstart, ystart + yoffset, xext, ©line, 0);
372 if (source->bpp == 24) {
373 for (pixel = 0, copy = copyline.pixels + 1; pixel < xext;
374 pixel++) {
375 *copy >>= shift;
376 copy += 3;
377 }
378 }
379 else {
380 for (pixel = 0, copy = copyline.pixels; pixel < xext;
381 pixel++)
382 *copy++ >>= shift; //scale down
383 }
384 }
385 dest->put_line (xdest, ydest + yoffset, xext, ©line, 0);
386 }
387 }
388 }
389
390
391 /**********************************************************************
392 * enlarge_sub_image
393 *
394 * Enlarge a portion of one image to a portion of another image.
395 * If the bpps are different, the position of the most significant
396 * bit is preserved.
397 **********************************************************************/
398
enlarge_sub_image(IMAGE * source,inT32 xstart,inT32 ystart,IMAGE * dest,inT32 xdest,inT32 ydest,inT32 xext,inT32 yext,inT32 scale,BOOL8 adjust_grey)399 DLLSYM void enlarge_sub_image( //enlarge rectangle
400 IMAGE *source, //source image
401 inT32 xstart, //scaled start coords
402 inT32 ystart,
403 IMAGE *dest, //destination image
404 inT32 xdest, //dest coords
405 inT32 ydest,
406 inT32 xext, //destination extent
407 inT32 yext,
408 inT32 scale, //scale factor
409 BOOL8 adjust_grey //shift to new bpp
410 ) {
411 inT8 shift; //shift factor
412 uinT8 pixel; //current pixel
413 inT32 srcext; //source extent
414 inT32 xoffset; //column index
415 inT32 yoffset; //line index
416 inT32 xindex, yindex; //index in super pixel
417 inT32 startxindex; //initial x index
418 inT32 xscale; //x scale factor
419 uinT8 *src; //source pixels
420 uinT8 *destpix; //dest pixels
421 IMAGELINE copyline; //copy of line
422 IMAGELINE bigline; //expanded line
423
424 if (xstart < 0 || ystart < 0 || xdest < 0 || ydest < 0)
425 return;
426
427 if (xext <= 0)
428 xext = dest->xsize; //default to all
429 if (xext > source->xsize * scale - xstart)
430 //clip to smallest
431 xext = source->xsize * scale - xstart;
432 if (xext > dest->xsize - xdest)
433 xext = dest->xsize - xdest;
434 if (yext <= 0)
435 yext = dest->ysize; //default to all
436 if (yext > source->ysize * scale - ystart)
437 yext = source->ysize * scale - ystart;
438 if (yext > dest->ysize - ydest)
439 yext = dest->ysize - ydest;
440 if (xext <= 0 || yext <= 0)
441 return; //nothing to do
442
443 xindex = xstart % scale; //offset in super pixel
444 startxindex = xindex;
445 yindex = ystart % scale;
446 //no of source pixels
447 srcext = (xext + xindex + scale - 1) / scale;
448 xstart /= scale; //actual start
449 ystart /= scale;
450 if (adjust_grey) {
451 shift = dest->bps - source->bps;
452 }
453 else
454 shift = 0; //no adjustment
455 bigline.init (xext * 3);
456 bigline.bpp = dest->bpp == 24 ? source->bpp : dest->bpp;
457
458 for (yoffset = 0; yoffset < yext; ystart++) {
459 source->check_legal_access (xstart, ystart, srcext);
460 dest->check_legal_access (xdest, ydest + yoffset, xext);
461 source->fast_get_line (xstart, ystart, srcext, ©line);
462 src = copyline.pixels;
463 destpix = bigline.pixels;
464 xscale = scale; //enlargement factor
465 if (source->bpp == 24 && dest->bpp == 24) {
466 for (xoffset = 0, xindex = startxindex; xoffset < xext;
467 src += source->bytespp) {
468 xoffset += xscale - xindex;
469 if (xoffset > xext)
470 xscale -= xoffset - xext;
471 for (; xindex < xscale; xindex++) {
472 *destpix++ = *src;
473 *destpix++ = *(src + 1);
474 *destpix++ = *(src + 2);
475 }
476 xindex = 0;
477 }
478 }
479 else {
480 if (source->bpp == 24)
481 src++;
482 for (xoffset = 0, xindex = startxindex; xoffset < xext;
483 src += source->bytespp) {
484 xoffset += xscale - xindex;
485 if (xoffset > xext)
486 //clip to dest limit
487 xscale -= xoffset - xext;
488 if (shift == 0)
489 pixel = *src;
490 else if (shift > 0)
491 pixel = *src << shift;
492 else
493 pixel = *src >> (-shift);
494 for (; xindex < xscale; xindex++)
495 *destpix++ = pixel; //duplicate pixel
496 xindex = 0;
497 }
498 }
499 for (; yoffset < yext && yindex < scale; yindex++, yoffset++) {
500 dest->put_line (xdest, ydest + yoffset, xext, &bigline, 0);
501 }
502 yindex = 0;
503 }
504 }
505
506
507 /**********************************************************************
508 * fast_reduce_sub_image
509 *
510 * Reduce a portion of one image to a portion of another image.
511 * If the bpps are different, the position of the most significant
512 * bit is preserved.
513 * This is a fast but dirty version, which simply sub-samples.
514 * It does not smooth as it reduces.
515 **********************************************************************/
516
fast_reduce_sub_image(IMAGE * source,inT32 xstart,inT32 ystart,inT32 xext,inT32 yext,IMAGE * dest,inT32 xdest,inT32 ydest,inT32 scale,BOOL8 adjust_grey)517 DLLSYM void fast_reduce_sub_image( //reduce rectangle
518 IMAGE *source, //source image
519 inT32 xstart, //start coords
520 inT32 ystart,
521 inT32 xext, //extent to copy
522 inT32 yext,
523 IMAGE *dest, //destination image
524 inT32 xdest, //destination coords
525 inT32 ydest,
526 inT32 scale, //reduction factor
527 BOOL8 adjust_grey //shift to new bpp
528 ) {
529 inT8 shift; //shift factor
530 inT32 xfactor; //run on x coord
531 inT32 divisor; //total cell area
532 inT32 xindex, yindex; //into averaging square
533 inT32 xcoord; //current x coord
534 inT32 destext; //destination size
535 inT32 yoffset; //current adjusted offset
536 uinT8 *pixel; //ptr to source pixels
537 inT32 *sums; //ptr to sums array
538 IMAGELINE copyline; //copy of line
539 inT32 *linesums; //averaging sums
540
541 if (xstart < 0 || ystart < 0 || xdest < 0 || ydest < 0)
542 return;
543 if (xext <= 0)
544 xext = source->xsize; //default to all
545 if (xext > source->xsize - xstart)
546 //clip to smallest
547 xext = source->xsize - xstart;
548 if (xext > (dest->xsize - xdest) * scale)
549 xext = (dest->xsize - xdest) * scale;
550 if (yext <= 0)
551 yext = source->ysize; //default to all
552 if (yext > source->ysize - ystart)
553 //clip to smallest
554 yext = source->ysize - ystart;
555 if (yext > (dest->ysize - ydest) * scale)
556 yext = (dest->ysize - ydest) * scale;
557 if (xext <= 0 || yext <= 0)
558 return; //nothing to do
559
560 xfactor = xext % scale; //left overs
561 if (xfactor == 0)
562 xfactor = scale;
563 //destination pixels
564 destext = (xext + scale - 1) / scale;
565 if (adjust_grey)
566 //shift factor
567 shift = dest->bps - source->bps;
568 else
569 shift = 0; //no adjustment
570 linesums = new inT32[destext * source->bytespp];
571
572 for (yoffset = 0; yoffset < yext; ydest++) {
573 source->check_legal_access (xstart, ystart + yoffset, xext);
574 dest->check_legal_access (xdest, ydest, destext);
575 for (xindex = destext * source->bytespp - 1; xindex >= 0; xindex--)
576 linesums[xindex] = 0; //zero sums
577 for (yindex = 0; yindex < scale
578 && ystart + yoffset < source->ysize; yindex += 3) {
579 source->fast_get_line (xstart, ystart + yoffset, xext, ©line);
580 pixel = copyline.pixels; //start of line
581 if (source->bpp == 24) {
582 for (xcoord = 1, sums = linesums; xcoord < destext;
583 xcoord++, sums += 3) {
584 for (xindex = 0; xindex < scale; xindex += 2) {
585 *sums += *pixel++;
586 *(sums + 1) += *pixel++;
587 *(sums + 2) += *pixel++;
588 pixel += 3;
589 }
590 if (scale & 1)
591 pixel -= 3; //correct position
592 }
593 for (xindex = 0; xindex < xfactor; xindex += 2) {
594 *sums += *pixel++;
595 *(sums + 1) += *pixel++;
596 *(sums + 2) += *pixel++;
597 pixel += 3;
598 }
599 }
600 else {
601 for (xcoord = 1, sums = linesums; xcoord < destext;
602 xcoord++, sums++) {
603 for (xindex = 0; xindex < scale; xindex += 2) {
604 *sums += *pixel;
605 pixel += 2;
606 }
607 if (scale & 1)
608 pixel--; //correct position
609 }
610 for (xindex = 0; xindex < xfactor; xindex += 2) {
611 *sums += *pixel;
612 pixel += 2;
613 }
614 }
615 yoffset += 3; //every 3 lines
616 }
617 if (yindex > scale)
618 yoffset -= yindex - scale; //back on right scale
619 copyline.init (); //set pixels back to array
620 copyline.bpp = source->bpp;
621 pixel = copyline.pixels;
622 //pixels in block
623 divisor = ((yindex + 2) / 3) * ((scale + 1) / 2);
624 if (shift <= 0) {
625 divisor <<= (-shift); //do greyscale correction
626 for (sums = linesums, xindex = (destext - 1) * source->bytespp;
627 xindex > 0; xindex--)
628 //turn to destination value
629 *pixel++ = (uinT8) (*sums++ / divisor);
630 for (xindex = source->bytespp; xindex > 0; xindex--)
631 *pixel++ = *sums++
632 / (((yindex + 2) / 3) * ((xfactor + 1) / 2) << (-shift));
633 //lastone different
634 }
635 else {
636 for (sums = linesums, xindex = (destext - 1) * source->bytespp;
637 xindex > 0; xindex--)
638 *pixel++ = (uinT8) ((*sums++ << shift) / divisor);
639 //destination value
640 for (xindex = source->bytespp; xindex > 0; xindex--)
641 //last one different
642 *pixel++ = (*(sums++) << shift) / (((yindex + 2) / 3) * ((xfactor + 1) / 2));
643 }
644 //put in destination
645 dest->put_line (xdest, ydest, destext, ©line, 0);
646 }
647 delete linesums;
648 }
649
650
651 /**********************************************************************
652 * reduce_sub_image
653 *
654 * Reduce a portion of one image to a portion of another image.
655 * If the bpps are different, the position of the most significant
656 * bit is preserved.
657 **********************************************************************/
658
reduce_sub_image(IMAGE * source,inT32 xstart,inT32 ystart,inT32 xext,inT32 yext,IMAGE * dest,inT32 xdest,inT32 ydest,inT32 scale,BOOL8 adjust_grey)659 DLLSYM void reduce_sub_image( //reduce rectangle
660 IMAGE *source, //source image
661 inT32 xstart, //start coords
662 inT32 ystart,
663 inT32 xext, //extent to copy
664 inT32 yext,
665 IMAGE *dest, //destination image
666 inT32 xdest, //destination coords
667 inT32 ydest,
668 inT32 scale, //reduction factor
669 BOOL8 adjust_grey //shift to new bpp
670 ) {
671 inT8 shift; //shift factor
672 inT32 xfactor; //run on x coord
673 inT32 divisor; //total cell area
674 inT32 div2; //total cell area divided by 2
675 inT32 xindex, yindex; //into averaging square
676 inT32 xcoord; //current x coord
677 inT32 destext; //destination size
678 inT32 yoffset; //current adjusted offset
679 uinT8 *pixel; //ptr to source pixels
680 inT32 *sums; //ptr to sums array
681 IMAGELINE copyline; //copy of line
682 inT32 *linesums; //averaging sums
683
684 if (xstart < 0 || ystart < 0 || xdest < 0 || ydest < 0)
685 return;
686 if (xext <= 0)
687 xext = source->xsize; //default to all
688 if (xext > source->xsize - xstart)
689 //clip to smallest
690 xext = source->xsize - xstart;
691 if (xext > (dest->xsize - xdest) * scale)
692 xext = (dest->xsize - xdest) * scale;
693 if (yext <= 0)
694 yext = source->ysize; //default to all
695 if (yext > source->ysize - ystart)
696 //clip to smallest
697 yext = source->ysize - ystart;
698 if (yext > (dest->ysize - ydest) * scale)
699 yext = (dest->ysize - ydest) * scale;
700 if (xext <= 0 || yext <= 0)
701 return; //nothing to do
702
703 xfactor = xext % scale; //left overs
704 if (xfactor == 0)
705 xfactor = scale;
706 //destination pixels
707 destext = (xext + scale - 1) / scale;
708 if (adjust_grey)
709 //shift factor
710 shift = dest->bps - source->bps;
711 else
712 shift = 0; //no adjustment
713 linesums = new inT32[destext * source->bytespp];
714
715 for (yoffset = 0; yoffset < yext; ydest++) {
716 source->check_legal_access (xstart, ystart + yoffset, xext);
717 dest->check_legal_access (xdest, ydest, destext);
718 for (xindex = 0; xindex < (destext) * source->bytespp; xindex++)
719 linesums[xindex] = 0; //zero sums
720 for (yindex = 0; yindex < scale && ystart + yoffset < source->ysize;
721 yindex++) {
722 source->fast_get_line (xstart, ystart + yoffset, xext, ©line);
723 pixel = copyline.pixels; //start of line
724 if (source->bpp == 24) {
725 for (xcoord = 1, sums = linesums; xcoord < destext;
726 xcoord++, sums += 3) {
727 for (xindex = 0; xindex < scale; xindex++) {
728 *sums += *pixel++;
729 *(sums + 1) += *pixel++;
730 *(sums + 2) += *pixel++;
731 }
732 }
733 for (xindex = 0; xindex < xfactor; xindex++) {
734 *sums += *pixel++;
735 *(sums + 1) += *pixel++;
736 *(sums + 2) += *pixel++;
737 }
738 }
739 else {
740 for (xcoord = 1, sums = linesums; xcoord < destext;
741 xcoord++, sums++) {
742 for (xindex = 0; xindex < scale; xindex++)
743 *sums += *pixel++;
744 }
745 for (xindex = 0; xindex < xfactor; xindex++)
746 *sums += *pixel++;
747 }
748 yoffset++; //next line
749 }
750 copyline.init (); //set pixels back to array
751 copyline.set_bpp (source->bpp);
752 pixel = copyline.pixels;
753 divisor = yindex * scale;
754 if (divisor == 0) {
755 tprintf
756 ("Impossible:divisor=0!, yindex=%d, scale=%d, yoffset=%d,yext=%d\n",
757 yindex, scale, yoffset, yext);
758 break;
759 }
760 if (shift <= 0) {
761 divisor <<= (-shift); //do greyscale correction
762 div2 = divisor / 2;
763 for (sums = linesums, xindex = (destext - 1) * source->bytespp;
764 xindex > 0; xindex--)
765 *pixel++ = (uinT8) ((div2 + *sums++) / divisor);
766 //turn to destination value
767 div2 = (yindex * xfactor << (-shift)) / 2;
768 for (xindex = source->bytespp; xindex > 0; xindex--)
769 *pixel++ =
770 (uinT8) ((div2 + *sums++) / (yindex * xfactor << (-shift)));
771 //lastone different
772 }
773 else {
774 div2 = divisor / 2;
775 for (sums = linesums, xindex = (destext - 1) * source->bytespp;
776 xindex > 0; xindex--)
777 *pixel++ = (uinT8) ((div2 + (*sums++ << shift)) / divisor);
778 //destination value
779 div2 = (yindex * xfactor) / 2;
780 for (xindex = source->bytespp; xindex > 0; xindex--)
781 *pixel++ =
782 (uinT8) ((div2 + (*sums++ << shift)) / (yindex * xfactor));
783 //last one different
784 }
785 //put in destination
786 dest->put_line (xdest, ydest, destext, ©line, 0);
787 }
788 delete linesums;
789 }
790
791
792 /**********************************************************************
793 * invert_image
794 *
795 * Invert the given image (the slow way.)
796 **********************************************************************/
797
invert_image(IMAGE * image)798 DLLSYM void invert_image( /*invert the image */
799 IMAGE *image /*image ot invert */
800 ) {
801 uinT8 mask; //bit mask
802 uinT8 bytespp; //bytes per pixel
803 inT32 xsize, ysize; /*size of image */
804 inT32 xindex, yindex; /*index into image */
805 uinT8 *pixel; /*current pixel */
806 IMAGELINE line; /*line of image */
807
808 bytespp = image->get_bpp () == 24 ? 3 : 1;
809 xsize = image->get_xsize (); /*find sizes */
810 ysize = image->get_ysize ();
811 //pixel mask
812 mask = (1 << image->get_bpp ()) - 1;
813 /*do each line */
814 for (yindex = ysize - 1; yindex >= 0; yindex--) {
815 image->fast_get_line (0, yindex, xsize, &line);
816 for (pixel = line.pixels, xindex = xsize * bytespp; xindex > 0;
817 xindex--) {
818 *pixel = (*pixel) ^ mask; //invert image only
819 ++pixel;
820 }
821 /*put it back */
822 image->fast_put_line (0, yindex, xsize, &line);
823 }
824 }
825
826
827 /**********************************************************************
828 * bias_sub_image
829 *
830 * Add a constant to a portion of an image.
831 **********************************************************************/
832
bias_sub_image(IMAGE * source,inT32 xstart,inT32 ystart,inT32 xext,inT32 yext,uinT8 bias)833 DLLSYM void bias_sub_image( //bias rectangle
834 IMAGE *source, //source image
835 inT32 xstart, //start coords
836 inT32 ystart,
837 inT32 xext, //extent to copy
838 inT32 yext,
839 uinT8 bias //number to add
840 ) {
841 IMAGELINE copyline; //copy of line
842 uinT8 *copy; //source pointer
843 inT32 pixel; //pixel index
844 inT32 y; //line index
845 uinT8 bytespp; //bytes per pixel
846
847 if (xstart < 0 || ystart < 0)
848 return;
849 if (xext <= 0)
850 xext = source->get_xsize (); //default to all
851 if (xext > source->get_xsize () - xstart)
852 //clip to smallest
853 xext = source->get_xsize () - xstart;
854 if (yext <= 0)
855 yext = source->get_ysize (); //default to all
856 if (yext > source->get_ysize () - ystart)
857 //clip to smallest
858 yext = source->get_ysize () - ystart;
859 if (xext <= 0 || yext <= 0)
860 return; //nothing to do
861
862 bytespp = source->get_bpp () == 24 ? 3 : 1;
863 for (y = 0; y < yext; y++) {
864 source->check_legal_access (xstart, ystart + y, xext);
865 source->fast_get_line (xstart, ystart + y, xext, ©line);
866 for (pixel = xext * bytespp, copy = copyline.pixels; pixel > 0;
867 pixel--, copy++)
868 *copy += bias; //add bias
869
870 source->fast_put_line (xstart, ystart + y, xext, ©line);
871 }
872 }
873
874
875 /**********************************************************************
876 * starbase_to_normal
877 *
878 * Copy a portion of one image to a portion of another image.
879 * This function maps the colour tables used on the screen to
880 * greyscale values in the way "normally" expected.
881 **********************************************************************/
882
starbase_to_normal(IMAGE * source,inT32 xstart,inT32 ystart,inT32 xext,inT32 yext,IMAGE * dest,inT32 xdest,inT32 ydest,BOOL8 preserve_grey)883 DLLSYM void starbase_to_normal( //copy rectangle
884 IMAGE *source, //source image
885 inT32 xstart, //start coords
886 inT32 ystart,
887 inT32 xext, //extent to copy
888 inT32 yext,
889 IMAGE *dest, //destination image
890 inT32 xdest, //destination coords
891 inT32 ydest,
892 BOOL8 preserve_grey //shift to new bpp
893 ) {
894 IMAGELINE copyline; //copy of line
895 uinT8 *copy; //source pointer
896 inT8 shift4; //shift factor
897 inT8 shift6; //shift factor
898 inT8 colour_shift; //shift of colours
899 uinT8 white_level; //dest white value
900 inT32 pixel; //pixel index
901 inT32 y; //line index
902 inT32 yoffset; //current adjusted offset
903 inT8 srcppb; //pixels per byte
904
905 if (xstart < 0 || ystart < 0 || xdest < 0 || ydest < 0)
906 return;
907 if (xext <= 0)
908 xext = source->get_xsize (); //default to all
909 if (xext > source->get_xsize () - xstart)
910 //clip to smallest
911 xext = source->get_xsize () - xstart;
912 if (xext > dest->get_xsize () - xdest)
913 xext = dest->get_xsize () - xdest;
914 if (yext <= 0)
915 yext = source->get_ysize (); //default to all
916 if (yext > source->get_ysize () - ystart)
917 //clip to smallest
918 yext = source->get_ysize () - ystart;
919 if (yext > dest->get_ysize () - ydest)
920 yext = dest->get_ysize () - ydest;
921 if (xext <= 0 || yext <= 0)
922 return; //nothing to do
923
924 //pixels per byte
925 srcppb = 8 / source->get_bpp ();
926 shift4 = 4 - dest->get_bpp (); //for different bpps
927 shift6 = 6 - dest->get_bpp ();
928 //for grey preserve
929 colour_shift = 8 - dest->get_bpp ();
930 white_level = dest->get_white_level ();
931 for (y = 0; y < yext; y++) {
932 if (ystart >= ydest)
933 yoffset = y; //top down
934 else
935 yoffset = yext - y - 1; //bottom up
936 source->check_legal_access (xstart, ystart + yoffset, xext);
937 dest->check_legal_access (xdest, ydest + yoffset, xext);
938 source->get_line (xstart, ystart + yoffset, xext, ©line, 0);
939 for (pixel = 0, copy = copyline.pixels; pixel < xext; pixel++) {
940 if (*copy < FIXED_COLOURS && preserve_grey)
941 *copy = grey_scales[*copy] >> colour_shift;
942 else if (*copy < FIXED_COLOURS) {
943 if (*copy == BLACK_PIX)
944 *copy = white_level; //black->white
945 else
946 *copy = 0; //others->black
947 }
948 else if (*copy >= MIN_4BIT && *copy < MAX_4BIT) {
949 if (shift4 < 0)
950 *copy = (*copy - MIN_4BIT) << (-shift4);
951 else
952 *copy = (*copy - MIN_4BIT) >> shift4;
953 }
954 else if (*copy >= MIN_6BIT && *copy < MAX_6BIT) {
955 if (shift6 < 0)
956 *copy = (*copy - MIN_6BIT) << (-shift6);
957 else
958 *copy = (*copy - MIN_6BIT) >> shift6;
959 }
960 else {
961 *copy = white_level; //white the rest
962 }
963 copy++;
964 }
965 dest->put_line (xdest, ydest + yoffset, xext, ©line, 0);
966 }
967 }
968
969
970 /**********************************************************************
971 * fast_get_line
972 *
973 * Get a line of image into the supplied image line buffer.
974 * The image is converted to 8bpp by simple assignment.
975 * If the image is aleady 8 or 6bpp, no copy is done and a pointer
976 * to the correct image section is put in the line buffer.
977 **********************************************************************/
978
fast_get_line(inT32 x,inT32 y,inT32 width,IMAGELINE * linebuf)979 void IMAGE::fast_get_line( //get image line
980 inT32 x, //coord to start at
981 inT32 y, //line to get
982 inT32 width, //no of pixels to get
983 IMAGELINE *linebuf //line to copy to
984 ) {
985 if (width > 0 && bpp > 4) {
986 check_legal_access(x, y, width);
987 //get pointer only
988 linebuf->pixels = image + xdim * (ymax - 1 - y) + x * bytespp;
989 }
990 else
991 //just copy it
992 this->get_line (x, y, width, linebuf, 0);
993 linebuf->bpp = bpp;
994 }
995
996
997 /**********************************************************************
998 * get_line
999 *
1000 * Get a line of image into the supplied image line buffer.
1001 * The image is converted to 8bpp by simple assignment.
1002 **********************************************************************/
1003
get_line(inT32 x,inT32 y,inT32 width,IMAGELINE * linebuf,inT32 margins)1004 void IMAGE::get_line( //get image line
1005 inT32 x, //coord to start at
1006 inT32 y, //line to get
1007 inT32 width, //no of pixels to get
1008 IMAGELINE *linebuf, //line to copy to
1009 inT32 margins //size of margins
1010 ) {
1011 uinT8 *src; //source pointer
1012 uinT8 *dest; //destination pointer
1013 uinT8 *unpacksrc; //unpacking pointer
1014 inT8 bit; //bit index
1015 inT8 pixperbyte; //pixels per byte
1016 uinT8 white; //white colour
1017 inT32 pixel; //pixel index
1018
1019 //test coords
1020 this->check_legal_access (x, y, width);
1021 if (width > xsize - x)
1022 width = xsize - x; //clip to image
1023 width *= bytespp;
1024 linebuf->init (width + margins * bytespp * 2);
1025 linebuf->bpp = bpp;
1026 //start of line
1027 src = image + xdim * (ymax - 1 - y);
1028 dest = linebuf->line; //destination line
1029 linebuf->pixels = dest;
1030 white = (1 << bpp) - 1; //max value of pixel
1031 for (pixel = margins * bytespp; pixel > 0; pixel--) {
1032 *dest++ = white; //margins are white
1033 }
1034 if (width > 0) {
1035 if (bpp > 4) {
1036 src += x; //offset
1037 //easy way
1038 memmove (dest, src, (unsigned) width);
1039 }
1040 else if (bpp == 4) {
1041 src += x / 2; //offset on line
1042 if (x & 1) {
1043 //get coded nibble
1044 *dest++ = bpp4table[*src++][1];
1045 width--;
1046 }
1047 while (width >= 2) {
1048 //get coded bits
1049 unpacksrc = bpp4table[*src++];
1050 *dest++ = *unpacksrc++;
1051 *dest++ = *unpacksrc++; //copy nibbles
1052 width -= 2;
1053 }
1054 if (width) {
1055 //get coded nibble
1056 *dest++ = bpp4table[*src++][0];
1057 }
1058 }
1059 else if (bpp == 2) {
1060 pixperbyte = 4;
1061 src += x / 4; //offset on line
1062 bit = (inT8) (x % 4); //offset in byte
1063 width += bit;
1064 while (width > 0) { //until all done
1065 if (width < pixperbyte)
1066 //less on last byte
1067 pixperbyte = (inT8) width;
1068 //get coded bits
1069 unpacksrc = &bpp2table[*src++][bit];
1070 for (; bit < pixperbyte; bit++)
1071 *dest++ = *unpacksrc++;//copy bytes
1072 width -= pixperbyte;
1073 bit = 0;
1074 }
1075 }
1076 else {
1077 pixperbyte = 8;
1078 src += x / 8; //offset on line
1079 bit = (inT8) (x % 8); //offset in byte
1080 width += bit;
1081 while (width > 0) { //until all done
1082 if (width < pixperbyte)
1083 //less on last byte
1084 pixperbyte = (inT8) width;
1085 //get coded bits
1086 unpacksrc = &bpp1table[*src++][bit];
1087 for (; bit < pixperbyte; bit++)
1088 *dest++ = *unpacksrc++;//copy bytes
1089 width -= pixperbyte;
1090 bit = 0;
1091 }
1092 }
1093 }
1094 for (pixel = margins * bytespp; pixel > 0; pixel--) {
1095 *dest++ = white; //margins are white
1096 }
1097 }
1098
1099
1100 /**********************************************************************
1101 * get_column
1102 *
1103 * Get a column of image into the supplied image line buffer.
1104 * The image is converted to 8bpp by simple assignment.
1105 **********************************************************************/
1106
get_column(inT32 x,inT32 y,inT32 height,IMAGELINE * linebuf,inT32 margins)1107 void IMAGE::get_column( //get image column
1108 inT32 x, //coord to start at
1109 inT32 y, //line to get
1110 inT32 height, //no of pixels to get
1111 IMAGELINE *linebuf, //line to copy to
1112 inT32 margins //size of margins
1113 ) {
1114 uinT8 *src; //source pointer
1115 uinT8 *dest; //destination pointer
1116 inT8 bit; //bit index
1117 inT8 pixperbyte; //pixels per byte
1118 uinT8 white; //white colour
1119 inT32 pixel; //pixel index
1120
1121 //test coords
1122 this->check_legal_access (x, y, 1);
1123 //test coords
1124 this->check_legal_access (x, y + height - 1, 1);
1125 if (height > ysize - y)
1126 height = ysize - y; //clip to image
1127 linebuf->init (height * bytespp + margins * bytespp * 2);
1128 //start of line
1129 src = image + xdim * (ymax - 1 - y);
1130 dest = linebuf->line; //destination line
1131 linebuf->pixels = dest;
1132 white = (1 << bpp) - 1; //max value of pixel
1133 for (pixel = margins * bytespp; pixel > 0; pixel--) {
1134 *dest++ = white; //margins are white
1135 }
1136 if (height > 0) {
1137 if (bpp == 24) {
1138 src += x * bytespp; //offset
1139 for (; height > 0; --height) {
1140 *dest++ = *src; //copy bytes
1141 *dest++ = *(src + 1);
1142 *dest++ = *(src + 2);
1143 src -= xdim;
1144 }
1145 }
1146 else if (bpp > 4) {
1147 src += x;
1148 for (; height > 0; --height) {
1149 *dest++ = *src; //copy bytes
1150 src -= xdim;
1151 }
1152 }
1153 else if (bpp == 4) {
1154 src += x / 2; //offset on line
1155 if (x & 1) {
1156 for (; height > 0; --height) {
1157 //get coded nibble
1158 *dest++ = bpp4table[*src][1];
1159 src -= xdim;
1160 }
1161 }
1162 else {
1163 for (; height > 0; --height) {
1164 //get coded nibble
1165 *dest++ = bpp4table[*src][0];
1166 src -= xdim;
1167 }
1168 }
1169 }
1170 else if (bpp == 2) {
1171 pixperbyte = 4;
1172 src += x / 4; //offset on line
1173 bit = (inT8) (x % 4); //offset in byte
1174 for (; height > 0; --height) {
1175 //get coded bits
1176 *dest++ = bpp2table[*src][bit];
1177 src -= xdim;
1178 }
1179 }
1180 else {
1181 pixperbyte = 8;
1182 src += x / 8; //offset on line
1183 bit = (inT8) (x % 8); //offset in byte
1184 for (; height > 0; --height) {
1185 //get coded bits
1186 *dest++ = bpp1table[*src][bit];
1187 src -= xdim;
1188 }
1189 }
1190 }
1191 for (pixel = margins * bytespp; pixel > 0; pixel--) {
1192 *dest++ = white; //margins are white
1193 }
1194 }
1195
1196
1197 /**********************************************************************
1198 * fast_put_line
1199 *
1200 * Put a line buffer back into the image.
1201 * If the line buffer merely points back into the image, nothing is done.
1202 * Otherwise, put_line is used to copy the line back.
1203 **********************************************************************/
1204
fast_put_line(inT32 x,inT32 y,inT32 width,IMAGELINE * linebuf)1205 void IMAGE::fast_put_line( //put image line
1206 inT32 x, //coord to start at
1207 inT32 y, //line to get
1208 inT32 width, //no of pixels to put
1209 IMAGELINE *linebuf //line to copy to
1210 ) {
1211 if (width > 0 && (bpp <= 4 || linebuf->pixels == linebuf->line))
1212 //just copy it
1213 put_line (x, y, width, linebuf, 0);
1214 }
1215
1216
1217 /**********************************************************************
1218 * put_line
1219 *
1220 * Put the supplied line buffer into the image.
1221 * The image is converted from 8bpp by simple assignment.
1222 **********************************************************************/
1223
put_line(inT32 x,inT32 y,inT32 width,IMAGELINE * linebuf,inT32 margins)1224 void IMAGE::put_line( //put image line
1225 inT32 x, //coord to start at
1226 inT32 y, //line to get
1227 inT32 width, //no of pixels to get
1228 IMAGELINE *linebuf, //line to copy to
1229 inT32 margins //margins in buffer
1230 ) {
1231 uinT8 *src; //source pointer
1232 uinT8 *dest; //destination pointer
1233 inT8 bit; //bit index
1234 uinT8 pixel; //collected bits
1235 inT8 pixperbyte; //pixels in a byte
1236 inT8 bytesperpix; //in source
1237
1238 this->check_legal_access (x, y, width);
1239 if (width > xsize - x)
1240 width = xsize - x; //clip to image
1241 if (width <= 0)
1242 return; //nothing to do
1243 //source line
1244 src = linebuf->pixels + margins;
1245 //start of line
1246 dest = image + xdim * (ymax - 1 - y);
1247
1248 if (linebuf->bpp == 24) {
1249 src++;
1250 bytesperpix = 3;
1251 }
1252 else
1253 bytesperpix = 1;
1254 if (bpp == 24 && linebuf->bpp == 24) {
1255 dest += x * bytespp;
1256 width *= bytespp;
1257 memmove (dest, src - 1, (unsigned) width);
1258 }
1259 else if (bpp == 24) {
1260 src--;
1261 dest += x * bytespp;
1262 while (width > 0) {
1263 pixel = *src++;
1264 *dest++ = pixel;
1265 *dest++ = pixel;
1266 *dest++ = pixel;
1267 width--;
1268 }
1269 }
1270 else if (bpp > 4) {
1271 dest += x; //offset
1272 if (linebuf->bpp == 24) {
1273 while (width > 0) {
1274 *dest++ = *src;
1275 src += 3;
1276 width--;
1277 }
1278 }
1279 else
1280 //easy way
1281 memmove (dest, src, (unsigned) width);
1282 }
1283 else if (bpp == 4) {
1284 dest += x / 2; //offset on line
1285 if (x & 1) {
1286 *dest &= 0xf0; //clean odd byte
1287 *dest++ |= *src & 0x0f; //and copy it
1288 src += bytesperpix;
1289 width--;
1290 }
1291 while (width >= 2) {
1292 pixel = *src << 4; //left pixel
1293 src += bytesperpix;
1294 pixel |= *src & 0x0f; //right pixel
1295 src += bytesperpix;
1296 *dest++ = pixel;
1297 width -= 2;
1298 }
1299 if (width) {
1300 *dest &= 0x0f; //clean odd byte
1301 *dest |= *src << 4;
1302 }
1303 }
1304 else if (bpp == 2) {
1305 pixperbyte = 4;
1306 dest += x / 4; //offset on line
1307 bit = (inT8) (x % 4); //offset in byte
1308 width += bit;
1309 pixel = *dest >> (8 - bit - bit);
1310 while (width >= 4) { //until all done
1311 for (; bit < 4; bit++) {
1312 pixel <<= 2; //make space for new one
1313 pixel |= *src & 3;
1314 src += bytesperpix;
1315 }
1316 *dest++ = pixel; //new pixel
1317 width -= 4;
1318 bit = 0;
1319 }
1320 if (width > 0) { //until all done
1321 for (bit = 0; bit < width; bit++) {
1322 pixel <<= 2; //make space for new one
1323 pixel |= *src & 3;
1324 src += bytesperpix;
1325 }
1326 pixel <<= (8 - bit - bit); //shift rest
1327 //keep trainling bits
1328 pixel |= *dest & ((1 << (8 - bit - bit)) - 1);
1329 *dest++ = pixel; //new pixel
1330 }
1331 }
1332 else {
1333 pixperbyte = 8;
1334 dest += x / 8; //offset on line
1335 bit = (inT8) (x % 8); //offset in byte
1336 width += bit;
1337 pixel = *dest >> (8 - bit);
1338 while (width >= 8) { //until all done
1339 for (; bit < 8; bit++) {
1340 pixel <<= 1; //make space for new one
1341 pixel |= *src & 1;
1342 src += bytesperpix;
1343 }
1344 *dest++ = pixel; //new pixel
1345 width -= 8;
1346 bit = 0;
1347 }
1348 width -= bit;
1349 if (width > 0) { //until all done
1350 while (width > 0) {
1351 pixel <<= 1; //make space for new one
1352 pixel |= *src & 1;
1353 src += bytesperpix;
1354 bit++;
1355 width--;
1356 }
1357 pixel <<= (8 - bit); //shift rest
1358 //keep trainling bits
1359 pixel |= *dest & ((1 << (8 - bit)) - 1);
1360 *dest++ = pixel; //new pixel
1361 }
1362 }
1363 }
1364
1365
1366 /**********************************************************************
1367 * put_column
1368 *
1369 * Put the supplied column buffer into the image.
1370 * The image is converted from 8bpp by simple assignment.
1371 **********************************************************************/
1372
put_column(inT32 x,inT32 y,inT32 height,IMAGELINE * linebuf,inT32 margins)1373 void IMAGE::put_column( //put image column
1374 inT32 x, //coord to start at
1375 inT32 y, //line to get
1376 inT32 height, //no of pixels to get
1377 IMAGELINE *linebuf, //line to copy to
1378 inT32 margins //margins in buffer
1379 ) {
1380 uinT8 *src; //source pointer
1381 uinT8 *dest; //destination pointer
1382 inT8 bit; //bit index
1383 uinT8 pixel; //collected bits
1384 inT8 bytesperpix; //in source
1385
1386 this->check_legal_access (x, y, 1);
1387 this->check_legal_access (x, y + height - 1, 1);
1388 if (height > ysize - y)
1389 height = ysize - y; //clip to image
1390 if (height <= 0)
1391 return; //nothing to do
1392 //source line
1393 src = linebuf->pixels + margins;
1394 //start of line
1395 dest = image + xdim * (ymax - 1 - y);
1396
1397 if (linebuf->bpp == 24) {
1398 src++;
1399 bytesperpix = 3;
1400 }
1401 else
1402 bytesperpix = 1;
1403
1404 if (bpp == 24 && linebuf->bpp == 24) {
1405 dest += x * bytesperpix;
1406 src--;
1407 for (; height > 0; --height) {
1408 *dest = *src++;
1409 *(dest + 1) = *src++;
1410 *(dest + 2) = *src++;
1411 dest -= xdim;
1412 }
1413 }
1414 else if (bpp == 24) {
1415 src--;
1416 dest += x * bytesperpix;
1417 for (; height > 0; --height) {
1418 pixel = *src++;
1419 *dest = pixel;
1420 *(dest + 1) = pixel;
1421 *(dest + 2) = pixel;
1422 dest -= xdim;
1423 }
1424 }
1425 else if (bpp > 4) {
1426 dest += x; //offset
1427 for (; height > 0; --height) {
1428 *dest = *src;
1429 src += bytesperpix;
1430 dest -= xdim;
1431 }
1432 }
1433 else if (bpp == 4) {
1434 dest += x / 2; //offset on line
1435 if (x & 1) {
1436 for (; height > 0; --height) {
1437 *dest &= 0xf0; //clean odd byte
1438 *dest |= *src & 0x0f; //and copy it
1439 src += bytesperpix;
1440 dest -= xdim;
1441 }
1442 }
1443 else {
1444 for (; height > 0; --height) {
1445 *dest &= 0x0f; //clean odd byte
1446 *dest |= *src << 4;
1447 src += bytesperpix;
1448 dest -= xdim;
1449 }
1450 }
1451 }
1452 else if (bpp == 2) {
1453 dest += x / 4; //offset on line
1454 bit = (inT8) (x % 4); //offset in byte
1455 bit = 6 - bit - bit; //bit shift
1456 pixel = ~(3 << bit); //mask
1457 for (; height > 0; --height) {
1458 //change 2 bits
1459 *dest = (*dest & pixel) | ((*src & 3) << bit);
1460 src += bytesperpix;
1461 dest -= xdim;
1462 }
1463 }
1464 else {
1465 dest += x / 8; //offset on line
1466 bit = (inT8) (x % 8); //offset in byte
1467 bit = 7 - bit;
1468 pixel = ~(1 << bit);
1469 for (; height > 0; --height) {
1470 //change 1 bit
1471 *dest = (*dest & pixel) | ((*src & 1) << bit);
1472 src += bytesperpix;
1473 dest -= xdim;
1474 }
1475 }
1476 }
1477
1478
1479 /**********************************************************************
1480 * check_legal_access
1481 *
1482 * Check that x,y are within the bounds of the image.
1483 * Call bufread if necessary to get the image into memory.
1484 **********************************************************************/
1485
check_legal_access(inT32 x,inT32 y,inT32 xext)1486 void IMAGE::check_legal_access( //check coords are legal
1487 inT32 x, //coords to check
1488 inT32 y,
1489 inT32 xext //xextent
1490 ) {
1491 if (x < 0 || x >= xsize || y < 0 || y >= ysize || x + xext > xsize)
1492 BADIMAGECOORDS.error ("IMAGE::check_legal_access",
1493 ABORT, "(%d+%d,%d)", x, xext, y);
1494 if (y >= ymax)
1495 BADIMAGESEEK.error ("IMAGE::check_legal_access", ABORT, "(%d,%d)", x, y);
1496 if (y < ymin)
1497 bufread(y); //read some more
1498 }
1499
1500 #ifdef HAVE_LIBLEPT
1501 // ONLY available if you have Leptonica installed.
1502 /**********************************************************************
1503 * ToPix
1504 *
1505 * Make a Pix from this image.
1506 **********************************************************************/
ToPix()1507 Pix* IMAGE::ToPix() {
1508 int width = this->get_xsize();
1509 int height = this->get_ysize();
1510 int bpp = this->get_bpp();
1511 Pix* pix = pixCreate(width, height, bpp == 24 ? 32 : bpp);
1512 l_uint32* data = pixGetData(pix);
1513 IMAGELINE line;
1514 if (bpp == 24) {
1515 line.init(width * 3);
1516 line.set_bpp(24);
1517 } else {
1518 line.init(width);
1519 }
1520 switch (bpp) {
1521 case 1:
1522 for (int y = height - 1 ; y >= 0; --y) {
1523 this->get_line(0, y, width, &line, 0);
1524 for (int x = 0; x < width; ++x) {
1525 if (line.pixels[x])
1526 CLEAR_DATA_BIT(data, x);
1527 else
1528 SET_DATA_BIT(data, x);
1529 }
1530 data += pixGetWpl(pix);
1531 }
1532 break;
1533
1534 case 8:
1535 // Greyscale just copies the bytes in the right order.
1536 for (int y = height - 1 ; y >= 0; --y) {
1537 this->get_line(0, y, width, &line, 0);
1538 for (int x = 0; x < width; ++x)
1539 SET_DATA_BYTE(data, x, line.pixels[x]);
1540 data += pixGetWpl(pix);
1541 }
1542 break;
1543
1544 case 24:
1545 // Put the colors in the correct places in the line buffer.
1546 for (int y = height - 1 ; y >= 0; --y) {
1547 this->get_line(0, y, width, &line, 0);
1548 for (int x = 0; x < width; ++x, ++data) {
1549 SET_DATA_BYTE(data, COLOR_RED, line[x][RED_PIX]);
1550 SET_DATA_BYTE(data, COLOR_GREEN, line[x][GREEN_PIX]);
1551 SET_DATA_BYTE(data, COLOR_BLUE, line[x][BLUE_PIX]);
1552 }
1553 }
1554 break;
1555
1556 default:
1557 tprintf("Cannot convert image to Pix with bpp = %d\n", bpp);
1558 }
1559 return pix;
1560 }
1561
1562 /**********************************************************************
1563 * FromPix
1564 *
1565 * Copy from the given Pix into this image.
1566 **********************************************************************/
FromPix(const Pix * src_pix)1567 void IMAGE::FromPix(const Pix* src_pix) {
1568 // Leptonica doesn't const its inputs, but we don't change the input.
1569 Pix* pix = const_cast<Pix*>(src_pix);
1570 Pix* destroy_this_pix = NULL;
1571
1572 int depth = pixGetDepth(pix);
1573 if (depth > 1 && depth < 8) {
1574 // Convert funny depths to 8 bit.
1575 destroy_this_pix = pixConvertTo8(pix, false);
1576 pix = destroy_this_pix;
1577 depth = pixGetDepth(pix);
1578 }
1579 int width = pixGetWidth(pix);
1580 int height = pixGetHeight(pix);
1581 const l_uint32* data = pixGetData(pix);
1582 this->create(width, height, depth == 32 ? 24 : depth);
1583 // For each line in the image, fill the IMAGELINE class and put it into the
1584 // destination image. Note that Tesseract stores images with the
1585 // bottom at y=0 and 0 is always black in grey and binary.
1586 IMAGELINE line;
1587 if (depth == 32) {
1588 line.init(width * 3);
1589 line.set_bpp(24);
1590 } else {
1591 line.init(width);
1592 }
1593 switch (depth) {
1594 case 1:
1595 // Binary images just flip the data bit.
1596 for (int y = height - 1 ; y >= 0; --y) {
1597 for (int x = 0; x < width; ++x)
1598 line.pixels[x] = GET_DATA_BIT(data, x) ^ 1;
1599 this->put_line(0, y, width, &line, 0);
1600 data += pixGetWpl(pix);
1601 }
1602 break;
1603
1604 case 8:
1605 // Greyscale just copies the bytes in the right order.
1606 for (int y = height - 1 ; y >= 0; --y) {
1607 for (int x = 0; x < width; ++x)
1608 line.pixels[x] = GET_DATA_BYTE(data, x);
1609 this->put_line(0, y, width, &line, 0);
1610 data += pixGetWpl(pix);
1611 }
1612 break;
1613
1614 case 32:
1615 // Put the colors in the correct places in the line buffer.
1616 for (int y = height - 1 ; y >= 0; --y) {
1617 for (int x = 0; x < width; ++x, ++data) {
1618 line[x][RED_PIX] = GET_DATA_BYTE(data, COLOR_RED);
1619 line[x][GREEN_PIX] = GET_DATA_BYTE(data, COLOR_GREEN);
1620 line[x][BLUE_PIX] = GET_DATA_BYTE(data, COLOR_BLUE);
1621 }
1622 this->put_line(0, y, width, &line, 0);
1623 }
1624 break;
1625
1626 default:
1627 tprintf("Cannot convert Pix to image with bpp = %d\n", depth);
1628 }
1629 if (destroy_this_pix != NULL)
1630 pixDestroy(&destroy_this_pix);
1631 }
1632 #endif // HAVE_LIBLEPT
1633
1634 /*************************************************************************
1635 * convolver()
1636 *
1637 * Calls the specified function for each pixel in the image, passing in an m x n
1638 * window of the image, centred on the pixel. The convolution function returns
1639 * a new value for the pixel, based on the window.
1640 *
1641 * At the edges of the image, the window is padded to white pixels.
1642 *************************************************************************/
1643
1644 void
convolver(inT32 win_width,inT32 win_height,void (* convolve)(uinT8 ** pixels,uinT8 bytespp,inT32 win_wd,inT32 win_ht,uinT8 ret_white_value,uinT8 * result))1645 IMAGE::convolver ( //Map fn over window
1646 inT32 win_width, //Window width
1647 inT32 win_height, //Window height
1648 void (*convolve) ( //Conv Function
1649 uinT8 ** pixels, //Of window
1650 uinT8 bytespp, //1 or 3 for colour
1651 inT32 win_wd, //Window width
1652 inT32 win_ht, //Window height
1653 uinT8 ret_white_value, //White value to RETURN
1654 uinT8 * result) //Ptr to result pix
1655 ) {
1656 IMAGELINE new_row; //Replacement pixels
1657 IMAGELINE *old_rows; //Rows being processed
1658 inT32 oldest_imline; //Next imline to replace
1659 uinT8 **window; //ptrs to pixel rows
1660 uinT8 **winmax; //ptrs to pixel rows
1661 uinT8 **win; //ptrs to pixel rows
1662 inT32 current_row; //Row being calculated
1663 inT32 current_col; //Col being calculated
1664 inT32 row = 0; //Next row to get
1665
1666 inT32 i, j;
1667 uinT8 *pix;
1668 uinT8 *max;
1669 inT32 xmargin = win_width / 2;
1670 inT32 ymargin = win_height / 2;
1671 uinT8 white = get_white_level ();
1672 const uinT8 max_white = 255;
1673 float white_scale = (float) 255 / get_white_level ();
1674
1675 if (((win_width % 2) == 0) ||
1676 ((win_height % 2) == 0) ||
1677 (win_height < 3) ||
1678 (win_width < 3) || (win_height > ysize / 2) || (win_width > xsize / 2))
1679 BADWINDOW.error ("IMAGE::convolver",
1680 ABORT, "(%d x %d)", win_width, win_height);
1681
1682 new_row.init (xsize * bytespp);
1683 new_row.set_bpp (bpp);
1684 old_rows = new IMAGELINE[win_height];
1685 for (i = 0; i < win_height; i++) {
1686 old_rows[i].init ((xsize + 2 * xmargin) * bytespp);
1687 old_rows[i].set_bpp (bpp);
1688 }
1689
1690 window = (uinT8 **) alloc_mem (win_height * sizeof (uinT8 *));
1691 winmax = window + win_height;
1692
1693 /* Make bottom border */
1694 for (oldest_imline = 0; oldest_imline < ymargin; oldest_imline++) {
1695 pix = old_rows[oldest_imline].pixels;
1696 max = pix + (xsize + 2 * xmargin) * bytespp;
1697 while (pix < max)
1698 *pix++ = max_white;
1699 }
1700 /* Initialise remaining rows but one*/
1701 for (; oldest_imline < win_height - 1; oldest_imline++) {
1702 get_line (0, row++, xsize, &old_rows[oldest_imline], xmargin);
1703 if (max_white != white) {
1704 pix = old_rows[oldest_imline].pixels;
1705 max = pix + (xsize + 2 * xmargin) * bytespp;
1706 while (pix < max) {
1707 *pix = (uinT8) (*pix * white_scale);
1708 ++pix;
1709 }
1710 }
1711 }
1712
1713 /* Image Processing */
1714
1715 for (current_row = 0; current_row < ysize;) {
1716 /* Get next row and re-initialise window array */
1717 if (row < ysize) {
1718 get_line (0, row++, xsize, &old_rows[oldest_imline], xmargin);
1719 if (max_white != white) {
1720 pix = old_rows[oldest_imline].pixels;
1721 max = pix + (xsize + 2 * xmargin) * bytespp;
1722 while (pix < max) {
1723 *pix = (uinT8) (*pix * white_scale);
1724 ++pix;
1725 }
1726 }
1727 }
1728 else {
1729 pix = old_rows[oldest_imline].pixels;
1730 max = pix + (xsize + 2 * xmargin) * bytespp;
1731 while (pix < max)
1732 *pix++ = max_white;
1733 }
1734 oldest_imline++;
1735 if (oldest_imline >= win_height)
1736 oldest_imline = 0;
1737
1738 /* Process line */
1739 pix = new_row.pixels;
1740 for (current_col = 0; current_col < xsize;) {
1741 /* Set up window ptrs */
1742 if (current_col == 0) {
1743 j = oldest_imline;
1744 for (i = 0; i < win_height; i++) {
1745 window[i] = old_rows[j++].pixels;
1746 if (j >= win_height)
1747 j = 0;
1748 }
1749 }
1750 else {
1751 for (win = window; win < winmax; (*win++) += bytespp);
1752 //Move along rows
1753 }
1754
1755 convolve(window, bytespp, win_width, win_height, white, pix);
1756 pix += bytespp;
1757 current_col++;
1758 }
1759
1760 put_line (0, current_row, xsize, &new_row, 0);
1761 new_row.init ();
1762 new_row.set_bpp (bpp);
1763 current_row++;
1764 }
1765 }
1766