Tesseract  3.02
tesseract-ocr/image/imgs.cpp
Go to the documentation of this file.
00001 /**********************************************************************
00002  * File:        imgs.c  (Formerly images.c)
00003  * Description: Main image manipulation functions.
00004  * Author:      Ray Smith
00005  * Created:     Thu Jun 07 16:25:02 BST 1990
00006  *
00007  * (C) Copyright 1990, Hewlett-Packard Ltd.
00008  ** Licensed under the Apache License, Version 2.0 (the "License");
00009  ** you may not use this file except in compliance with the License.
00010  ** You may obtain a copy of the License at
00011  ** http://www.apache.org/licenses/LICENSE-2.0
00012  ** Unless required by applicable law or agreed to in writing, software
00013  ** distributed under the License is distributed on an "AS IS" BASIS,
00014  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015  ** See the License for the specific language governing permissions and
00016  ** limitations under the License.
00017  *
00018  **********************************************************************/
00019 
00020 #include          "mfcpch.h"     //precompiled headers
00021 #ifdef _WIN32
00022 #include          <io.h>
00023 #else
00024 #include          <unistd.h>
00025 #endif
00026 #include          <string.h>
00027 #ifdef __UNIX__
00028 #include          <assert.h>
00029 #endif
00030 
00031 // Include automatically generated configuration file if running autoconf.
00032 #ifdef HAVE_CONFIG_H
00033 #include "config_auto.h"
00034 #endif
00035 
00036 #include "allheaders.h"
00037 
00038 #include          "stderr.h"
00039 #include          "tprintf.h"
00040 #include          "imgerrs.h"
00041 #include          "memry.h"
00042 #include          "imgs.h"
00043 #include          "imgunpk.h"
00044 
00045 #define FIXED_COLOURS   32       /*number of fixed colours */
00046 #define MIN_4BIT      48         /*4bpp range */
00047 #define MAX_4BIT      64
00048 #define MIN_6BIT      64         /*6bpp range */
00049 #define MAX_6BIT      128
00050 #define BLACK_PIX     0
00051 
00052 const uinT8 grey_scales[FIXED_COLOURS] = {
00053   0, 255, 76, 227, 151, 179, 28, 104,
00054   149, 72, 215, 67, 53, 44, 156, 137,
00055   110, 153, 79, 181, 166, 218, 55, 81,
00056   129, 105, 179, 149, 168, 69, 84, 126
00057 };
00058 
00059 #undef EXTERN
00060 #define EXTERN
00061 
00062 // Parameter remains truly global, as it is tough to make a member of Image
00063 // and the whole of this code is likely to go away in the future.
00064 EXTERN INT_VAR (image_default_resolution, 300, "Image resolution dpi");
00065 
00066 /**********************************************************************
00067  * IMAGE
00068  *
00069  * Contructor for an IMAGE class. Makes the image definitely illegal.
00070  **********************************************************************/
00071 
00072 IMAGE::IMAGE() {  //construct an image
00073   bpp = 0;                       //all illegal
00074   fd = -1;
00075   image = NULL;
00076   photo_interp = 1;
00077   res = image_default_resolution;
00078 }
00079 
00080 
00081 /**********************************************************************
00082  * IMAGE::operator=
00083  *
00084  * Assign an IMAGE to another. The dest becomes the owner of the memory.
00085  **********************************************************************/
00086 
00087 IMAGE & IMAGE::operator= (       //assignment
00088 IMAGE & source                   //source image
00089 ) {
00090   destroy();
00091   bpp = source.bpp;
00092   photo_interp = source.photo_interp;
00093   bps = source.bps;
00094   bytespp = (bpp + 7) / 8;
00095   lineskip = source.lineskip;    //copy everything
00096   captured = source.captured;
00097   xsize = source.xsize;
00098   ysize = source.ysize;
00099   res = source.res;
00100   image = source.image;
00101   xdim = source.xdim;
00102   bufheight = source.bufheight;
00103   fd = source.fd;
00104   reader = source.reader;
00105   ymin = source.ymin;
00106   ymax = source.ymax;
00107 
00108   source.captured = TRUE;        //source now captured
00109   source.fd = -1;
00110 
00111   return *this;
00112 }
00113 
00114 
00115 /**********************************************************************
00116  * create
00117  *
00118  * Create an image (allocate memory) of a specific size and bpp.
00119  **********************************************************************/
00120 
00121 inT8 IMAGE::create(                     //get rest of image
00122                    inT32 x,             //x size required
00123                    inT32 y,             //ysize required
00124                    inT8 bits_per_pixel  //bpp required
00125                   ) {
00126   uinT8 *pixels;                 //memory for image
00127 
00128   xdim = check_legal_image_size (x, y, bits_per_pixel);
00129   if (xdim < 0)
00130     return -1;
00131   pixels = (uinT8 *) alloc_big_zeros ((size_t) (xdim * y * sizeof (uinT8)));
00132   if (pixels == NULL) {
00133     MEMORY_OUT.error ("IMAGE::create", ABORT, "Size=(%d,%d)", xdim, y);
00134     return -1;
00135   }
00136                                  //allocate to image
00137   this->capture (pixels, x, y, bits_per_pixel);
00138   captured = FALSE;
00139   res = image_default_resolution;
00140   return 0;                      //success
00141 }
00142 
00143 
00144 /**********************************************************************
00145  * destroy
00146  *
00147  * Destroy an image, freeing memory and closing any open file.
00148  **********************************************************************/
00149 
00150 void IMAGE::destroy() {  //get rid of image
00151   if (image != NULL && !captured) {
00152     free_big_mem(image);
00153   }
00154   image = NULL;
00155   if (fd >= 0) {
00156     close(fd);
00157     fd = -1;
00158   }
00159   bpp = 0;
00160 }
00161 
00162 
00163 /**********************************************************************
00164  * capture
00165  *
00166  * Assign a given memory area to an image to use as an image of
00167  * given size and bpp.
00168  **********************************************************************/
00169 
00170 inT8 IMAGE::capture(                     //get rest of image
00171                     uinT8 *pixels,       //image memory
00172                     inT32 x,             //x size required
00173                     inT32 y,             //ysize required
00174                     inT8 bits_per_pixel  //bpp required
00175                    ) {
00176   destroy();
00177   xdim = check_legal_image_size (x, y, bits_per_pixel);
00178   if (xdim < 0)
00179     return -1;
00180   xsize = x;
00181   ysize = y;
00182   bufheight = y;
00183   bpp = bits_per_pixel;
00184   bps = bpp == 24 ? 8 : bpp;
00185   photo_interp = 1;
00186   bytespp = (bpp + 7) / 8;
00187   image = pixels;                //assign image area
00188   ymin = 0;
00189   ymax = bufheight;              //read it all
00190   captured = TRUE;
00191   res = image_default_resolution;
00192   return 0;                      //success
00193 }
00194 
00195 
00196 /**********************************************************************
00197  * pixel
00198  *
00199  * Get a single pixel out of the image.
00200  **********************************************************************/
00201 
00202 uinT8 IMAGE::pixel(          //get rest of image
00203                    inT32 x,  //x coord
00204                    inT32 y   //y coord
00205                   ) {
00206   if (x < 0)
00207     x = 0;                       //silently clip
00208   else if (x >= xsize)
00209     x = xsize - 1;
00210   if (y < 0)
00211     y = 0;
00212   else if (y >= ysize)
00213     y = ysize - 1;
00214   check_legal_access (x, y, 1);
00215   switch (bpp) {
00216     case 5:
00217     case 6:
00218     case 8:
00219       return image[(ymax - 1 - y) * xdim + x];
00220     case 4:
00221       return bpp4table[image[(ymax - 1 - y) * xdim + x / 2]][x & 1];
00222     case 2:
00223       return bpp2table[image[(ymax - 1 - y) * xdim + x / 4]][x & 3];
00224     case 1:
00225       return bpp1table[image[(ymax - 1 - y) * xdim + x / 8]][x & 7];
00226     default:
00227       tprintf ("Unexpected bits per pixel %d\n", bpp);
00228       return 0;
00229   }
00230 }
00231 
00232 
00233 /**********************************************************************
00234  * check_legal_image_size
00235  *
00236  * Check that the supplied image sizes are legal.  If they are,
00237  * the xdim is returned, else -1.
00238  **********************************************************************/
00239 
00240 inT32 check_legal_image_size(                     //get rest of image
00241                              inT32 x,             //x size required
00242                              inT32 y,             //ysize required
00243                              inT8 bits_per_pixel  //bpp required
00244                             ) {
00245   if (x <= 0 || y <= 0) {
00246     BADIMAGESIZE.error ("check_legal_image_size", TESSLOG, "(%d,%d)", x, y);
00247     return -1;                   //failed
00248   }
00249   if (bits_per_pixel != 1 && bits_per_pixel != 2
00250       && bits_per_pixel != 4 && bits_per_pixel != 5
00251       && bits_per_pixel != 6 && bits_per_pixel != 8 && bits_per_pixel != 24
00252       && bits_per_pixel != 32) {
00253     BADBPP.error ("check_legal_image_size", TESSLOG, "%d", bits_per_pixel);
00254     return -1;
00255   }
00256                                  //bytes per line
00257   return COMPUTE_IMAGE_XDIM (x, bits_per_pixel);
00258 }
00259 
00260 
00261 /**********************************************************************
00262  * copy_sub_image
00263  *
00264  * Copy a portion of one image to a portion of another image.
00265  * If the bpps are different, the position of the most significant
00266  * bit is preserved.
00267  **********************************************************************/
00268 
00269 DLLSYM void copy_sub_image(                   //copy rectangle
00270                            IMAGE *source,     //source image
00271                            inT32 xstart,      //start coords
00272                            inT32 ystart,
00273                            inT32 xext,        //extent to copy
00274                            inT32 yext,
00275                            IMAGE *dest,       //destination image
00276                            inT32 xdest,       //destination coords
00277                            inT32 ydest,
00278                            BOOL8 adjust_grey  //shift to new bpp
00279                           ) {
00280   IMAGELINE copyline;            //copy of line
00281   uinT8 *copy;                   //source pointer
00282   inT8 shift;                    //shift factor
00283   inT32 pixel;                   //pixel index
00284   inT32 y;                       //line index
00285   inT32 yoffset;                 //current adjusted offset
00286   inT32 bytesize;                //no of bytes to copy
00287   inT32 srcppb;                  //pixels per byte
00288   BOOL8 aligned;
00289 
00290   if (xstart < 0 || ystart < 0 || xdest < 0 || ydest < 0)
00291     return;
00292   if (xext <= 0)
00293     xext = source->xsize;        //default to all
00294   if (xext > source->xsize - xstart)
00295                                  //clip to smallest
00296       xext = source->xsize - xstart;
00297   if (xext > dest->xsize - xdest)
00298     xext = dest->xsize - xdest;
00299   if (yext <= 0)
00300     yext = source->ysize;        //default to all
00301   if (yext > source->ysize - ystart)
00302                                  //clip to smallest
00303       yext = source->ysize - ystart;
00304   if (yext > dest->ysize - ydest)
00305     yext = dest->ysize - ydest;
00306   if (xext <= 0 || yext <= 0)
00307     return;                      //nothing to do
00308 
00309   srcppb = 8 / source->bpp;      //pixels per byte
00310   if (source->bpp == dest->bpp || !adjust_grey)
00311     shift = 0;                   //no adjustment
00312   else {
00313     shift = source->bps - dest->bps;
00314     if (shift < 0)
00315       shift = -shift;            //keep positive
00316   }
00317   aligned = source->bpp == dest->bpp;
00318   if (aligned && srcppb != 0) {
00319     aligned = xstart % srcppb == 0
00320       && xdest % srcppb == 0
00321       && (xext % srcppb == 0 || xdest + xext == dest->xsize);
00322   }
00323   for (y = 0; y < yext; y++) {
00324     if (ystart >= ydest)
00325       yoffset = y;               //top down
00326     else
00327       yoffset = yext - y - 1;    //bottom up
00328     source->check_legal_access (xstart, ystart + yoffset, xext);
00329     dest->check_legal_access (xdest, ydest + yoffset, xext);
00330     if (aligned) {
00331       bytesize = COMPUTE_IMAGE_XDIM (xext, source->bpp);
00332       //get bytes per line
00333       if (srcppb == 0)
00334                                  //do cheap move
00335         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);
00336       else
00337                                  //do cheap move
00338         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);
00339     }
00340     else {
00341       if (shift == 0) {
00342         source->fast_get_line (xstart, ystart + yoffset, xext,
00343           &copyline);
00344       }
00345       else if (source->bpp < dest->bpp) {
00346         source->get_line (xstart, ystart + yoffset, xext, &copyline, 0);
00347         if (source->bpp <= shift
00348         && (source->bpp == 1 || source->bpp == 4)) {
00349           if (source->bpp == 1) {
00350             for (pixel = 0, copy = copyline.pixels; pixel < xext;
00351               pixel++, copy++)
00352             if (*copy)
00353               *copy = 0xff;
00354           }
00355           else {
00356             for (pixel = 0, copy = copyline.pixels; pixel < xext;
00357               pixel++, copy++)
00358                                  //scale up
00359             *copy = (*copy << shift) | *copy;
00360           }
00361         }
00362         else {
00363           for (pixel = 0, copy = copyline.pixels; pixel < xext;
00364             pixel++)
00365           *copy++ <<= shift;     //scale up
00366         }
00367       }
00368       else {
00369         source->get_line (xstart, ystart + yoffset, xext, &copyline, 0);
00370         if (source->bpp == 24) {
00371           for (pixel = 0, copy = copyline.pixels + 1; pixel < xext;
00372           pixel++) {
00373             *copy >>= shift;
00374             copy += 3;
00375           }
00376         }
00377         else {
00378           for (pixel = 0, copy = copyline.pixels; pixel < xext;
00379             pixel++)
00380           *copy++ >>= shift;     //scale down
00381         }
00382       }
00383       dest->put_line (xdest, ydest + yoffset, xext, &copyline, 0);
00384     }
00385   }
00386 }
00387 
00388 
00389 /**********************************************************************
00390  * enlarge_sub_image
00391  *
00392  * Enlarge a portion of one image to a portion of another image.
00393  * If the bpps are different, the position of the most significant
00394  * bit is preserved.
00395  **********************************************************************/
00396 
00397 DLLSYM void enlarge_sub_image(                   //enlarge rectangle
00398                               IMAGE *source,     //source image
00399                               inT32 xstart,      //scaled start coords
00400                               inT32 ystart,
00401                               IMAGE *dest,       //destination image
00402                               inT32 xdest,       //dest coords
00403                               inT32 ydest,
00404                               inT32 xext,        //destination extent
00405                               inT32 yext,
00406                               inT32 scale,       //scale factor
00407                               BOOL8 adjust_grey  //shift to new bpp
00408                              ) {
00409   inT8 shift;                    //shift factor
00410   uinT8 pixel;                   //current pixel
00411   inT32 srcext;                  //source extent
00412   inT32 xoffset;                 //column index
00413   inT32 yoffset;                 //line index
00414   inT32 xindex, yindex;          //index in super pixel
00415   inT32 startxindex;             //initial x index
00416   inT32 xscale;                  //x scale factor
00417   uinT8 *src;                    //source pixels
00418   uinT8 *destpix;                //dest pixels
00419   IMAGELINE copyline;            //copy of line
00420   IMAGELINE bigline;             //expanded line
00421 
00422   if (xstart < 0 || ystart < 0 || xdest < 0 || ydest < 0)
00423     return;
00424 
00425   if (xext <= 0)
00426     xext = dest->xsize;          //default to all
00427   if (xext > source->xsize * scale - xstart)
00428                                  //clip to smallest
00429     xext = source->xsize * scale - xstart;
00430   if (xext > dest->xsize - xdest)
00431     xext = dest->xsize - xdest;
00432   if (yext <= 0)
00433     yext = dest->ysize;          //default to all
00434   if (yext > source->ysize * scale - ystart)
00435     yext = source->ysize * scale - ystart;
00436   if (yext > dest->ysize - ydest)
00437     yext = dest->ysize - ydest;
00438   if (xext <= 0 || yext <= 0)
00439     return;                      //nothing to do
00440 
00441   xindex = xstart % scale;       //offset in super pixel
00442   startxindex = xindex;
00443   yindex = ystart % scale;
00444                                  //no of source pixels
00445   srcext = (xext + xindex + scale - 1) / scale;
00446   xstart /= scale;               //actual start
00447   ystart /= scale;
00448   if (adjust_grey) {
00449     shift = dest->bps - source->bps;
00450   }
00451   else
00452     shift = 0;                   //no adjustment
00453   bigline.init (xext * 3);
00454   bigline.bpp = dest->bpp == 24 ? source->bpp : dest->bpp;
00455 
00456   for (yoffset = 0; yoffset < yext; ystart++) {
00457     source->check_legal_access (xstart, ystart, srcext);
00458     dest->check_legal_access (xdest, ydest + yoffset, xext);
00459     source->fast_get_line (xstart, ystart, srcext, &copyline);
00460     src = copyline.pixels;
00461     destpix = bigline.pixels;
00462     xscale = scale;              //enlargement factor
00463     if (source->bpp == 24 && dest->bpp == 24) {
00464       for (xoffset = 0, xindex = startxindex; xoffset < xext;
00465       src += source->bytespp) {
00466         xoffset += xscale - xindex;
00467         if (xoffset > xext)
00468           xscale -= xoffset - xext;
00469         for (; xindex < xscale; xindex++) {
00470           *destpix++ = *src;
00471           *destpix++ = *(src + 1);
00472           *destpix++ = *(src + 2);
00473         }
00474         xindex = 0;
00475       }
00476     }
00477     else {
00478       if (source->bpp == 24)
00479         src++;
00480       for (xoffset = 0, xindex = startxindex; xoffset < xext;
00481       src += source->bytespp) {
00482         xoffset += xscale - xindex;
00483         if (xoffset > xext)
00484                                  //clip to dest limit
00485             xscale -= xoffset - xext;
00486         if (shift == 0)
00487           pixel = *src;
00488         else if (shift > 0)
00489           pixel = *src << shift;
00490         else
00491           pixel = *src >> (-shift);
00492         for (; xindex < xscale; xindex++)
00493           *destpix++ = pixel;    //duplicate pixel
00494         xindex = 0;
00495       }
00496     }
00497     for (; yoffset < yext && yindex < scale; yindex++, yoffset++) {
00498       dest->put_line (xdest, ydest + yoffset, xext, &bigline, 0);
00499     }
00500     yindex = 0;
00501   }
00502 }
00503 
00504 
00505 /**********************************************************************
00506  * fast_reduce_sub_image
00507  *
00508  * Reduce a portion of one image to a portion of another image.
00509  * If the bpps are different, the position of the most significant
00510  * bit is preserved.
00511  * This is a fast but dirty version, which simply sub-samples.
00512  * It does not smooth as it reduces.
00513  **********************************************************************/
00514 
00515 DLLSYM void fast_reduce_sub_image(                   //reduce rectangle
00516                                   IMAGE *source,     //source image
00517                                   inT32 xstart,      //start coords
00518                                   inT32 ystart,
00519                                   inT32 xext,        //extent to copy
00520                                   inT32 yext,
00521                                   IMAGE *dest,       //destination image
00522                                   inT32 xdest,       //destination coords
00523                                   inT32 ydest,
00524                                   inT32 scale,       //reduction factor
00525                                   BOOL8 adjust_grey  //shift to new bpp
00526                                  ) {
00527   inT8 shift;                    //shift factor
00528   inT32 xfactor;                 //run on x coord
00529   inT32 divisor;                 //total cell area
00530   inT32 xindex, yindex;          //into averaging square
00531   inT32 xcoord;                  //current x coord
00532   inT32 destext;                 //destination size
00533   inT32 yoffset;                 //current adjusted offset
00534   uinT8 *pixel;                  //ptr to source pixels
00535   inT32 *sums;                   //ptr to sums array
00536   IMAGELINE copyline;            //copy of line
00537   inT32 *linesums;               //averaging sums
00538 
00539   if (xstart < 0 || ystart < 0 || xdest < 0 || ydest < 0)
00540     return;
00541   if (xext <= 0)
00542     xext = source->xsize;        //default to all
00543   if (xext > source->xsize - xstart)
00544                                  //clip to smallest
00545       xext = source->xsize - xstart;
00546   if (xext > (dest->xsize - xdest) * scale)
00547     xext = (dest->xsize - xdest) * scale;
00548   if (yext <= 0)
00549     yext = source->ysize;        //default to all
00550   if (yext > source->ysize - ystart)
00551                                  //clip to smallest
00552       yext = source->ysize - ystart;
00553   if (yext > (dest->ysize - ydest) * scale)
00554     yext = (dest->ysize - ydest) * scale;
00555   if (xext <= 0 || yext <= 0)
00556     return;                      //nothing to do
00557 
00558   xfactor = xext % scale;        //left overs
00559   if (xfactor == 0)
00560     xfactor = scale;
00561                                  //destination pixels
00562   destext = (xext + scale - 1) / scale;
00563   if (adjust_grey)
00564                                  //shift factor
00565     shift = dest->bps - source->bps;
00566   else
00567     shift = 0;                   //no adjustment
00568   linesums = new inT32[destext * source->bytespp];
00569 
00570   for (yoffset = 0; yoffset < yext; ydest++) {
00571     source->check_legal_access (xstart, ystart + yoffset, xext);
00572     dest->check_legal_access (xdest, ydest, destext);
00573     for (xindex = destext * source->bytespp - 1; xindex >= 0; xindex--)
00574       linesums[xindex] = 0;      //zero sums
00575     for (yindex = 0; yindex < scale
00576     && ystart + yoffset < source->ysize; yindex += 3) {
00577       source->fast_get_line (xstart, ystart + yoffset, xext, &copyline);
00578       pixel = copyline.pixels;   //start of line
00579       if (source->bpp == 24) {
00580         for (xcoord = 1, sums = linesums; xcoord < destext;
00581         xcoord++, sums += 3) {
00582           for (xindex = 0; xindex < scale; xindex += 2) {
00583             *sums += *pixel++;
00584             *(sums + 1) += *pixel++;
00585             *(sums + 2) += *pixel++;
00586             pixel += 3;
00587           }
00588           if (scale & 1)
00589             pixel -= 3;          //correct position
00590         }
00591         for (xindex = 0; xindex < xfactor; xindex += 2) {
00592           *sums += *pixel++;
00593           *(sums + 1) += *pixel++;
00594           *(sums + 2) += *pixel++;
00595           pixel += 3;
00596         }
00597       }
00598       else {
00599         for (xcoord = 1, sums = linesums; xcoord < destext;
00600         xcoord++, sums++) {
00601           for (xindex = 0; xindex < scale; xindex += 2) {
00602             *sums += *pixel;
00603             pixel += 2;
00604           }
00605           if (scale & 1)
00606             pixel--;             //correct position
00607         }
00608         for (xindex = 0; xindex < xfactor; xindex += 2) {
00609           *sums += *pixel;
00610           pixel += 2;
00611         }
00612       }
00613       yoffset += 3;              //every 3 lines
00614     }
00615     if (yindex > scale)
00616       yoffset -= yindex - scale; //back on right scale
00617     copyline.init ();            //set pixels back to array
00618     copyline.bpp = source->bpp;
00619     pixel = copyline.pixels;
00620                                  //pixels in block
00621     divisor = ((yindex + 2) / 3) * ((scale + 1) / 2);
00622     if (shift <= 0) {
00623       divisor <<= (-shift);      //do greyscale correction
00624       for (sums = linesums, xindex = (destext - 1) * source->bytespp;
00625         xindex > 0; xindex--)
00626                                  //turn to destination value
00627       *pixel++ = (uinT8) (*sums++ / divisor);
00628       for (xindex = source->bytespp; xindex > 0; xindex--)
00629         *pixel++ = *sums++
00630           / (((yindex + 2) / 3) * ((xfactor + 1) / 2) << (-shift));
00631       //lastone different
00632     }
00633     else {
00634       for (sums = linesums, xindex = (destext - 1) * source->bytespp;
00635         xindex > 0; xindex--)
00636       *pixel++ = (uinT8) ((*sums++ << shift) / divisor);
00637       //destination value
00638       for (xindex = source->bytespp; xindex > 0; xindex--)
00639                                  //last one different
00640         *pixel++ = (*(sums++) << shift) / (((yindex + 2) / 3) * ((xfactor + 1) / 2));
00641     }
00642                                  //put in destination
00643     dest->put_line (xdest, ydest, destext, &copyline, 0);
00644   }
00645   delete [] linesums;
00646 }
00647 
00648 
00649 /**********************************************************************
00650  * reduce_sub_image
00651  *
00652  * Reduce a portion of one image to a portion of another image.
00653  * If the bpps are different, the position of the most significant
00654  * bit is preserved.
00655  **********************************************************************/
00656 
00657 DLLSYM void reduce_sub_image(                   //reduce rectangle
00658                              IMAGE *source,     //source image
00659                              inT32 xstart,      //start coords
00660                              inT32 ystart,
00661                              inT32 xext,        //extent to copy
00662                              inT32 yext,
00663                              IMAGE *dest,       //destination image
00664                              inT32 xdest,       //destination coords
00665                              inT32 ydest,
00666                              inT32 scale,       //reduction factor
00667                              BOOL8 adjust_grey  //shift to new bpp
00668                             ) {
00669   inT8 shift;                    //shift factor
00670   inT32 xfactor;                 //run on x coord
00671   inT32 divisor;                 //total cell area
00672   inT32 div2;                    //total cell area divided by 2
00673   inT32 xindex, yindex;          //into averaging square
00674   inT32 xcoord;                  //current x coord
00675   inT32 destext;                 //destination size
00676   inT32 yoffset;                 //current adjusted offset
00677   uinT8 *pixel;                  //ptr to source pixels
00678   inT32 *sums;                   //ptr to sums array
00679   IMAGELINE copyline;            //copy of line
00680   inT32 *linesums;               //averaging sums
00681 
00682   if (xstart < 0 || ystart < 0 || xdest < 0 || ydest < 0)
00683     return;
00684   if (xext <= 0)
00685     xext = source->xsize;        //default to all
00686   if (xext > source->xsize - xstart)
00687                                  //clip to smallest
00688       xext = source->xsize - xstart;
00689   if (xext > (dest->xsize - xdest) * scale)
00690     xext = (dest->xsize - xdest) * scale;
00691   if (yext <= 0)
00692     yext = source->ysize;        //default to all
00693   if (yext > source->ysize - ystart)
00694                                  //clip to smallest
00695       yext = source->ysize - ystart;
00696   if (yext > (dest->ysize - ydest) * scale)
00697     yext = (dest->ysize - ydest) * scale;
00698   if (xext <= 0 || yext <= 0)
00699     return;                      //nothing to do
00700 
00701   xfactor = xext % scale;        //left overs
00702   if (xfactor == 0)
00703     xfactor = scale;
00704                                  //destination pixels
00705   destext = (xext + scale - 1) / scale;
00706   if (adjust_grey)
00707                                  //shift factor
00708     shift = dest->bps - source->bps;
00709   else
00710     shift = 0;                   //no adjustment
00711   linesums = new inT32[destext * source->bytespp];
00712 
00713   for (yoffset = 0; yoffset < yext; ydest++) {
00714     source->check_legal_access (xstart, ystart + yoffset, xext);
00715     dest->check_legal_access (xdest, ydest, destext);
00716     for (xindex = 0; xindex < (destext) * source->bytespp; xindex++)
00717       linesums[xindex] = 0;      //zero sums
00718     for (yindex = 0; yindex < scale && ystart + yoffset < source->ysize;
00719     yindex++) {
00720       source->fast_get_line (xstart, ystart + yoffset, xext, &copyline);
00721       pixel = copyline.pixels;   //start of line
00722       if (source->bpp == 24) {
00723         for (xcoord = 1, sums = linesums; xcoord < destext;
00724         xcoord++, sums += 3) {
00725           for (xindex = 0; xindex < scale; xindex++) {
00726             *sums += *pixel++;
00727             *(sums + 1) += *pixel++;
00728             *(sums + 2) += *pixel++;
00729           }
00730         }
00731         for (xindex = 0; xindex < xfactor; xindex++) {
00732           *sums += *pixel++;
00733           *(sums + 1) += *pixel++;
00734           *(sums + 2) += *pixel++;
00735         }
00736       }
00737       else {
00738         for (xcoord = 1, sums = linesums; xcoord < destext;
00739         xcoord++, sums++) {
00740           for (xindex = 0; xindex < scale; xindex++)
00741             *sums += *pixel++;
00742         }
00743         for (xindex = 0; xindex < xfactor; xindex++)
00744           *sums += *pixel++;
00745       }
00746       yoffset++;                 //next line
00747     }
00748     copyline.init ();            //set pixels back to array
00749     copyline.set_bpp (source->bpp);
00750     pixel = copyline.pixels;
00751     divisor = yindex * scale;
00752     if (divisor == 0) {
00753       tprintf
00754         ("Impossible:divisor=0!, yindex=%d, scale=%d, yoffset=%d,yext=%d\n",
00755         yindex, scale, yoffset, yext);
00756       break;
00757     }
00758     if (shift <= 0) {
00759       divisor <<= (-shift);      //do greyscale correction
00760       div2 = divisor / 2;
00761       for (sums = linesums, xindex = (destext - 1) * source->bytespp;
00762         xindex > 0; xindex--)
00763       *pixel++ = (uinT8) ((div2 + *sums++) / divisor);
00764       //turn to destination value
00765       div2 = (yindex * xfactor << (-shift)) / 2;
00766       for (xindex = source->bytespp; xindex > 0; xindex--)
00767         *pixel++ =
00768           (uinT8) ((div2 + *sums++) / (yindex * xfactor << (-shift)));
00769       //lastone different
00770     }
00771     else {
00772       div2 = divisor / 2;
00773       for (sums = linesums, xindex = (destext - 1) * source->bytespp;
00774         xindex > 0; xindex--)
00775       *pixel++ = (uinT8) ((div2 + (*sums++ << shift)) / divisor);
00776       //destination value
00777       div2 = (yindex * xfactor) / 2;
00778       for (xindex = source->bytespp; xindex > 0; xindex--)
00779         *pixel++ =
00780           (uinT8) ((div2 + (*sums++ << shift)) / (yindex * xfactor));
00781       //last one different
00782     }
00783                                  //put in destination
00784     dest->put_line (xdest, ydest, destext, &copyline, 0);
00785   }
00786   delete [] linesums;
00787 }
00788 
00789 
00790 /**********************************************************************
00791  * invert_image
00792  *
00793  * Invert the given image (the slow way.)
00794  **********************************************************************/
00795 
00796 DLLSYM void invert_image(              /*invert the image */
00797                          IMAGE *image  /*image ot invert */
00798                         ) {
00799   uinT8 mask;                    //bit mask
00800   uinT8 bytespp;                 //bytes per pixel
00801   inT32 xsize, ysize;            /*size of image */
00802   inT32 xindex, yindex;          /*index into image */
00803   uinT8 *pixel;                  /*current pixel */
00804   IMAGELINE line;                /*line of image */
00805 
00806   bytespp = image->get_bpp () == 24 ? 3 : 1;
00807   xsize = image->get_xsize ();   /*find sizes */
00808   ysize = image->get_ysize ();
00809                                  //pixel mask
00810   mask = (1 << image->get_bpp ()) - 1;
00811                                  /*do each line */
00812   for (yindex = ysize - 1; yindex >= 0; yindex--) {
00813     image->fast_get_line (0, yindex, xsize, &line);
00814     for (pixel = line.pixels, xindex = xsize * bytespp; xindex > 0;
00815       xindex--) {
00816       *pixel = (*pixel) ^ mask;  //invert image only
00817       ++pixel;
00818     }
00819                                  /*put it back */
00820     image->fast_put_line (0, yindex, xsize, &line);
00821   }
00822 }
00823 
00824 
00825 /**********************************************************************
00826  * bias_sub_image
00827  *
00828  * Add a constant to a portion of an image.
00829  **********************************************************************/
00830 
00831 DLLSYM void bias_sub_image(                //bias rectangle
00832                            IMAGE *source,  //source image
00833                            inT32 xstart,   //start coords
00834                            inT32 ystart,
00835                            inT32 xext,     //extent to copy
00836                            inT32 yext,
00837                            uinT8 bias      //number to add
00838                           ) {
00839   IMAGELINE copyline;            //copy of line
00840   uinT8 *copy;                   //source pointer
00841   inT32 pixel;                   //pixel index
00842   inT32 y;                       //line index
00843   uinT8 bytespp;                 //bytes per pixel
00844 
00845   if (xstart < 0 || ystart < 0)
00846     return;
00847   if (xext <= 0)
00848     xext = source->get_xsize (); //default to all
00849   if (xext > source->get_xsize () - xstart)
00850                                  //clip to smallest
00851     xext = source->get_xsize () - xstart;
00852   if (yext <= 0)
00853     yext = source->get_ysize (); //default to all
00854   if (yext > source->get_ysize () - ystart)
00855                                  //clip to smallest
00856     yext = source->get_ysize () - ystart;
00857   if (xext <= 0 || yext <= 0)
00858     return;                      //nothing to do
00859 
00860   bytespp = source->get_bpp () == 24 ? 3 : 1;
00861   for (y = 0; y < yext; y++) {
00862     source->check_legal_access (xstart, ystart + y, xext);
00863     source->fast_get_line (xstart, ystart + y, xext, &copyline);
00864     for (pixel = xext * bytespp, copy = copyline.pixels; pixel > 0;
00865       pixel--, copy++)
00866     *copy += bias;               //add bias
00867 
00868     source->fast_put_line (xstart, ystart + y, xext, &copyline);
00869   }
00870 }
00871 
00872 
00873 /**********************************************************************
00874  * starbase_to_normal
00875  *
00876  * Copy a portion of one image to a portion of another image.
00877  * This function maps the colour tables used on the screen to
00878  * greyscale values in the way "normally" expected.
00879  **********************************************************************/
00880 
00881 DLLSYM void starbase_to_normal(                     //copy rectangle
00882                                IMAGE *source,       //source image
00883                                inT32 xstart,        //start coords
00884                                inT32 ystart,
00885                                inT32 xext,          //extent to copy
00886                                inT32 yext,
00887                                IMAGE *dest,         //destination image
00888                                inT32 xdest,         //destination coords
00889                                inT32 ydest,
00890                                BOOL8 preserve_grey  //shift to new bpp
00891                               ) {
00892   IMAGELINE copyline;            //copy of line
00893   uinT8 *copy;                   //source pointer
00894   inT8 shift4;                   //shift factor
00895   inT8 shift6;                   //shift factor
00896   inT8 colour_shift;             //shift of colours
00897   uinT8 white_level;             //dest white value
00898   inT32 pixel;                   //pixel index
00899   inT32 y;                       //line index
00900   inT32 yoffset;                 //current adjusted offset
00901   inT8 srcppb;                   //pixels per byte
00902 
00903   if (xstart < 0 || ystart < 0 || xdest < 0 || ydest < 0)
00904     return;
00905   if (xext <= 0)
00906     xext = source->get_xsize (); //default to all
00907   if (xext > source->get_xsize () - xstart)
00908                                  //clip to smallest
00909     xext = source->get_xsize () - xstart;
00910   if (xext > dest->get_xsize () - xdest)
00911     xext = dest->get_xsize () - xdest;
00912   if (yext <= 0)
00913     yext = source->get_ysize (); //default to all
00914   if (yext > source->get_ysize () - ystart)
00915                                  //clip to smallest
00916     yext = source->get_ysize () - ystart;
00917   if (yext > dest->get_ysize () - ydest)
00918     yext = dest->get_ysize () - ydest;
00919   if (xext <= 0 || yext <= 0)
00920     return;                      //nothing to do
00921 
00922                                  //pixels per byte
00923   srcppb = 8 / source->get_bpp ();
00924   shift4 = 4 - dest->get_bpp (); //for different bpps
00925   shift6 = 6 - dest->get_bpp ();
00926                                  //for grey preserve
00927   colour_shift = 8 - dest->get_bpp ();
00928   white_level = dest->get_white_level ();
00929   for (y = 0; y < yext; y++) {
00930     if (ystart >= ydest)
00931       yoffset = y;               //top down
00932     else
00933       yoffset = yext - y - 1;    //bottom up
00934     source->check_legal_access (xstart, ystart + yoffset, xext);
00935     dest->check_legal_access (xdest, ydest + yoffset, xext);
00936     source->get_line (xstart, ystart + yoffset, xext, &copyline, 0);
00937     for (pixel = 0, copy = copyline.pixels; pixel < xext; pixel++) {
00938       if (*copy < FIXED_COLOURS && preserve_grey)
00939         *copy = grey_scales[*copy] >> colour_shift;
00940       else if (*copy < FIXED_COLOURS) {
00941         if (*copy == BLACK_PIX)
00942           *copy = white_level;   //black->white
00943         else
00944           *copy = 0;             //others->black
00945       }
00946       else if (*copy >= MIN_4BIT && *copy < MAX_4BIT) {
00947         if (shift4 < 0)
00948           *copy = (*copy - MIN_4BIT) << (-shift4);
00949         else
00950           *copy = (*copy - MIN_4BIT) >> shift4;
00951       }
00952       else if (*copy >= MIN_6BIT && *copy < MAX_6BIT) {
00953         if (shift6 < 0)
00954           *copy = (*copy - MIN_6BIT) << (-shift6);
00955         else
00956           *copy = (*copy - MIN_6BIT) >> shift6;
00957       }
00958       else {
00959         *copy = white_level;     //white the rest
00960       }
00961       copy++;
00962     }
00963     dest->put_line (xdest, ydest + yoffset, xext, &copyline, 0);
00964   }
00965 }
00966 
00967 
00968 /**********************************************************************
00969  * fast_get_line
00970  *
00971  * Get a line of image into the supplied image line buffer.
00972  * The image is converted to 8bpp by simple assignment.
00973  * If the image is aleady 8 or 6bpp, no copy is done and a pointer
00974  * to the correct image section is put in the line buffer.
00975  **********************************************************************/
00976 
00977 void IMAGE::fast_get_line(                    //get image line
00978                           inT32 x,            //coord to start at
00979                           inT32 y,            //line to get
00980                           inT32 width,        //no of pixels to get
00981                           IMAGELINE *linebuf  //line to copy to
00982                          ) {
00983   if (width > 0 && bpp > 4) {
00984     check_legal_access(x, y, width);
00985                                  //get pointer only
00986     linebuf->pixels = image + xdim * (ymax - 1 - y) + x * bytespp;
00987   }
00988   else
00989                                  //just copy it
00990     this->get_line (x, y, width, linebuf, 0);
00991   linebuf->bpp = bpp;
00992 }
00993 
00994 
00995 /**********************************************************************
00996  * get_line
00997  *
00998  * Get a line of image into the supplied image line buffer.
00999  * The image is converted to 8bpp by simple assignment.
01000  **********************************************************************/
01001 
01002 void IMAGE::get_line(                     //get image line
01003                      inT32 x,             //coord to start at
01004                      inT32 y,             //line to get
01005                      inT32 width,         //no of pixels to get
01006                      IMAGELINE *linebuf,  //line to copy to
01007                      inT32 margins        //size of margins
01008                     ) {
01009   uinT8 *src;                    // source pointer
01010   uinT8 *dest;                   // destination pointer
01011   const uinT8 *unpacksrc;        // unpacking pointer
01012   inT8 bit;                      // bit index
01013   inT8 pixperbyte;               // pixels per byte
01014   uinT8 white;                   // white colour
01015   inT32 pixel;                   // pixel index
01016 
01017   this->check_legal_access (x, y, width);
01018   if (width > xsize - x)
01019     width = xsize - x;           //clip to image
01020   width *= bytespp;
01021   linebuf->init (width + margins * bytespp * 2);
01022   linebuf->bpp = bpp;
01023                                  //start of line
01024   src = image + xdim * (ymax - 1 - y);
01025   dest = linebuf->line;          //destination line
01026   linebuf->pixels = dest;
01027   white = (1 << bpp) - 1;        //max value of pixel
01028   for (pixel = margins * bytespp; pixel > 0; pixel--) {
01029     *dest++ = white;             //margins are white
01030   }
01031   if (width > 0) {
01032     if (bpp > 4) {
01033       src += x;                  //offset
01034                                  //easy way
01035       memmove (dest, src, (unsigned) width);
01036     }
01037     else if (bpp == 4) {
01038       src += x / 2;              //offset on line
01039       if (x & 1) {
01040                                  //get coded nibble
01041         *dest++ = bpp4table[*src++][1];
01042         width--;
01043       }
01044       while (width >= 2) {
01045                                  //get coded bits
01046         unpacksrc = bpp4table[*src++];
01047         *dest++ = *unpacksrc++;
01048         *dest++ = *unpacksrc++;  //copy nibbles
01049         width -= 2;
01050       }
01051       if (width) {
01052                                  //get coded nibble
01053         *dest++ = bpp4table[*src++][0];
01054       }
01055     }
01056     else if (bpp == 2) {
01057       pixperbyte = 4;
01058       src += x / 4;              //offset on line
01059       bit = (inT8) (x % 4);      //offset in byte
01060       width += bit;
01061       while (width > 0) {        //until all done
01062         if (width < pixperbyte)
01063                                  //less on last byte
01064           pixperbyte = (inT8) width;
01065                                  //get coded bits
01066         unpacksrc = &bpp2table[*src++][bit];
01067         for (; bit < pixperbyte; bit++)
01068           *dest++ = *unpacksrc++;//copy bytes
01069         width -= pixperbyte;
01070         bit = 0;
01071       }
01072     }
01073     else {
01074       pixperbyte = 8;
01075       src += x / 8;              //offset on line
01076       bit = (inT8) (x % 8);      //offset in byte
01077       width += bit;
01078       while (width > 0) {        //until all done
01079         if (width < pixperbyte)
01080                                  //less on last byte
01081           pixperbyte = (inT8) width;
01082                                  //get coded bits
01083         unpacksrc = &bpp1table[*src++][bit];
01084         for (; bit < pixperbyte; bit++)
01085           *dest++ = *unpacksrc++;//copy bytes
01086         width -= pixperbyte;
01087         bit = 0;
01088       }
01089     }
01090   }
01091   for (pixel = margins * bytespp; pixel > 0; pixel--) {
01092     *dest++ = white;             //margins are white
01093   }
01094 }
01095 
01096 
01097 /**********************************************************************
01098  * get_column
01099  *
01100  * Get a column of image into the supplied image line buffer.
01101  * The image is converted to 8bpp by simple assignment.
01102  **********************************************************************/
01103 
01104 void IMAGE::get_column(                     //get image column
01105                        inT32 x,             //coord to start at
01106                        inT32 y,             //line to get
01107                        inT32 height,        //no of pixels to get
01108                        IMAGELINE *linebuf,  //line to copy to
01109                        inT32 margins        //size of margins
01110                       ) {
01111   uinT8 *src;                    //source pointer
01112   uinT8 *dest;                   //destination pointer
01113   inT8 bit;                      //bit index
01114   inT8 pixperbyte;               //pixels per byte
01115   uinT8 white;                   //white colour
01116   inT32 pixel;                   //pixel index
01117 
01118                                  //test coords
01119   this->check_legal_access (x, y, 1);
01120                                  //test coords
01121   this->check_legal_access (x, y + height - 1, 1);
01122   if (height > ysize - y)
01123     height = ysize - y;          //clip to image
01124   linebuf->init (height * bytespp + margins * bytespp * 2);
01125                                  //start of line
01126   src = image + xdim * (ymax - 1 - y);
01127   dest = linebuf->line;          //destination line
01128   linebuf->pixels = dest;
01129   white = (1 << bpp) - 1;        //max value of pixel
01130   for (pixel = margins * bytespp; pixel > 0; pixel--) {
01131     *dest++ = white;             //margins are white
01132   }
01133   if (height > 0) {
01134     if (bpp == 24) {
01135       src += x * bytespp;        //offset
01136       for (; height > 0; --height) {
01137         *dest++ = *src;          //copy bytes
01138         *dest++ = *(src + 1);
01139         *dest++ = *(src + 2);
01140         src -= xdim;
01141       }
01142     }
01143     else if (bpp > 4) {
01144       src += x;
01145       for (; height > 0; --height) {
01146         *dest++ = *src;          //copy bytes
01147         src -= xdim;
01148       }
01149     }
01150     else if (bpp == 4) {
01151       src += x / 2;              //offset on line
01152       if (x & 1) {
01153         for (; height > 0; --height) {
01154                                  //get coded nibble
01155           *dest++ = bpp4table[*src][1];
01156           src -= xdim;
01157         }
01158       }
01159       else {
01160         for (; height > 0; --height) {
01161                                  //get coded nibble
01162           *dest++ = bpp4table[*src][0];
01163           src -= xdim;
01164         }
01165       }
01166     }
01167     else if (bpp == 2) {
01168       pixperbyte = 4;
01169       src += x / 4;              //offset on line
01170       bit = (inT8) (x % 4);      //offset in byte
01171       for (; height > 0; --height) {
01172                                  //get coded bits
01173         *dest++ = bpp2table[*src][bit];
01174         src -= xdim;
01175       }
01176     }
01177     else {
01178       pixperbyte = 8;
01179       src += x / 8;              //offset on line
01180       bit = (inT8) (x % 8);      //offset in byte
01181       for (; height > 0; --height) {
01182                                  //get coded bits
01183         *dest++ = bpp1table[*src][bit];
01184         src -= xdim;
01185       }
01186     }
01187   }
01188   for (pixel = margins * bytespp; pixel > 0; pixel--) {
01189     *dest++ = white;             //margins are white
01190   }
01191 }
01192 
01193 
01194 /**********************************************************************
01195  * fast_put_line
01196  *
01197  * Put a line buffer back into the image.
01198  * If the line buffer merely points back into the image, nothing is done.
01199  * Otherwise, put_line is used to copy the line back.
01200  **********************************************************************/
01201 
01202 void IMAGE::fast_put_line(                    //put image line
01203                           inT32 x,            //coord to start at
01204                           inT32 y,            //line to get
01205                           inT32 width,        //no of pixels to put
01206                           IMAGELINE *linebuf  //line to copy to
01207                          ) {
01208   if (width > 0 && (bpp <= 4 || linebuf->pixels == linebuf->line))
01209                                  //just copy it
01210     put_line (x, y, width, linebuf, 0);
01211 }
01212 
01213 
01214 /**********************************************************************
01215  * put_line
01216  *
01217  * Put the supplied line buffer into the image.
01218  * The image is converted from 8bpp by simple assignment.
01219  **********************************************************************/
01220 
01221 void IMAGE::put_line(                     //put image line
01222                      inT32 x,             //coord to start at
01223                      inT32 y,             //line to get
01224                      inT32 width,         //no of pixels to get
01225                      IMAGELINE *linebuf,  //line to copy to
01226                      inT32 margins        //margins in buffer
01227                     ) {
01228   uinT8 *src;                    //source pointer
01229   uinT8 *dest;                   //destination pointer
01230   inT8 bit;                      //bit index
01231   uinT8 pixel;                   //collected bits
01232   inT8 pixperbyte;               //pixels in a byte
01233   inT8 bytesperpix;              //in source
01234 
01235   this->check_legal_access (x, y, width);
01236   if (width > xsize - x)
01237     width = xsize - x;           //clip to image
01238   if (width <= 0)
01239     return;                      //nothing to do
01240                                  //source line
01241   src = linebuf->pixels + margins;
01242                                  //start of line
01243   dest = image + xdim * (ymax - 1 - y);
01244 
01245   if (linebuf->bpp == 24) {
01246     src++;
01247     bytesperpix = 3;
01248   }
01249   else
01250     bytesperpix = 1;
01251   if (bpp == 24 && linebuf->bpp == 24) {
01252     dest += x * bytespp;
01253     width *= bytespp;
01254     memmove (dest, src - 1, (unsigned) width);
01255   }
01256   else if (bpp == 24) {
01257     src--;
01258     dest += x * bytespp;
01259     while (width > 0) {
01260       pixel = *src++;
01261       *dest++ = pixel;
01262       *dest++ = pixel;
01263       *dest++ = pixel;
01264       width--;
01265     }
01266   }
01267   else if (bpp > 4) {
01268     dest += x;                   //offset
01269     if (linebuf->bpp == 24) {
01270       while (width > 0) {
01271         *dest++ = *src;
01272         src += 3;
01273         width--;
01274       }
01275     }
01276     else
01277                                  //easy way
01278       memmove (dest, src, (unsigned) width);
01279   }
01280   else if (bpp == 4) {
01281     dest += x / 2;               //offset on line
01282     if (x & 1) {
01283       *dest &= 0xf0;             //clean odd byte
01284       *dest++ |= *src & 0x0f;    //and copy it
01285       src += bytesperpix;
01286       width--;
01287     }
01288     while (width >= 2) {
01289       pixel = *src << 4;         //left pixel
01290       src += bytesperpix;
01291       pixel |= *src & 0x0f;      //right pixel
01292       src += bytesperpix;
01293       *dest++ = pixel;
01294       width -= 2;
01295     }
01296     if (width) {
01297       *dest &= 0x0f;             //clean odd byte
01298       *dest |= *src << 4;
01299     }
01300   }
01301   else if (bpp == 2) {
01302     pixperbyte = 4;
01303     dest += x / 4;               //offset on line
01304     bit = (inT8) (x % 4);        //offset in byte
01305     width += bit;
01306     pixel = *dest >> (8 - bit - bit);
01307     while (width >= 4) {         //until all done
01308       for (; bit < 4; bit++) {
01309         pixel <<= 2;             //make space for new one
01310         pixel |= *src & 3;
01311         src += bytesperpix;
01312       }
01313       *dest++ = pixel;           //new pixel
01314       width -= 4;
01315       bit = 0;
01316     }
01317     if (width > 0) {             //until all done
01318       for (bit = 0; bit < width; bit++) {
01319         pixel <<= 2;             //make space for new one
01320         pixel |= *src & 3;
01321         src += bytesperpix;
01322       }
01323       pixel <<= (8 - bit - bit); //shift rest
01324                                  //keep trainling bits
01325       pixel |= *dest & ((1 << (8 - bit - bit)) - 1);
01326       *dest++ = pixel;           //new pixel
01327     }
01328   }
01329   else {
01330     pixperbyte = 8;
01331     dest += x / 8;               //offset on line
01332     bit = (inT8) (x % 8);        //offset in byte
01333     width += bit;
01334     pixel = *dest >> (8 - bit);
01335     while (width >= 8) {         //until all done
01336       for (; bit < 8; bit++) {
01337         pixel <<= 1;             //make space for new one
01338         pixel |= *src & 1;
01339         src += bytesperpix;
01340       }
01341       *dest++ = pixel;           //new pixel
01342       width -= 8;
01343       bit = 0;
01344     }
01345     width -= bit;
01346     if (width > 0) {             //until all done
01347       while (width > 0) {
01348         pixel <<= 1;             //make space for new one
01349         pixel |= *src & 1;
01350         src += bytesperpix;
01351         bit++;
01352         width--;
01353       }
01354       pixel <<= (8 - bit);       //shift rest
01355                                  //keep trainling bits
01356       pixel |= *dest & ((1 << (8 - bit)) - 1);
01357       *dest++ = pixel;           //new pixel
01358     }
01359   }
01360 }
01361 
01362 
01363 /**********************************************************************
01364  * put_column
01365  *
01366  * Put the supplied column buffer into the image.
01367  * The image is converted from 8bpp by simple assignment.
01368  **********************************************************************/
01369 
01370 void IMAGE::put_column(                     //put image column
01371                        inT32 x,             //coord to start at
01372                        inT32 y,             //line to get
01373                        inT32 height,        //no of pixels to get
01374                        IMAGELINE *linebuf,  //line to copy to
01375                        inT32 margins        //margins in buffer
01376                       ) {
01377   uinT8 *src;                    //source pointer
01378   uinT8 *dest;                   //destination pointer
01379   inT8 bit;                      //bit index
01380   uinT8 pixel;                   //collected bits
01381   inT8 bytesperpix;              //in source
01382 
01383   this->check_legal_access (x, y, 1);
01384   this->check_legal_access (x, y + height - 1, 1);
01385   if (height > ysize - y)
01386     height = ysize - y;          //clip to image
01387   if (height <= 0)
01388     return;                      //nothing to do
01389                                  //source line
01390   src = linebuf->pixels + margins;
01391                                  //start of line
01392   dest = image + xdim * (ymax - 1 - y);
01393 
01394   if (linebuf->bpp == 24) {
01395     src++;
01396     bytesperpix = 3;
01397   }
01398   else
01399     bytesperpix = 1;
01400 
01401   if (bpp == 24 && linebuf->bpp == 24) {
01402     dest += x * bytesperpix;
01403     src--;
01404     for (; height > 0; --height) {
01405       *dest = *src++;
01406       *(dest + 1) = *src++;
01407       *(dest + 2) = *src++;
01408       dest -= xdim;
01409     }
01410   }
01411   else if (bpp == 24) {
01412     src--;
01413     dest += x * bytesperpix;
01414     for (; height > 0; --height) {
01415       pixel = *src++;
01416       *dest = pixel;
01417       *(dest + 1) = pixel;
01418       *(dest + 2) = pixel;
01419       dest -= xdim;
01420     }
01421   }
01422   else if (bpp > 4) {
01423     dest += x;                   //offset
01424     for (; height > 0; --height) {
01425       *dest = *src;
01426       src += bytesperpix;
01427       dest -= xdim;
01428     }
01429   }
01430   else if (bpp == 4) {
01431     dest += x / 2;               //offset on line
01432     if (x & 1) {
01433       for (; height > 0; --height) {
01434         *dest &= 0xf0;           //clean odd byte
01435         *dest |= *src & 0x0f;    //and copy it
01436         src += bytesperpix;
01437         dest -= xdim;
01438       }
01439     }
01440     else {
01441       for (; height > 0; --height) {
01442         *dest &= 0x0f;           //clean odd byte
01443         *dest |= *src << 4;
01444         src += bytesperpix;
01445         dest -= xdim;
01446       }
01447     }
01448   }
01449   else if (bpp == 2) {
01450     dest += x / 4;               //offset on line
01451     bit = (inT8) (x % 4);        //offset in byte
01452     bit = 6 - bit - bit;         //bit shift
01453     pixel = ~(3 << bit);         //mask
01454     for (; height > 0; --height) {
01455                                  //change 2 bits
01456       *dest = (*dest & pixel) | ((*src & 3) << bit);
01457       src += bytesperpix;
01458       dest -= xdim;
01459     }
01460   }
01461   else {
01462     dest += x / 8;               //offset on line
01463     bit = (inT8) (x % 8);        //offset in byte
01464     bit = 7 - bit;
01465     pixel = ~(1 << bit);
01466     for (; height > 0; --height) {
01467                                  //change 1 bit
01468       *dest = (*dest & pixel) | ((*src & 1) << bit);
01469       src += bytesperpix;
01470       dest -= xdim;
01471     }
01472   }
01473 }
01474 
01475 
01476 /**********************************************************************
01477  * check_legal_access
01478  *
01479  * Check that x,y are within the bounds of the image.
01480  * Call bufread if necessary to get the image into memory.
01481  **********************************************************************/
01482 
01483 void IMAGE::check_legal_access(            //check coords are legal
01484                                inT32 x,    //coords to check
01485                                inT32 y,
01486                                inT32 xext  //xextent
01487                               ) {
01488   if (x < 0 || x >= xsize || y < 0 || y >= ysize || x + xext > xsize)
01489     BADIMAGECOORDS.error ("IMAGE::check_legal_access",
01490       ABORT, "(%d+%d,%d)", x, xext, y);
01491   if (y < ymin || y >= ymax)
01492     BADIMAGESEEK.error ("IMAGE::check_legal_access", ABORT, "(%d,%d)", x, y);
01493 }
01494 
01495 /**********************************************************************
01496  * ToPix
01497  *
01498  * Make a Pix from this image.
01499  **********************************************************************/
01500 Pix* IMAGE::ToPix() {
01501   int width = this->get_xsize();
01502   int height = this->get_ysize();
01503   int bpp = this->get_bpp();
01504   Pix* pix = pixCreate(width, height, bpp == 24 ? 32 : bpp);
01505   l_uint32* data = pixGetData(pix);
01506   IMAGELINE line;
01507   if (bpp == 24) {
01508     line.init(width * 3);
01509     line.set_bpp(24);
01510   } else {
01511     line.init(width);
01512   }
01513   switch (bpp) {
01514   case 1:
01515     for (int y = height - 1 ; y >= 0; --y) {
01516       this->get_line(0, y, width, &line, 0);
01517       for (int x = 0; x < width; ++x) {
01518         if (line.pixels[x])
01519           CLEAR_DATA_BIT(data, x);
01520         else
01521           SET_DATA_BIT(data, x);
01522       }
01523       data += pixGetWpl(pix);
01524     }
01525     break;
01526 
01527   case 8:
01528     // Greyscale just copies the bytes in the right order.
01529     for (int y = height - 1 ; y >= 0; --y) {
01530       this->get_line(0, y, width, &line, 0);
01531       for (int x = 0; x < width; ++x)
01532         SET_DATA_BYTE(data, x, line.pixels[x]);
01533       data += pixGetWpl(pix);
01534     }
01535     break;
01536 
01537   case 24:
01538     // Put the colors in the correct places in the line buffer.
01539     for (int y = height - 1 ; y >= 0; --y) {
01540       this->get_line(0, y, width, &line, 0);
01541       for (int x = 0; x < width; ++x, ++data) {
01542         SET_DATA_BYTE(data, COLOR_RED, line[x][RED_PIX]);
01543         SET_DATA_BYTE(data, COLOR_GREEN, line[x][GREEN_PIX]);
01544         SET_DATA_BYTE(data, COLOR_BLUE, line[x][BLUE_PIX]);
01545       }
01546     }
01547     break;
01548 
01549   default:
01550     tprintf("Cannot convert image to Pix with bpp = %d\n", bpp);
01551   }
01552   return pix;
01553 }
01554 
01555 /**********************************************************************
01556  * FromPix
01557  *
01558  * Copy from the given Pix into this image.
01559  **********************************************************************/
01560 void IMAGE::FromPix(const Pix* src_pix) {
01561   // Leptonica doesn't const its inputs, but we don't change the input.
01562   Pix* pix = const_cast<Pix*>(src_pix);
01563   Pix* destroy_this_pix = NULL;
01564 
01565   int depth = pixGetDepth(pix);
01566   if (depth > 1 && depth < 8) {
01567     // Convert funny depths to 8 bit.
01568     destroy_this_pix = pixConvertTo8(pix, false);
01569     pix = destroy_this_pix;
01570     depth = pixGetDepth(pix);
01571   }
01572   int width = pixGetWidth(pix);
01573   int height = pixGetHeight(pix);
01574   const l_uint32* data = pixGetData(pix);
01575   this->create(width, height, depth == 32 ? 24 : depth);
01576   // For each line in the image, fill the IMAGELINE class and put it into the
01577   // destination image. Note that Tesseract stores images with the
01578   // bottom at y=0 and 0 is always black in grey and binary.
01579   IMAGELINE line;
01580   if (depth == 32) {
01581     line.init(width * 3);
01582     line.set_bpp(24);
01583   } else {
01584     line.init(width);
01585   }
01586   switch (depth) {
01587   case 1:
01588     // Binary images just flip the data bit.
01589     for (int y = height - 1 ; y >= 0; --y) {
01590       for (int x = 0; x < width; ++x)
01591         line.pixels[x] = GET_DATA_BIT((void *)data, x) ^ 1;
01592       this->put_line(0, y, width, &line, 0);
01593       data += pixGetWpl(pix);
01594     }
01595     break;
01596 
01597   case 8:
01598     // Greyscale just copies the bytes in the right order.
01599     for (int y = height - 1 ; y >= 0; --y) {
01600       for (int x = 0; x < width; ++x)
01601         line.pixels[x] = GET_DATA_BYTE((void *)data, x);
01602       this->put_line(0, y, width, &line, 0);
01603       data += pixGetWpl(pix);
01604     }
01605     break;
01606 
01607   case 32:
01608     // Put the colors in the correct places in the line buffer.
01609     for (int y = height - 1 ; y >= 0; --y) {
01610       for (int x = 0; x < width; ++x, ++data) {
01611         line[x][RED_PIX] = GET_DATA_BYTE((void *)data, COLOR_RED);
01612         line[x][GREEN_PIX] = GET_DATA_BYTE((void *)data, COLOR_GREEN);
01613         line[x][BLUE_PIX] = GET_DATA_BYTE((void *)data, COLOR_BLUE);
01614       }
01615       this->put_line(0, y, width, &line, 0);
01616     }
01617     break;
01618 
01619   default:
01620     tprintf("Cannot convert Pix to image with bpp = %d\n", depth);
01621   }
01622   if (destroy_this_pix != NULL)
01623     pixDestroy(&destroy_this_pix);
01624 }
01625 
01626 /*************************************************************************
01627  * convolver()
01628  *
01629  * Calls the specified function for each pixel in the image, passing in an m x n
01630  * window of the image, centred on the pixel.  The convolution function returns
01631  * a new value for the pixel, based on the window.
01632  *
01633  * At the edges of the image, the window is padded to white pixels.
01634  *************************************************************************/
01635 
01636 void
01637 IMAGE::convolver (               //Map fn over window
01638 inT32 win_width,                 //Window width
01639 inT32 win_height,                //Window height
01640 void (*convolve) (               //Conv Function
01641 uinT8 ** pixels,                 //Of window
01642 uinT8 bytespp,                   //1 or 3 for colour
01643 inT32 win_wd,                    //Window width
01644 inT32 win_ht,                    //Window height
01645 uinT8 ret_white_value,           //White value to RETURN
01646 uinT8 * result)                  //Ptr to result pix
01647 ) {
01648   IMAGELINE new_row;             //Replacement pixels
01649   IMAGELINE *old_rows;           //Rows being processed
01650   inT32 oldest_imline;           //Next imline to replace
01651   uinT8 **window;                //ptrs to pixel rows
01652   uinT8 **winmax;                //ptrs to pixel rows
01653   uinT8 **win;                   //ptrs to pixel rows
01654   inT32 current_row;             //Row being calculated
01655   inT32 current_col;             //Col being calculated
01656   inT32 row = 0;                 //Next row to get
01657 
01658   inT32 i, j;
01659   uinT8 *pix;
01660   uinT8 *max;
01661   inT32 xmargin = win_width / 2;
01662   inT32 ymargin = win_height / 2;
01663   uinT8 white = get_white_level ();
01664   const uinT8 max_white = 255;
01665   float white_scale = (float) 255 / get_white_level ();
01666 
01667   if (((win_width % 2) == 0) ||
01668     ((win_height % 2) == 0) ||
01669     (win_height < 3) ||
01670     (win_width < 3) || (win_height > ysize / 2) || (win_width > xsize / 2))
01671     BADWINDOW.error ("IMAGE::convolver",
01672       ABORT, "(%d x %d)", win_width, win_height);
01673 
01674   new_row.init (xsize * bytespp);
01675   new_row.set_bpp (bpp);
01676   old_rows = new IMAGELINE[win_height];
01677   for (i = 0; i < win_height; i++) {
01678     old_rows[i].init ((xsize + 2 * xmargin) * bytespp);
01679     old_rows[i].set_bpp (bpp);
01680   }
01681 
01682   window = (uinT8 **) alloc_mem (win_height * sizeof (uinT8 *));
01683   winmax = window + win_height;
01684 
01685   /* Make bottom border */
01686   for (oldest_imline = 0; oldest_imline < ymargin; oldest_imline++) {
01687     pix = old_rows[oldest_imline].pixels;
01688     max = pix + (xsize + 2 * xmargin) * bytespp;
01689     while (pix < max)
01690       *pix++ = max_white;
01691   }
01692   /* Initialise remaining rows but one*/
01693   for (; oldest_imline < win_height - 1; oldest_imline++) {
01694     get_line (0, row++, xsize, &old_rows[oldest_imline], xmargin);
01695     if (max_white != white) {
01696       pix = old_rows[oldest_imline].pixels;
01697       max = pix + (xsize + 2 * xmargin) * bytespp;
01698       while (pix < max) {
01699         *pix = (uinT8) (*pix * white_scale);
01700         ++pix;
01701       }
01702     }
01703   }
01704 
01705   /* Image Processing */
01706 
01707   for (current_row = 0; current_row < ysize;) {
01708     /* Get next row and re-initialise window array */
01709     if (row < ysize) {
01710       get_line (0, row++, xsize, &old_rows[oldest_imline], xmargin);
01711       if (max_white != white) {
01712         pix = old_rows[oldest_imline].pixels;
01713         max = pix + (xsize + 2 * xmargin) * bytespp;
01714         while (pix < max) {
01715           *pix = (uinT8) (*pix * white_scale);
01716           ++pix;
01717         }
01718       }
01719     }
01720     else {
01721       pix = old_rows[oldest_imline].pixels;
01722       max = pix + (xsize + 2 * xmargin) * bytespp;
01723       while (pix < max)
01724         *pix++ = max_white;
01725     }
01726     oldest_imline++;
01727     if (oldest_imline >= win_height)
01728       oldest_imline = 0;
01729 
01730     /* Process line */
01731     pix = new_row.pixels;
01732     for (current_col = 0; current_col < xsize;) {
01733       /* Set up window ptrs */
01734       if (current_col == 0) {
01735         j = oldest_imline;
01736         for (i = 0; i < win_height; i++) {
01737           window[i] = old_rows[j++].pixels;
01738           if (j >= win_height)
01739             j = 0;
01740         }
01741       }
01742       else {
01743         for (win = window; win < winmax; (*win++) += bytespp);
01744         //Move along rows
01745       }
01746 
01747       convolve(window, bytespp, win_width, win_height, white, pix);
01748       pix += bytespp;
01749       current_col++;
01750     }
01751 
01752     put_line (0, current_row, xsize, &new_row, 0);
01753     new_row.init ();
01754     new_row.set_bpp (bpp);
01755     current_row++;
01756   }
01757 }