Tesseract 3.02

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

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