• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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           &copyline);
346       }
347       else if (source->bpp < dest->bpp) {
348         source->get_line (xstart, ystart + yoffset, xext, &copyline, 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, &copyline, 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, &copyline, 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, &copyline);
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, &copyline);
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, &copyline, 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, &copyline);
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, &copyline, 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, &copyline);
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, &copyline);
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, &copyline, 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, &copyline, 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