Tesseract
3.02
|
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 ©line); 00344 } 00345 else if (source->bpp < dest->bpp) { 00346 source->get_line (xstart, ystart + yoffset, xext, ©line, 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, ©line, 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, ©line, 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, ©line); 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, ©line); 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, ©line, 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, ©line); 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, ©line, 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, ©line); 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, ©line); 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, ©line, 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, ©line, 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 }