tesseract/image/imgio.cpp
2007-03-07 20:03:40 +00:00

322 lines
10 KiB
C++

/**********************************************************************
* 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", LOG, 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", LOG, 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", LOG, 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", LOG, 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", LOG, 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", LOG, 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", LOG, 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", LOG, 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", LOG, name);
close(fd);
fd = -1;
return -1; //failed
}
return 0; //success
}