00001 00002 00003 00004 00005 00006 00007 00008 00009 00010 00011 00012 00013 00014 00015 00016 00017 00018 00019
00020
00021 #include "config.h"
00022 #include "_gocr.h"
00023 #include "gocr.h"
00024 #include <string.h>
00025 #ifdef HAVE_PAM_H
00026 #include <pam.h>
00027 #endif
00028 #if defined HAVE_PNM_H && !defined HAVE_PAM_H
00029 #include <pnm.h>
00030 #endif
00031
00032 gocrImage *currentimage = NULL;
00033
00034 00035
00036
00049 int _gocr_imageSharedCopy ( gocrImage *orig, int x0, int y0, int x1, int y1,
00050 gocrImage *new ) {
00051 int i;
00052
00053 _gocr_debug(3, fprintf(_data.error,
00054 "_gocr_imageSharedCopy(%p, %d, %d, %d, %d, %p)\n",
00055 orig, x0, y0, x1, y1, new);)
00056
00057 if ( orig == NULL ) {
00058 _gocr_debug(1, fprintf(_data.error, "NULL pointer at _gocr_imageSharedCopy\n");)
00059 return -1;
00060 }
00061
00062 _gocr_fixParameters ( &x0, &y0, &x1, &y1 );
00063 if ( x0 < 0 || x1 >= orig->x || y0 < 0 || y1 >= orig->y ) {
00064 _gocr_debug(1, fprintf(_data.error, "_gocr_imageSharedCopy: data OOB\n");)
00065 return -1;
00066 }
00067
00068 if ( new == NULL ) {
00069 new = (gocrImage *)malloc(sizeof(gocrImage));
00070 if ( new == NULL ) {
00071 _gocr_debug(1, fprintf(_data.error, "gocr_imageSharedCopy NULL malloc\n");)
00072 return -1;
00073 }
00074 }
00075 else
00076 _gocr_debug(2, fprintf(_data.error,
00077 "gocr_imageSharedCopy got a non NULL structure; memory waste may occur\n");)
00078
00079 new->filename = NULL;
00080 new->x = x1 - x0 + 1;
00081 new->y = y1 - y0 + 1;
00082 new->type = orig->type;
00083 new->data = (gocrPixel **)malloc(new->x * sizeof(gocrPixel *));
00084 if ( new->data == NULL ) {
00085 _gocr_debug(1, fprintf(_data.error, "_gocr_imageSharedCopy: NULL malloc\n");)
00086 return -1;
00087 }
00088
00089 for ( i = 0; i < new->x; i++ )
00090 new->data[i] = &orig->data[i + x0][y0];
00091
00092 list_init(&new->blocklist);
00093 return 0;
00094 }
00095
00108 /* */
00109 int _gocr_imageCopy ( gocrImage *orig, int x0, int y0, int x1, int y1,
00110 gocrImage *new ) {
00111 int i;
00112
00113 _gocr_debug(3, fprintf(_data.error,
00114 "_gocr_imageCopy(%p, %d, %d, %d, %d, %p)\n",
00115 orig, x0, y0, x1, y1, new);)
00116
00117 if ( orig == NULL ) {
00118 _gocr_debug(1, fprintf(_data.error, "NULL pointer at _gocr_imageCopy\n");)
00119 return -1;
00120 }
00121
00122 _gocr_fixParameters ( &x0, &y0, &x1, &y1 );
00123 if ( x0 < 0 || x1 >= orig->x || y0 < 0 || y1 >= orig->y ) {
00124 _gocr_debug(1, fprintf(_data.error, "_gocr_imageCopy: data OOB\n");)
00125 return -1;
00126 }
00127
00128 if ( new == NULL ) {
00129 new = (gocrImage *)malloc(sizeof(gocrImage));
00130 if ( new == NULL ) {
00131 _gocr_debug(1, fprintf(_data.error, "gocr_imageCopy NULL malloc\n");)
00132 return -1;
00133 }
00134 }
00135 new->filename = NULL;
00136 new->x = x1 - x0 + 1;
00137 new->y = y1 - y0 + 1;
00138 new->type = orig->type;
00139 new->data = (gocrPixel **)malloc(new->x * sizeof(gocrPixel *));
00140 if ( new->data == NULL ) {
00141 _gocr_debug(1, fprintf(_data.error, "_gocr_imageCopy: NULL malloc\n");)
00142 return -1;
00143 }
00144
00145 for ( i = 0; i < new->x; i++ ) {
00146 new->data[i] = (gocrPixel *)malloc(new->y * sizeof(gocrPixel));
00147 if ( new->data[i] == NULL ) {
00148 _gocr_debug(1, fprintf(_data.error, "_gocr_imageCopy: NULL malloc[]\n");)
00149 for ( i--; i >= 0; i-- ) {
00150 free(new->data[i]);
00151 free(new);
00152 }
00153 return -1;
00154 }
00155 memcpy(new->data[i], &orig->data[i + x0][y0], new->y);
00156 }
00157
00158 list_init(&new->blocklist);
00159 return 0;
00160 }
00161
00171 void _gocr_fixParameters ( int *x0, int *x1, int *y0, int *y1 ) {
00172 if ( *x0 <= *x1 && *y0 <= *y1 ) /* OK */
00173 return;
00174
00175 if ( *x0 > *x1 && *y0 > *y1 ) { /* then swap the pairs */
00176 int i;
00177 i = *x0; *x0 = *x1; *x1 = i;
00178 i = *y0; *y0 = *y1; *y1 = i;
00179 return;
00180 }
00181
00182 if ( *x0 > *x1 && *y0 <= *y1 ) { /* correct is (x1,y0), (x0,y1) */
00183 int i;
00184 i = *x0; *x0 = *x1; *x1 = i;
00185 return;
00186 }
00187
00188 if ( *x0 <= *x1 && *y0 > *y1 ) { /* correct is (x0,y1), (x1,y0) */
00189 int i;
00190 i = *y0; *y0 = *y1; *y1 = i;
00191 return;
00192 }
00193 }
00194
00195 /*
00196 feel free to expand this list of usable converting programs
00197 Note 1: the last field must be NULL.
00198 Note 2: "smaller" extensions must come later: ".pnm.gz" must come
00199 before ".pnm".
00200 */
00201 static const char *xlist[]={
00202 ".pnm.gz", "gzip -cd",
00203 ".pbm.gz", "gzip -cd",
00204 ".pgm.gz", "gzip -cd",
00205 ".ppm.gz", "gzip -cd",
00206 ".pnm.bz2", "bzip2 -cd",
00207 ".pbm.bz2", "bzip2 -cd",
00208 ".pgm.bz2", "bzip2 -cd",
00209 ".ppm.bz2", "bzip2 -cd",
00210 ".jpg", "djpeg -gray -pnm",
00211 ".jpeg", "djpeg -gray -pnm",
00212 ".gif", "giftopnm",
00213 ".bmp", "bmptoppm",
00214 ".tiff", "tifftopnm",
00215 ".png", "pngtopnm",
00216 NULL
00217 };
00218
00219 /* return a pointer to command converting file to pnm or NULL */
00220 static const char *testsuffix ( const char *name ) {
00221 int i;
00222
00223 for ( i = 0; xlist[i] != NULL; i += 2 ) {
00224 if ( strstr( name, xlist[i] ) != NULL )
00225 return xlist[i+1];
00226 }
00227 return NULL;
00228 }
00229
00238 int gocr_imageLoad ( const char *filename ) {
00239 const char *command;
00240 unsigned char **data;
00241 FILE *fp;
00242 int row, col, i;
00243 #ifdef HAVE_PAM_H
00244 struct pam inpam;
00245 tuple *tuplerow;
00246 #endif
00247
00248 _gocr_debug(3, fprintf(_data.error, "gocr_imageLoad(%s)\n", filename);)
00249
00250 /* open file; test if conversion is needed. */
00251 command = testsuffix( filename );
00252 if ( !command ) {
00253 fp = fopen(filename, "rb");
00254 if (!fp) {
00255 _gocr_debug(1, fprintf(_data.error, "File %s couldn't be opened\n", filename);)
00256 return -1;
00257 }
00258 }
00259 else {
00260 char *buf = (char *)malloc((strlen(command)+strlen(filename)+2)*sizeof(char));
00261
00262 sprintf(buf, "%s %s", buf, filename);
00263 _gocr_debug(3, fprintf(_data.error, "# popen( %s )\n", buf);)
00264 #if defined(__USE_POSIX2)
00265 fp = popen(buf, "r");
00266 #else
00267 _gocr_debug(0, fprintf(_data.error, "Sorry, you must compile with __USE_POSIX2 to use pipes\n"
00268 "Cannot open this file format without pipes\n");)
00269 #endif
00270 if (!fp)
00271 _gocr_debug(1, fprintf(_data.error, "opening pipe %s\n", buf);)
00272
00273 free(buf);
00274 }
00275
00276 /* do we have an image? If so, close it first */
00277 if ( currentimage )
00278 gocr_imageClose();
00279
00280 /* read file */
00281 /* Ok, I'll explain my dirty trick to save lots of memory: I cast img.data
00282 to (unsigned char **), read the image into it and filter. The monochrome
00283 conversor then is called with a threshold and takes care of filling the
00284 image.data.value fields correctly and zeroing all other fields. Confusing?
00285 Yes, a bit. But the nice method would take two times the memory we use now.
00286 Of course, a change in the size of gocrPixel is a disaster. Read the
00287 developers.txt file. */
00288
00289 /* allocate memory */
00290 currentimage = (gocrImage *)malloc(sizeof(gocrImage));
00291 if ( currentimage == NULL ) {
00292 _gocr_debug(1, fprintf(_data.error, "gocr_loadImage NULL malloc\n");)
00293 return -1;
00294 }
00295
00296 #ifdef HAVE_PAM_H
00297 pnm_readpaminit(fp, &inpam, sizeof(inpam));
00298
00299 /* allocate memory for the image data */
00300 currentimage->x = inpam.height;
00301 currentimage->y = inpam.width;
00302 currentimage->data = (gocrPixel **)malloc(currentimage->x * sizeof(gocrPixel *));
00303 if ( currentimage->data == NULL ) {
00304 _gocr_debug(1, fprintf(_data.error, "_gocr_imageSharedCopy: NULL malloc\n");)
00305 fclose(fp);
00306 return -1;
00307 }
00308 for ( i = 0; i < currentimage->x; i++ )
00309 currentimage->data[i] = (gocrPixel *)malloc(currentimage->y * sizeof(gocrPixel));
00310
00311 /* and fill it */
00312 if ( inpam.depth == 1 && strcmp(inpam.tuple_type, PAM_PBM_TUPLETYPE) == 0 ) {
00313 /* we have a PBM (Black and white) */
00314 _gocr_debug(3, fprintf(_data.error, "PBM format detected.\n");)
00315
00316 currentimage->type = BLACK_AND_WHITE;
00317
00318 tuplerow = pnm_allocpamrow(&inpam);
00319 for ( row = 0; row < inpam.height; row++ ) {
00320 pnm_readpamrow(&inpam, tuplerow);
00321 for ( col = 0; col < inpam.width; col++ ) {
00322 currentimage->data[row][col].value =
00323 (tuplerow[col][0] == PAM_PBM_BLACK ? GOCR_BLACK : GOCR_WHITE );
00324 }
00325 }
00326 pnm_freepamrow(tuplerow);
00327 }
00328 else if ( inpam.depth == 1 && strcmp(inpam.tuple_type, PAM_PGM_TUPLETYPE) == 0 ) {
00329 /* we have a PGM (gray) */
00330 unsigned char **data = (unsigned char **)currentimage->data;
00331
00332 _gocr_debug(3, fprintf(_data.error, "PGM format detected.\n");)
00333
00334 currentimage->type = GRAY;
00335
00336 tuplerow = pnm_allocpamrow(&inpam);
00337 for ( row = 0; row < inpam.height; row++ ) {
00338 pnm_readpamrow(&inpam, tuplerow);
00339 for ( col = 0; col < inpam.width; col++ ) {
00340 data[row][col] = tuplerow[col][0];
00341 }
00342 }
00343 pnm_freepamrow(tuplerow);
00344 }
00345 else if ( inpam.depth == 3 && strcmp(inpam.tuple_type, PAM_PPM_TUPLETYPE) == 0 ) {
00346 /* we have a PPM (color) */
00347 _gocr_debug(3, fprintf(_data.error, "PPM format detected.\n");)
00348 _gocr_debug(0, fprintf(_data.error, "PPM format not handled yet.\n");)
00349 goto error;
00350 }
00351 else {
00352 _gocr_debug(1, fprintf(_data.error, "Format not recognized.\n");)
00353 goto error;
00354 }
00355 #endif
00356 #if defined HAVE_PNM_H && !defined HAVE_PAM_H
00357 _gocr_debug(0, fprintf(_data.error, "PNM not coded yet. Get a newer NetPBM with pam functions.\n");)
00358 #endif
00359
00360 currentimage->filename = strdup(filename);
00361
00362 list_init(¤timage->blocklist);
00363 fclose(fp);
00364
00365 return 0;
00366
00367 error: /* free, close, and return */
00368 fclose(fp);
00369 free(currentimage->data);
00370 free(currentimage);
00371 return -1;
00372 }
00373
00379 void gocr_imageClose ( void ) {
00380 gocr_imageFree(currentimage);
00381 }
00382
00390 void gocr_imageFree ( gocrImage *image ) {
00391 _gocr_debug(3, fprintf(_data.error, "gocr_imageFree(%p)\n", image);)
00392
00393 if ( image == NULL )
00394 return;
00395
00396 if ( image->filename )
00397 free(image->filename);
00398 if ( image->data ) {
00399 int i;
00400
00401 for ( i = 0; i < image->x; i++ )
00402 if (image->data[i])
00403 free(image->data[i]);
00404
00405 free(image->data);
00406 }
00407 image->x = image->y = 0;
00408 free(image);
00409 /*TODO list_free(block)*/
00410 }
00411
00412 /* if data == 1, print blocks and boxes frames */
00413 int _gocr_imageWrite ( gocrImage *image, char *filename, char data ) {
00414 FILE *fp;
00415 #ifdef HAVE_PAM_H
00416 struct pam outpam;
00417 #endif
00418
00419 _gocr_debug(3, fprintf(_data.error, "_gocr_imageWrite(%p, %s)\n", image, filename);)
00420
00421 if ( image == NULL ) {
00422 _gocr_debug(1, fprintf(_data.error, "_gocr_imageWrite: NULL image\n");)
00423 return -1;
00424 }
00425
00426 /* open the file */
00427 if ( filename == NULL ) {
00428 filename = image->filename;
00429 if ( filename == NULL ) {
00430 _gocr_debug(1, fprintf(_data.error, "_gocr_imageWrite: NULL filename\n");)
00431 return -1;
00432 }
00433 }
00434
00435 fp = fopen(filename, "w");
00436 if ( fp == NULL ) {
00437 _gocr_debug(1, fprintf(_data.error, "_gocr_imageWrite: file open error\n");)
00438 return -1;
00439 }
00440
00441 #ifdef HAVE_PAM_H
00442 /* fill the pam structure */
00443 outpam.file = fp;
00444 #ifdef NOTDONEYET
00445 outpam.size = ;
00446 outpam.len = ;
00447 outpam.height = image->y;
00448 outpam.width = image->x;
00449
00450 if ( data == 1 ) { /* output .pbm */
00451 outpam.format = PBM_FORMAT;
00452 outpam.depth = 1;
00453 outpam.maxval = 1;
00454 outpam.tuple_type = BLACKANDWHITE;
00455 }
00456 else { /* output ppm */
00457 outpam.format = PPM_FORMAT;
00458 outpam.depth = 3;
00459 outpam.maxval = 255;
00460 outpam.tuple_type = RGB;
00461 }
00462 #endif
00463
00464 pnm_writepaminit(&outpam);
00465 {
00466 tuple *tuplerow;
00467 int row;
00468
00469 tuplerow = pnm_allocpamrow(&outpam);
00470 for (row = 0; row < outpam.height; row++) {
00471 /* fill row */
00472 pnm_writepamrow(&outpam, tuplerow);
00473 }
00474 pnm_freepamrow(tuplerow);
00475 }
00476 #endif
00477 #if defined HAVE_PNM_H && !defined HAVE_PAM_H
00478 if ( data == 0 ) { /* output .pbm */
00479 bit *bitrow;
00480
00481 pbm_writepbminit(fp, image->x, image->y, 0);
00482 bitrow = pbm_allocrow(image->x);
00483 for ( i = 0; i < image->y; i++ ) {
00484 for ( j = 0; j < image->x; j++ )
00485 bitrow[j] = ( image->data[i][j].value == GOCR_BLACK ? PBM_BLACK : PBM_WHITE );
00486 pbm_writepbmrow(fp, bitrow, image->x, 0 );
00487 }
00488 pbm_freerow(bitrow);
00489 }
00490 else { /* output .ppm */
00491 pixel *pixelrow;
00492
00493 ppm_writeppminit(fp, image->x, image->y, 255, 0);
00494 pixelrow = ppm_allocrow(image->x);
00495 for ( i = 0; i < image->y; i++ ) {
00496 for ( j = 0; j < image->x; j++ ) {
00497 /*TODO*/
00498 }
00499 ppm_writeppmrow(fp, pixelrow, image->x, 255, 0 );
00500 }
00501 ppm_freerow(pixelrow);
00502
00503 }
00504 #endif
00505
00506 fclose(fp);
00507 }
00508
00519 int gocr_imageWrite ( gocrImage *image, char *filename ) {
00520 return _gocr_imageWrite( image, filename, 0 );
00521 }
00522
00535 int gocr_imageWriteWithData ( gocrImage *image, char *filename ) {
00536 return _gocr_imageWrite( image, filename, 1 );
00537 }