| /********************************************************************** |
| * File: imgio.c (Formerly imageio.c) |
| * Description: Controls image input/output and selection of format. |
| * Author: Ray Smith |
| * Created: Mon Jun 11 11:47:26 BST 1990 |
| * |
| * (C) Copyright 1990, Hewlett-Packard Ltd. |
| ** Licensed under the Apache License, Version 2.0 (the "License"); |
| ** you may not use this file except in compliance with the License. |
| ** You may obtain a copy of the License at |
| ** http://www.apache.org/licenses/LICENSE-2.0 |
| ** Unless required by applicable law or agreed to in writing, software |
| ** distributed under the License is distributed on an "AS IS" BASIS, |
| ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| ** See the License for the specific language governing permissions and |
| ** limitations under the License. |
| * |
| **********************************************************************/ |
| |
| #include "mfcpch.h" //precompiled headers |
| #ifdef __MSW32__ |
| #include <io.h> |
| #else |
| #include <unistd.h> |
| #endif |
| #include <fcntl.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <string.h> |
| #include "scanutils.h" |
| #include "stderr.h" |
| #include "fileerr.h" |
| #include "imgerrs.h" |
| #include "memry.h" |
| #include "imgs.h" |
| #include "imgbmp.h" |
| #include "imgtiff.h" |
| #include "imgio.h" |
| |
| #define DEFAULTIMAGETYPE "tif" //default to im files |
| |
| typedef struct |
| { |
| const char *string; //extension |
| IMAGE_OPENER opener; //opening function |
| IMAGE_READER reader; //reading function |
| IMAGE_WRITER writer; //writing function |
| } IMAGETYPE; //image type record |
| |
| static IMAGETYPE imagetypes[] = { { |
| "TIF", |
| open_tif_image, |
| read_tif_image, |
| write_moto_tif |
| }, |
| { |
| "itf", |
| open_tif_image, |
| read_tif_image, |
| write_inverse_tif |
| }, |
| { |
| "tif", |
| open_tif_image, |
| read_tif_image, |
| write_intel_tif |
| }, |
| { |
| "bmp", |
| open_bmp_image, |
| read_bmp_image, |
| write_bmp_image |
| }, |
| }; //image readers/writers |
| |
| #define MAXIMAGETYPES (sizeof(imagetypes)/sizeof(IMAGETYPE)) |
| |
| /********************************************************************** |
| * name_to_image_type |
| * |
| * Convert a file name to an image type, picking defaults if it is |
| * has no extension, and complaining if the extension is not supported. |
| **********************************************************************/ |
| |
| static inT8 name_to_image_type( //get image type |
| const char *name //name of image |
| ) { |
| const char *nametype; //type part of name |
| inT8 type; //imagetypes index |
| |
| nametype = strrchr (name, '.');//find extension |
| if (nametype != NULL) |
| nametype++; //ptr to extension |
| else |
| nametype = DEFAULTIMAGETYPE; //had none |
| |
| //find type of image |
| for (type = 0; type < MAXIMAGETYPES && strcmp (imagetypes[type].string, nametype); type++); |
| if (type >= MAXIMAGETYPES) { |
| //unrecognized type |
| BADIMAGETYPE.error ("name_to_image_type", TESSLOG, name); |
| return -1; |
| } |
| return type; |
| } |
| |
| |
| /********************************************************************** |
| * read_header |
| * |
| * Read the header of an image, typed according to the extension of |
| * the name. Return is 0 for success, -1 for failure. |
| **********************************************************************/ |
| |
| inT8 IMAGE::read_header( //get file header |
| const char *name //name of image |
| ) { |
| inT8 type; //image type |
| |
| destroy(); //destroy old image |
| //get type |
| type = name_to_image_type (name); |
| if (type < 0 || imagetypes[type].opener == NULL) { |
| CANTREADIMAGETYPE.error ("IMAGE::read_header", TESSLOG, name); |
| return -1; //read not supported |
| } |
| #ifdef __UNIX__ |
| if ((fd = open (name, O_RDONLY)) < 0) |
| #endif |
| #if defined (__MSW32__) || defined (__MAC__) |
| if ((fd = open (name, O_RDONLY | O_BINARY)) < 0) |
| #endif |
| { |
| CANTOPENFILE.error ("IMAGE::read_header", TESSLOG, name); |
| return -1; //failed |
| } |
| lineskip = |
| (*imagetypes[type].opener) (fd, &xsize, &ysize, &bpp, &photo_interp, |
| &res); |
| if (lineskip == -1) { |
| //get header |
| bpp = 0; //still empty |
| close(fd); |
| fd = -1; |
| return -1; //failed |
| } |
| if (res <= 0) |
| res = image_default_resolution; |
| // fprintf(stderr,"Image size=(%d,%d), bpp=%d\n", |
| // xsize,ysize,bpp); |
| //bytes per line |
| xdim = COMPUTE_IMAGE_XDIM (xsize, bpp); |
| bps = bpp == 24 ? 8 : bpp; |
| bytespp = (bpp + 7) / 8; |
| //funtion to read with |
| reader = imagetypes[type].reader; |
| return 0; //success |
| } |
| |
| |
| /********************************************************************** |
| * read |
| * |
| * Read a previously opened image file into memory. |
| * If buflines is 0, the whole image is read in one go. |
| * If buflines>0, memory space is reserved for reading just that many |
| * lines at once. |
| * As soon as a request is made to get a line past the end of the buffer, |
| * the buffer is re-read with a 50% overlap. |
| * Backward seeks are not allowed. |
| * Read returns -1 in case of failure or 0 if successful. |
| **********************************************************************/ |
| |
| inT8 IMAGE::read( //get rest of image |
| inT32 buflines //size of buffer |
| ) { |
| inT32 row; //image row |
| BOOL8 failed; //read failed |
| |
| if (fd < 0 || image != NULL) |
| IMAGEUNDEFINED.error ("IMAGE::read", ABORT, NULL); |
| |
| if (buflines <= 0 || buflines > ysize || reader == NULL) |
| buflines = ysize; //default to all |
| bufheight = buflines; |
| image = |
| (uinT8 *) alloc_big_mem ((size_t) (xdim * bufheight * sizeof (uinT8))); |
| if (image == NULL) { |
| MEMORY_OUT.error ("IMAGE::read", TESSLOG, NULL); |
| destroy(); |
| return -1; |
| } |
| captured = FALSE; |
| ymax = ysize; |
| ymin = ysize - buflines; //amount of image read |
| if (reader != NULL && lineskip < 0) |
| failed = (*reader) (fd, image, xsize, ysize, bpp, xdim) < 0; |
| else { |
| if (lineskip == 0) |
| failed =::read (fd, (char *) image, |
| (size_t) (xdim * bufheight)) != xdim * bufheight; |
| else { |
| for (failed = FALSE, row = 0; row < bufheight && !failed; row++) { |
| failed =::read (fd, (char *) image + row * xdim, |
| (size_t) xdim) != xdim; |
| failed |= lseek (fd, lineskip, SEEK_CUR) < 0; |
| } |
| } |
| } |
| if (failed) { |
| READFAILED.error ("IMAGE::read", TESSLOG, NULL); |
| destroy(); |
| return -1; //read failed |
| } |
| if (ymin <= 0) { |
| close(fd); //finished reading |
| fd = -1; //not open now |
| } |
| return 0; //success |
| } |
| |
| |
| /********************************************************************** |
| * bufread |
| * |
| * Read a bit more of an image into the buffer. |
| **********************************************************************/ |
| |
| inT8 IMAGE::bufread( //read more into buffer |
| inT32 y //required coord |
| ) { |
| inT32 readtop; //no of lines copied |
| inT32 linestoread; //no of lines to read |
| inT32 row; //row to read |
| BOOL8 failed; //read failed |
| |
| //copy needed? |
| if (y + bufheight / 2 >= ymin) { |
| //no of lines to move |
| readtop = y + bufheight / 2 - ymin + 1; |
| //copy inside it |
| copy_sub_image (this, 0, ymin, xsize, readtop, this, 0, ymax - readtop, TRUE); |
| } |
| else |
| readtop = 0; |
| ymax = y + bufheight / 2; //new top of image |
| ymin = ymax - bufheight; //possible bottom |
| if (ymin < 0) |
| ymin = 0; //clip to image size |
| linestoread = ymax - ymin - readtop; |
| if (lineskip == 0) |
| failed =::read (fd, (char *) (image + xdim * readtop), |
| (size_t) (xdim * linestoread)) != xdim * linestoread; |
| else { |
| for (failed = FALSE, row = 0; row < linestoread && !failed; row++) { |
| failed =::read (fd, (char *) (image + (readtop + row) * xdim), |
| (size_t) xdim) != xdim; |
| failed |= lseek (fd, lineskip, SEEK_CUR) < 0; |
| } |
| } |
| if (failed) { |
| READFAILED.error ("IMAGE::bufread", TESSLOG, NULL); |
| return -1; //read failed |
| } |
| if (ymin <= 0) { |
| close(fd); //finished reading |
| fd = -1; //not open now |
| } |
| return 0; //success |
| } |
| |
| |
| /********************************************************************** |
| * write |
| * |
| * Write an image to a file in a format determined by the name. |
| **********************************************************************/ |
| |
| inT8 IMAGE::write( //write image |
| const char *name //name to write |
| ) { |
| inT8 type; //type of image |
| |
| if (bpp == 0 || image == NULL || bufheight != ysize) |
| IMAGEUNDEFINED.error ("IMAGE::write", ABORT, NULL); |
| if (fd >= 0) { |
| close(fd); //close old file |
| fd = -1; //no longer open |
| } |
| //get image type |
| type = name_to_image_type (name); |
| if (type < 0 || imagetypes[type].writer == NULL) { |
| CANTWRITEIMAGETYPE.error ("IMAGE::write", TESSLOG, name); |
| return -1; //write not supported |
| } |
| #ifdef __UNIX__ |
| if ((fd = creat (name, 0666)) < 0) |
| #endif |
| #ifdef __MSW32__ |
| if ((fd = open (name, _O_CREAT | _O_WRONLY | _O_BINARY, _S_IWRITE)) < 0) |
| #endif |
| #ifdef __MAC__ |
| if ((fd = creat (name, O_WRONLY | O_BINARY)) < 0) |
| #endif |
| { |
| CANTCREATEFILE.error ("IMAGE::write", TESSLOG, name); |
| return -1; //failed |
| } |
| if (res <= 0) |
| res = image_default_resolution; |
| if ((*imagetypes[type].writer) (fd, image, xsize, ysize, bpp, photo_interp, |
| res) < 0) { |
| //get header |
| //write failed |
| WRITEFAILED.error ("IMAGE::write", TESSLOG, name); |
| close(fd); |
| fd = -1; |
| return -1; //failed |
| } |
| return 0; //success |
| } |