Tesseract  3.02
 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 
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;
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;
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;
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  **********************************************************************/
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 }