mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1753 lines
74 KiB
1753 lines
74 KiB
/*
|
|
|
|
$Log: S:\oiwh\libgfs\tfwrite.c_v $
|
|
*
|
|
* Rev 1.3 12 Sep 1995 17:15:16 HEIDI
|
|
*
|
|
* commented out 'writeifh' routine. It is no longer used.
|
|
*
|
|
* Rev 1.2 12 Sep 1995 16:57:14 HEIDI
|
|
*
|
|
* check for HFILE_ERROR on reads and writes
|
|
*
|
|
* Rev 1.1 19 Apr 1995 16:35:16 RWR
|
|
* Make sure WIN32_LEAN_AND_MEAN is defined (explicitly or via GFSINTRN.H)
|
|
* Also surround local include files with quotes instead of angle brackets
|
|
*
|
|
* Rev 1.0 06 Apr 1995 14:02:32 HEIDI
|
|
* Initial entry
|
|
*
|
|
* Rev 1.0 28 Mar 1995 15:52:58 JAR
|
|
* Initial entry
|
|
|
|
*/
|
|
|
|
/*
|
|
Copyright 1989, 1990, 1991 by Wang Laboratories Inc.
|
|
Permission to use, copy, modify, and distribute this
|
|
software and its documentation for any purpose and without
|
|
fee is hereby granted, provided that the above copyright
|
|
notice appear in all copies and that both that copyright
|
|
notice and this permission notice appear in supporting
|
|
documentation, and that the name of WANG not be used in
|
|
advertising or publicity pertaining to distribution of the
|
|
software without specific, written prior permission.
|
|
WANG makes no representations about the suitability of
|
|
this software for any purpose. It is provided "as is"
|
|
without express or implied warranty.
|
|
*
|
|
*/
|
|
/*
|
|
* SccsId: @(#)Source tfwrite.c 1.42@(#)
|
|
*
|
|
* GFS: TIFF write handling routines
|
|
*
|
|
* Routines:
|
|
* long tfwrite(fct, buf, numbytes, pgnum, done )
|
|
*
|
|
* UPDATE HISTORY:
|
|
* 08/18/94 - KMC, multi-page TIFF write enhancements.
|
|
* 03/15/94 - RWR, In writeifd, check if Hi-TIFF data has been written
|
|
* to the file. If so, add tag to IFD in the correct order.
|
|
* 03/09/94 - KMC, Changed annotation tag write in writeifd to come
|
|
* before TOC tag in IFD.
|
|
* 02/18/94 - KMC, In writeifd, check if annotation data has been written
|
|
* to the file. If so, add an. tag to IFD.
|
|
* 10/12/93 - KMC, now using compression type of JPEG2 to identify new
|
|
* Jpeg compression (Wang's, not Xing's).
|
|
* 09/10/93 - KMC, fixed a problem with passing the subsample info for the
|
|
* YCbCr SubSampling tag in the GfsInfo...grp3 field.
|
|
* 08/25/93 - KMC, don't swap bytes for data in TAG_JPEGINTFORMAT before
|
|
* writing it in bldifde_tb(...). This data should never be swaped.
|
|
* 08/23/93 - KMC, forced count for JpegInterchangeFormat tag to be 1.
|
|
* 08/19/93 - KMC, fixed bug in the writing of the Q, AC, DC table JPEG tags.
|
|
* 06/15/93 - KMC, added support for TIFF 6.0 JPEG and YCbCr color space tags.
|
|
* 05/18/93 - KMC, now when writing ImageWidth and ImageLength tags, check
|
|
* to see if value will fit into a short. If not, use long.
|
|
* 04/16/93 - KMC, fixed bug where a tag of 0 was being written to IFD.
|
|
*
|
|
*/
|
|
|
|
/*LINTLIBRARY*/
|
|
#define GFS_CORE
|
|
#ifndef HVS1
|
|
|
|
#include "gfsintrn.h"
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include "gfs.h"
|
|
#include "gfct.h"
|
|
#include "tiff.h"
|
|
|
|
extern int FAR PASCAL puttoc();
|
|
extern void FAR PASCAL swapbytes();
|
|
extern long FAR PASCAL w_swapbytes();
|
|
extern int FAR PASCAL tfrdifd();
|
|
|
|
extern long FAR PASCAL writebytes(int, char FAR *, u_int, u_long, u_short, u_short);
|
|
extern int FAR PASCAL GetOffsetFromToc2(struct _gfct FAR *, u_long,
|
|
u_long FAR *, char);
|
|
extern int FAR PASCAL WriteOutFirstIFD(struct _gfct FAR *);
|
|
extern int FAR PASCAL PutOffsetInList(struct _gfct FAR *, u_short, u_long);
|
|
extern int FAR PASCAL GetNextIfdOffset(int, u_long FAR *, u_long);
|
|
|
|
int getdataoffs(struct _gfct FAR *, char);
|
|
int write_offs_cnts(struct _gfct FAR *);
|
|
|
|
/*****************************************************************
|
|
*
|
|
* write the idh to the temp toc file
|
|
*/
|
|
int FAR PASCAL writeidh(fct, idh) /*errno_KEY*/
|
|
struct _gfct FAR *fct;
|
|
struct _idh FAR *idh;
|
|
{
|
|
int num_written;
|
|
long fp;
|
|
|
|
/* lseek to the beginning and write ifh0 and ifd0 */
|
|
fp = lseek( fct->u.tif.mem_ptr.toc32->fildes, 0L, (int) FROM_BEGINNING);
|
|
if (fp < 0L)
|
|
return( (int) -1 );
|
|
|
|
num_written = write(fct->u.tif.mem_ptr.toc32->fildes,
|
|
(char FAR *) idh, (unsigned) IDH_SIZE );
|
|
if (num_written < (int) 0)
|
|
return( (int) -1);
|
|
|
|
return( (int) 0);
|
|
}
|
|
|
|
/***********************************************************/
|
|
/* Return tiff orientation given rotation,origin&reflection */
|
|
u_short FAR PASCAL get_orientation( info) /*errno_KEY*/
|
|
struct gfsinfo FAR *info;
|
|
{
|
|
u_short orientation = (u_short) 1; /* always default to this */
|
|
u_long org = info->origin; /* shorten names */
|
|
u_long rot = info->rotation;
|
|
|
|
if (info->reflection == (u_long) NORMAL_REFLECTION)
|
|
{
|
|
if (((org == (u_long) TOPLEFT_00) && (rot ==(u_long) DEGREES_0)) ||
|
|
((org == (u_long) TOPRIGHT_00) && (rot== (u_long) DEGREES_90)) ||
|
|
((org == (u_long) BOTTOMRIGHT_00) && (rot== (u_long) DEGREES_180))||
|
|
((org == (u_long) BOTTOMLEFT_00) && (rot== (u_long) DEGREES_270)) )
|
|
orientation = (u_short) 1;
|
|
else
|
|
if(((org == (u_long) TOPLEFT_00) && (rot == (u_long) DEGREES_270)) ||
|
|
((org == (u_long) TOPRIGHT_00) && (rot == (u_long) DEGREES_0)) ||
|
|
((org == (u_long) BOTTOMRIGHT_00) && (rot == (u_long) DEGREES_90))||
|
|
((org == (u_long) BOTTOMLEFT_00) && (rot == (u_long) DEGREES_180)) )
|
|
orientation = (u_short) 2;
|
|
else
|
|
if (((org == (u_long) TOPLEFT_00) && (rot == (u_long) DEGREES_180)) ||
|
|
((org == (u_long) TOPRIGHT_00) && (rot == (u_long) DEGREES_270)) ||
|
|
((org == (u_long) BOTTOMRIGHT_00) && (rot == (u_long) DEGREES_0))||
|
|
((org == (u_long) BOTTOMLEFT_00) && (rot == (u_long) DEGREES_90)) )
|
|
orientation = (u_short) 3;
|
|
else
|
|
if (((org == (u_long) TOPLEFT_00) && (rot == (u_long) DEGREES_90)) ||
|
|
((org == (u_long) TOPRIGHT_00) && (rot == (u_long) DEGREES_180)) ||
|
|
((org == (u_long) BOTTOMRIGHT_00) && (rot == (u_long) DEGREES_270))||
|
|
((org == (u_long) BOTTOMLEFT_00) && (rot == (u_long) DEGREES_0)) )
|
|
orientation = (u_short) 4;
|
|
}
|
|
else /* MIRROR_REFLECTION */
|
|
{
|
|
if (((org == (u_long) TOPLEFT_00) && (rot== (u_long) DEGREES_0)) ||
|
|
((org == (u_long) TOPRIGHT_00) && (rot== (u_long) DEGREES_90)) ||
|
|
((org == (u_long) BOTTOMRIGHT_00) && (rot== (u_long) DEGREES_180))||
|
|
((org == (u_long) BOTTOMLEFT_00) && (rot == (u_long) DEGREES_270)) )
|
|
orientation = (u_short) 5;
|
|
else
|
|
if(((org == (u_long) TOPLEFT_00) && (rot == (u_long) DEGREES_270)) ||
|
|
((org == (u_long) TOPRIGHT_00) && (rot == (u_long) DEGREES_0)) ||
|
|
((org == (u_long) BOTTOMRIGHT_00) && (rot == (u_long) DEGREES_90))||
|
|
((org == (u_long) BOTTOMLEFT_00) && (rot == (u_long) DEGREES_180)) )
|
|
orientation = (u_short) 6;
|
|
else
|
|
if (((org == (u_long) TOPLEFT_00) && (rot == (u_long) DEGREES_180)) ||
|
|
((org == (u_long) TOPRIGHT_00) && (rot == (u_long) DEGREES_270)) ||
|
|
((org == (u_long) BOTTOMRIGHT_00) && (rot == (u_long) DEGREES_0))||
|
|
((org == (u_long) BOTTOMLEFT_00) && (rot == (u_long) DEGREES_90)) )
|
|
orientation = (u_short) 7;
|
|
else
|
|
if (((org == (u_long) TOPLEFT_00) && (rot == (u_long) DEGREES_90)) ||
|
|
((org == (u_long) TOPRIGHT_00) && (rot == (u_long) DEGREES_180)) ||
|
|
((org == (u_long) BOTTOMRIGHT_00) && (rot == (u_long) DEGREES_270))||
|
|
((org == (u_long) BOTTOMLEFT_00) && (rot == (u_long) DEGREES_0)) )
|
|
orientation = (u_short) 8;
|
|
};
|
|
|
|
return( (u_short) orientation);
|
|
}
|
|
|
|
/****************************************************************/
|
|
/* subroutine for doing the output of color/gray and JPEG data, */
|
|
/* and add tag to ifd */
|
|
/****************************************************************/
|
|
int FAR PASCAL bldifde_tb( fct, ifd, n, fp, tag, tb, type) /*errno_KEY*/
|
|
struct _gfct FAR *fct;
|
|
struct _ifd FAR *ifd;
|
|
int FAR *n;
|
|
long FAR *fp;
|
|
int tag;
|
|
struct gfstidbit FAR *tb;
|
|
int type;
|
|
{
|
|
long rem;
|
|
struct typetbl ttbl[2];
|
|
long bw;
|
|
|
|
if (tb->ptr != (char FAR *) NULL )
|
|
{
|
|
ifd->entry[*n].tag = (u_short) tag;
|
|
ifd->entry[*n].type = (u_short) type;
|
|
|
|
/* need the len to be in terms of #of elements of type TYPE */
|
|
if (ifd->entry[*n].type == (u_short) TYPE_USHORT)
|
|
ifd->entry[*n].len = (u_long) tb->cnt / sizeof(u_short);
|
|
/* KMC - new for TIFF 6.0 JPEG tags */
|
|
else if (ifd->entry[*n].type == (u_short) TYPE_ULONG)
|
|
/* KMC - force count of JPEGInterchangeFormat tag to be 1, */
|
|
/* as indicated in the TIFF 6.0 spec. */
|
|
if (tag == TAG_JPEGINTFORMAT)
|
|
ifd->entry[*n].len = 1;
|
|
else
|
|
ifd->entry[*n].len = (u_long) tb->cnt / sizeof(u_long);
|
|
else
|
|
if (ifd->entry[*n].type == (u_short) TYPE_RATIONAL)
|
|
ifd->entry[*n].len = (u_long) tb->cnt / 2 * sizeof (u_long);
|
|
else
|
|
if (ifd->entry[*n].type == (u_short) TYPE_ASCII)
|
|
ifd->entry[*n].len = (u_long) tb->cnt;
|
|
|
|
/* Write data, file pointer in proper place. */
|
|
/* KMC - make sure you don't swap bytes if this is data for */
|
|
/* JPEGInterchangeFormat tag. */
|
|
if ((ifd->entry[*n].type != TYPE_ASCII) &&
|
|
(fct->out_byteorder != (u_short) SYSBYTEORDER) && (tag != TAG_JPEGINTFORMAT))
|
|
{
|
|
ttbl[0].num = (u_long) ifd->entry[*n].len;
|
|
ttbl[0].type = (u_long) type;
|
|
bw = (long) w_swapbytes( fct->fildes, (long) tb->cnt,
|
|
(char FAR *) tb->ptr,
|
|
(struct typetbl FAR *) ttbl, 1L, 1L);
|
|
}
|
|
else
|
|
bw = (long) write(fct->fildes, (char FAR *) tb->ptr,
|
|
(u_int) tb->cnt );
|
|
|
|
if (bw < 0L)
|
|
return( (short) -1);
|
|
|
|
ifd->entry[*n].valoffset.l = (u_long) fct->u.tif.cur_data_offset;
|
|
|
|
(*n)++;
|
|
|
|
/* now make sure next offset is on a word boundary, not guarenteed*/
|
|
/* that the ascii string just written was a multiple of 4 */
|
|
if ((rem = bw % 4) != 0L)
|
|
{
|
|
rem = 4L - rem;
|
|
if ((*fp = (long) lseek(fct->fildes, rem, FROM_CURRENT)) < 0L)
|
|
|
|
return( (int) -1);
|
|
}
|
|
else
|
|
*fp += bw;
|
|
|
|
/* if rem was 0 then just offset by bw, else get both changes */
|
|
fct->u.tif.cur_data_offset += (u_long)(bw + rem);
|
|
ifd->entrycount++;
|
|
}
|
|
|
|
return( (short) 0);
|
|
}
|
|
|
|
|
|
/*********************************************************/
|
|
long FAR PASCAL tfwrite(fct, buf, numbytes, pgnum, done ) /*errno_KEY*/
|
|
struct _gfct FAR *fct;
|
|
register char FAR *buf;
|
|
u_long numbytes;
|
|
u_short pgnum;
|
|
char done;
|
|
{
|
|
long bw; /* bytes written to the file */
|
|
long fp;
|
|
u_long numstrips;
|
|
|
|
/* fct->curr_page must be complete, else error, because the user should
|
|
not be mixing different image pages of image data together. This error
|
|
means the user has not set the done flag in the last gfswrite() call
|
|
associated with the fct->curr_page to IMAGE_DONE and
|
|
has probably not issued a new gfsputi() call for the image associated
|
|
with pgnum. PAGE_DONE gets set at the end of tfwrite().*/
|
|
if ( fct->curr_page != pgnum )
|
|
{
|
|
if ( (fct->PAGE_STATUS & (char) PAGE_DONE ) != (char) PAGE_DONE )
|
|
{
|
|
errno = (int) EPREVIOUS_PG_NOT_COMPLETE;
|
|
return( (long) -1 );
|
|
}
|
|
}
|
|
/* if pgs are equal and PAGE_DONE not set, then in the middle of a partial
|
|
write */
|
|
/* There is still the problem of
|
|
if the pages are equal, thus signifying a subfile image, a gfsputi() call
|
|
is still necessary to output the ifd for the previous image. If the
|
|
user has forgotten to do the gfsputi() call and has not set IMAGE_DONE in
|
|
the last call of gfswrite(), then right now they are not caught here */
|
|
|
|
/* move file pointer to data start location */
|
|
if (( fp = lseek( fct->fildes, (long) fct->u.tif.cur_data_offset,
|
|
(int) FROM_BEGINNING)) < 0L)
|
|
return( (long) -1);
|
|
|
|
/* now write out the buffer, bw could come back less than numbytes */
|
|
/* The writing of image data does not need to have a byteorder swap. */
|
|
if ( (bw = (long) write(fct->fildes, (char FAR *) buf, (unsigned) numbytes))
|
|
< 0)
|
|
return( (long) -1);
|
|
|
|
/* now interpret buffer that was just written */
|
|
/* see if it's the beginning of a strip; (whether page or strip write) */
|
|
if ( (fct->PAGE_STATUS & (char) BEGIN_STRIP) == (char) 0 )
|
|
{
|
|
fct->PAGE_STATUS |= (char) BEGIN_STRIP; /* set flag */
|
|
/* first strip is 0th offset from top, (cur_strip initialized to -1) */
|
|
fct->u.tif.cur_strip++;
|
|
|
|
/* only do datatype of u_long for now */
|
|
/* determine if need to allocate the first one, or subsequent ones */
|
|
if (fct->u.tif.cur_strip == (int) 0 ) /* if the first strip */
|
|
{
|
|
/* Allocate memory once to avoid fragmention if user has a number */
|
|
/* in strips_per_image, otherwise allocate first one */
|
|
numstrips = 1L;
|
|
if (fct->uinfo._file.fmt.tiff.strips_per_image != (u_long) 0)
|
|
numstrips = (u_long) fct->uinfo._file.fmt.tiff.strips_per_image;
|
|
|
|
fct->u.tif.offsets->ptr.l = (u_long FAR *) calloc( (unsigned) 1,
|
|
(unsigned) (sizeof(u_long) * numstrips) );
|
|
fct->u.tif.bytecnt->ptr.l = (u_long FAR *) calloc( (unsigned) 1,
|
|
(unsigned) (sizeof(u_long) * numstrips) );
|
|
}
|
|
else
|
|
{
|
|
/* Make sure there is enough memory allocated, else get some more*/
|
|
/* This will cause a "writebystrip mode" call to realloc for every
|
|
strip if the user wants or if made wrong assumption about #of
|
|
strips this will give you more memory */
|
|
if ((unsigned long)fct->u.tif.cur_strip >=
|
|
fct->uinfo._file.fmt.tiff.strips_per_image)
|
|
{
|
|
/* resize the amount of storage */
|
|
fct->u.tif.offsets->ptr.l = (u_long FAR *) realloc( (char FAR *)
|
|
fct->u.tif.offsets->ptr.l, (unsigned) (sizeof(u_long) *
|
|
(fct->u.tif.cur_strip + 1L)) );
|
|
fct->u.tif.bytecnt->ptr.l = (u_long FAR *) realloc( (char FAR *)
|
|
fct->u.tif.bytecnt->ptr.l, (unsigned) (sizeof(u_long) *
|
|
(fct->u.tif.cur_strip + 1L)) );
|
|
}
|
|
}
|
|
|
|
/* make sure have valid pointers */
|
|
if ((fct->u.tif.offsets->ptr.l == ( u_long FAR *) NULL) ||
|
|
(fct->u.tif.bytecnt->ptr.l == ( u_long FAR *) NULL) )
|
|
{
|
|
errno = (int) ENOMEM;
|
|
return( (int) -1);
|
|
}
|
|
/* initialize bytecount and save offset */
|
|
*(fct->u.tif.offsets->ptr.l + fct->u.tif.cur_strip )
|
|
= (u_long) fp;
|
|
*(fct->u.tif.bytecnt->ptr.l + fct->u.tif.cur_strip )
|
|
= (u_long) bw;
|
|
}
|
|
else
|
|
{
|
|
/* increment bytes written to existing bytecount */
|
|
*(fct->u.tif.bytecnt->ptr.l + fct->u.tif.cur_strip )
|
|
+= (u_long) bw;
|
|
}
|
|
|
|
if ( fct->WRITE_BY_STRIP )
|
|
{
|
|
if (done & (char) STRIP_DONE )
|
|
{
|
|
fct->PAGE_STATUS &= ~( (char) BEGIN_STRIP); /* clear flag */
|
|
}
|
|
else
|
|
/* trying to finish page before strip is done */
|
|
if (done & (char) IMAGE_DONE )
|
|
{
|
|
errno = (int) EINCOMPLETE_STRIP;
|
|
return( (long) -1);
|
|
}
|
|
}
|
|
else /* write by page */
|
|
{
|
|
}
|
|
|
|
fct->u.tif.cur_data_offset += (u_long) bw;
|
|
|
|
/* are we all done with this image page? */
|
|
if (done & (char) IMAGE_DONE ) /* passes for done == TRUE */
|
|
{
|
|
fct->PAGE_STATUS |= (char) PAGE_DONE; /* set PAGE_DONE */
|
|
fct->PAGE_STATUS &= ~( (char) BEGIN_STRIP); /* clear flag */
|
|
}
|
|
|
|
return( (long) bw);
|
|
}
|
|
|
|
/***************************************************************/
|
|
/*
|
|
* build an ifdentry from an info structure, and update entrycount
|
|
* and write out intermediate data
|
|
*
|
|
*/
|
|
int FAR PASCAL bldifde(info, fct) /*errno_KEY*/
|
|
struct gfsinfo FAR *info;
|
|
struct _gfct FAR *fct;
|
|
{
|
|
int required_numtags = (int) 16; /* More may be added !!! */
|
|
int n;
|
|
register struct _ifd FAR *ifd;
|
|
struct typetbl ttbl[3];
|
|
long fp;
|
|
long rem;
|
|
long bw;
|
|
struct gfstidbit temp_tidbit; /* KMC - for TIFF JPEG tags */
|
|
int loop;
|
|
long horiz_sub_sample; /* KMC - for YCbCr SubSampling tag */
|
|
long vert_sub_sample;
|
|
|
|
ifd = fct->u.tif.ifd;
|
|
fct->u.tif.cur_strip = (int) -1; /* initialize here */
|
|
n = (int) ifd->entrycount; /* will contain current count */
|
|
|
|
/* find out where to start writing intermediate data */
|
|
if ( getdataoffs( (struct _gfct FAR *) fct, (char) FALSE ) < 0 )
|
|
return( (int) -1);
|
|
|
|
/* now that the we have the location for writing intermediate data,*/
|
|
/* move the fp there initially */
|
|
if ((fp = lseek(fct->fildes, (long) fct->u.tif.cur_data_offset,
|
|
(int) FROM_BEGINNING)) < 0L)
|
|
return( (int) -1);
|
|
|
|
/* make sure the offset is word aligned */
|
|
if ( (rem = fp % 4) != 0L)
|
|
{
|
|
rem = 4L - rem;
|
|
/* perhaps here should be a write of rem 0's to the file? */
|
|
if ((fp = lseek(fct->fildes, (long) rem, FROM_CURRENT) ) < 0L)
|
|
return( (int) -1);
|
|
fct->u.tif.cur_data_offset = fp;
|
|
}
|
|
|
|
ifd->entry[n].tag = (u_short) TAG_NEWSUBFILETYPE;
|
|
ifd->entry[n].type = (u_short) TYPE_ULONG;
|
|
ifd->entry[n].len = (u_long) 1;
|
|
ifd->entry[n++].valoffset.l = (u_long) info->type;
|
|
|
|
/* TAG_SUBFILETYPE is here */
|
|
|
|
ifd->entry[n].tag = (u_short) TAG_IMAGEWIDTH;
|
|
ifd->entry[n].len = (u_long) 1;
|
|
/* KMC - check if the value will fit into a short. Use short if it
|
|
will fit, otherwise use long.
|
|
*/
|
|
if (info->horiz_size < 65536)
|
|
{
|
|
ifd->entry[n].type = (u_short) TYPE_USHORT;
|
|
ifd->entry[n++].valoffset.s = (u_short) info->horiz_size;
|
|
}
|
|
else
|
|
{
|
|
ifd->entry[n].type = (u_short) TYPE_ULONG;
|
|
ifd->entry[n++].valoffset.l = (u_long) info->horiz_size;
|
|
}
|
|
|
|
ifd->entry[n].tag = (u_short) TAG_IMAGELENGTH;
|
|
ifd->entry[n].len = (u_long) 1;
|
|
/* KMC - check if the value will fit into a short. Use short if it
|
|
will fit, otherwise use long.
|
|
*/
|
|
if (info->vert_size < 65536)
|
|
{
|
|
ifd->entry[n].type = (u_short) TYPE_USHORT;
|
|
ifd->entry[n++].valoffset.s = (u_short) info->vert_size;
|
|
}
|
|
else
|
|
{
|
|
ifd->entry[n].type = (u_short) TYPE_ULONG;
|
|
ifd->entry[n++].valoffset.l = (u_long) info->vert_size;
|
|
}
|
|
|
|
ifd->entry[n].tag = (u_short) TAG_BITSPERSAMPLE;
|
|
ifd->entry[n].type = (u_short) TYPE_USHORT;
|
|
ifd->entry[n].len = (u_long) info->samples_per_pix;
|
|
if (info->samples_per_pix == 1)
|
|
ifd->entry[n++].valoffset.s = (u_short) info->bits_per_sample[0];
|
|
else
|
|
{
|
|
u_short ushort_bps[5];
|
|
|
|
ifd->entry[n++].valoffset.l = (u_long) fct->u.tif.cur_data_offset;
|
|
|
|
/* check if the user wants to have a non-native byteorder */
|
|
/* there is a separate write() so that if needed the value stored in
|
|
memory is still a valid number and not swapped */
|
|
/* move the bits_per_sample values into a ushort array - the
|
|
TIFF stuff is u_short not u_long. */
|
|
ushort_bps[0] = (u_short) info->bits_per_sample[0];
|
|
ushort_bps[1] = (u_short) info->bits_per_sample[1];
|
|
ushort_bps[2] = (u_short) info->bits_per_sample[2];
|
|
ushort_bps[3] = (u_short) info->bits_per_sample[3];
|
|
ushort_bps[4] = (u_short) info->bits_per_sample[4];
|
|
|
|
if (fct->out_byteorder != (u_short) SYSBYTEORDER)
|
|
{
|
|
ttbl[0].type = ( u_long) TYPE_USHORT;
|
|
ttbl[0].num = (u_long) info->samples_per_pix;
|
|
bw = (long) w_swapbytes(fct->fildes,
|
|
(long)(info->samples_per_pix * sizeof(u_short)),
|
|
(char FAR *) ushort_bps,
|
|
(struct typetbl FAR *) ttbl, 1L, 1L );
|
|
}
|
|
else
|
|
{
|
|
bw = (long) write(fct->fildes, (char FAR *) ushort_bps,
|
|
(u_int) (info->samples_per_pix * sizeof(u_short)));
|
|
}
|
|
|
|
if (bw < 0L)
|
|
return( (int) -1);
|
|
|
|
/* now make sure next offset is on a word boundary, not guarenteed
|
|
that the ascii string just written was a multiple of 4 */
|
|
if ((rem = bw % 4) != 0L)
|
|
{
|
|
rem = 4L - rem;
|
|
if ((fp = lseek(fct->fildes, (long) rem, FROM_CURRENT)) < 0L)
|
|
return( (int) -1);
|
|
}
|
|
|
|
/* if rem was 0 then just offset by bw, else get both changes */
|
|
fct->u.tif.cur_data_offset += (u_long)(bw + rem);
|
|
}
|
|
|
|
|
|
ifd->entry[n].tag = (u_short) TAG_COMPRESSION;
|
|
ifd->entry[n].type = (u_short) TYPE_USHORT;
|
|
ifd->entry[n].len = (u_long) 1;
|
|
|
|
if ((info->img_cmpr.type == (u_long) UNCOMPRESSED) ||
|
|
(info->img_cmpr.type == (u_long) CCITT_GRP3_NO_EOLS) ||
|
|
(info->img_cmpr.type == (u_long) CCITT_GRP3_FACS) ||
|
|
(info->img_cmpr.type == (u_long) CCITT_GRP4_FACS) ||
|
|
(info->img_cmpr.type == (u_long) TF_JPEG_ECOM) ||
|
|
(info->img_cmpr.type == (u_long) LZW) )
|
|
ifd->entry[n++].valoffset.s = (u_short) info->img_cmpr.type;
|
|
else
|
|
{
|
|
if (info->img_cmpr.type == (u_long) PACKBITS )
|
|
ifd->entry[n++].valoffset.s = (u_short) TF_PACKBITS;
|
|
else
|
|
if (info->img_cmpr.type == (u_long) JPEG2 ) /* Wang Jpeg */
|
|
ifd->entry[n++].valoffset.s = (u_short) TF_JPEG;
|
|
else if (info->img_cmpr.type == (u_long) JPEG ) /* Xing Jpeg */
|
|
{
|
|
errno = (int) EINVALID_COMPRESSION; /* not supported for tiff */
|
|
return( (int) -1);
|
|
}
|
|
else
|
|
{
|
|
errno = (int) EINVALID_COMPRESSION; /* not supported for tiff */
|
|
return( (int) -1);
|
|
}
|
|
}
|
|
|
|
ifd->entry[n].tag = (u_short) TAG_PHOTOMETRICINTERP;
|
|
ifd->entry[n].type = (u_short) TYPE_USHORT;
|
|
ifd->entry[n].len = (u_long) 1;
|
|
switch ((int) info->img_clr.img_interp)
|
|
{
|
|
case GFS_BILEVEL_0ISWHITE:
|
|
case GFS_TEXT:
|
|
case GFS_GRAYSCALE_0ISWHITE:
|
|
ifd->entry[n++].valoffset.s = (u_short) TF_BILEVEL_0ISWHITE;
|
|
break;
|
|
case GFS_BILEVEL_0ISBLACK:
|
|
case GFS_GRAYSCALE_0ISBLACK:
|
|
ifd->entry[n++].valoffset.s = (u_short) TF_BILEVEL_0ISBLACK;
|
|
break;
|
|
/* KMC - new for YCbCr color space. */
|
|
case GFS_YCBCR:
|
|
ifd->entry[n++].valoffset.s = (u_short) TF_YCBCR;
|
|
break;
|
|
case GFS_RGB:
|
|
/* KMC - NOTE: if JPEG compression and RGB color space,
|
|
it is actually YCbCr color space, so make the correction.
|
|
*/
|
|
if (info->img_cmpr.type == (u_long) JPEG2)
|
|
{
|
|
info->img_clr.img_interp = GFS_YCBCR;
|
|
ifd->entry[n++].valoffset.s = (u_short) TF_YCBCR;
|
|
}
|
|
else
|
|
ifd->entry[n++].valoffset.s = (u_short) TF_RGB;
|
|
break;
|
|
case GFS_PSEUDO:
|
|
ifd->entry[n++].valoffset.s = (u_short) TF_PALETTE;
|
|
break;
|
|
case GFS_TRANSPARENCY:
|
|
ifd->entry[n++].valoffset.s = (u_short) TF_TRANSPARENCY;
|
|
break;
|
|
default:
|
|
errno = (int) ENOTSUPPORTED_IMAGETYPE;
|
|
return( (int) -1);
|
|
}
|
|
|
|
/* TAG_THRESHOLDING is here */
|
|
/* TAG_CELLWIDTH is here */
|
|
/* TAG_CELLLENGTH is here */
|
|
|
|
ifd->entry[n].tag = (u_short) TAG_FILLORDER;
|
|
ifd->entry[n].type = (u_short) TYPE_USHORT;
|
|
ifd->entry[n].len = (u_long) 1;
|
|
ifd->entry[n++].valoffset.s = (u_short) info->fill_order;
|
|
|
|
/* write the ascii data for the following tags and add entry to ifd*/
|
|
if (info->tidbit != (struct gfstidbit FAR *) NULL )
|
|
{
|
|
if ( bldifde_tb((struct _gfct FAR *) fct, (struct _ifd FAR *) ifd,
|
|
(int FAR *) &n, (long FAR *) &fp, TAG_DOCUMENTNAME,
|
|
(struct gfstidbit FAR *) &(info->TB_DOCUMENTNAME),
|
|
TYPE_ASCII) < 0)
|
|
return( (int) -1);
|
|
|
|
if ( bldifde_tb((struct _gfct FAR *) fct, (struct _ifd FAR *) ifd,
|
|
(int FAR *) &n, (long FAR *) &fp, TAG_IMAGEDESCRIPTION,
|
|
(struct gfstidbit FAR *) &info->TB_IMGDESCRIPTION,
|
|
TYPE_ASCII) < 0)
|
|
return( (int) -1);
|
|
|
|
if ( bldifde_tb((struct _gfct FAR *) fct, (struct _ifd FAR *) ifd,
|
|
(int FAR *) &n, (long FAR *) &fp, TAG_MAKE,
|
|
(struct gfstidbit FAR *) &info->TB_MAKE, TYPE_ASCII) < 0)
|
|
return( (int) -1);
|
|
|
|
if ( bldifde_tb((struct _gfct FAR *) fct, (struct _ifd FAR *) ifd,
|
|
(int FAR *) &n, (long FAR *) &fp, TAG_MODEL,
|
|
( struct gfstidbit FAR *) &info->TB_MODEL, TYPE_ASCII ) < 0)
|
|
return( (int) -1);
|
|
}
|
|
|
|
ifd->entry[n].tag = (u_short) TAG_STRIPOFFSETS;
|
|
ifd->entry[n].type = (u_short) TYPE_ULONG;
|
|
ifd->entry[n].len =(u_long) info->_file.fmt.tiff.strips_per_image;
|
|
fct->u.tif.stripoffset_index = (u_long) n;
|
|
ifd->entry[n++].valoffset.l = (u_long) NULL;
|
|
|
|
/* TAG_ORIENTATATION is here */
|
|
ifd->entry[n].tag = (u_short) TAG_ORIENTATION;
|
|
ifd->entry[n].type = (u_short) TYPE_USHORT;
|
|
ifd->entry[n].len = (u_long) 1;
|
|
ifd->entry[n++].valoffset.s =
|
|
(u_short) get_orientation((struct gfsinfo FAR *) info);
|
|
|
|
ifd->entry[n].tag = (u_short) TAG_SAMPLESPERPXL;
|
|
ifd->entry[n].type = (u_short) TYPE_USHORT;
|
|
ifd->entry[n].len = (u_long) 1;
|
|
ifd->entry[n++].valoffset.s = (u_short) info->samples_per_pix;
|
|
|
|
ifd->entry[n].tag = (u_short) TAG_ROWSPERSTRIP;
|
|
ifd->entry[n].type = (u_short) TYPE_USHORT;
|
|
ifd->entry[n].len = (u_long) 1;
|
|
ifd->entry[n++].valoffset.s = (u_short) info->_file.fmt.tiff.rows_strip;
|
|
|
|
ifd->entry[n].tag = (u_short) TAG_STRIPBYTECOUNTS;
|
|
ifd->entry[n].type = (u_short) TYPE_ULONG;
|
|
ifd->entry[n].len =(u_long) info->_file.fmt.tiff.strips_per_image;
|
|
fct->u.tif.bytecnt_index = (u_long) n;
|
|
ifd->entry[n++].valoffset.l = (u_long) NULL;/* dummy val. replcd later*/
|
|
|
|
/* TAG_MINSAMPLEVALUE is HERE */
|
|
/* TAG_MAXSAMPLEVALUE is HERE */
|
|
|
|
ifd->entry[n].tag = (u_short) TAG_XRES;
|
|
ifd->entry[n].type = (u_short) TYPE_RATIONAL;
|
|
ifd->entry[n].len = (u_long) 1;
|
|
ifd->entry[n++].valoffset.l = (u_long) fct->u.tif.cur_data_offset;
|
|
|
|
/* if user has placed no value into denominator, put a 1 there so
|
|
later have no divide by zero problems */
|
|
if (info->horiz_res[1] == (u_long) 0)
|
|
info->horiz_res[1] = 1L;
|
|
|
|
/* check if the user wants to have a non-native byteorder */
|
|
/* there is a separate write() so that if needed the value stored in
|
|
memory is still a valid number and not swapped */
|
|
if (fct->out_byteorder != (u_short) SYSBYTEORDER)
|
|
{
|
|
ttbl[0].type = ( u_long) TYPE_ULONG;
|
|
ttbl[0].num = 2L;
|
|
bw = (long) w_swapbytes(fct->fildes, (long) sizeof(info->horiz_res),
|
|
(char FAR *) info->horiz_res,
|
|
(struct typetbl FAR *) ttbl, 1L, 1L );
|
|
}
|
|
else
|
|
{
|
|
bw = (long) write(fct->fildes, (char FAR *) info->horiz_res,
|
|
sizeof(info->horiz_res)) ;
|
|
}
|
|
|
|
if (bw < 0L)
|
|
return( (int) -1);
|
|
|
|
/* since this was already word aligned, it will still be cuz just
|
|
wrote a u_long value to file */
|
|
fct->u.tif.cur_data_offset += (u_long) bw;
|
|
|
|
/* now output the intermediate data for yres */
|
|
ifd->entry[n].tag = (u_short) TAG_YRES;
|
|
ifd->entry[n].type = (u_short) TYPE_RATIONAL;
|
|
ifd->entry[n].len = (u_long) 1;
|
|
ifd->entry[n++].valoffset.l = (u_long) fct->u.tif.cur_data_offset;
|
|
|
|
/* if user has placed no value into denominator, put a 1 there so
|
|
later have no divide by zero problems */
|
|
if (info->vert_res[1] == (u_long) 0)
|
|
info->vert_res[1] = 1L;
|
|
|
|
/* write out data, file pointer in proper place */
|
|
|
|
if (fct->out_byteorder != (u_short) SYSBYTEORDER)
|
|
{
|
|
ttbl[0].type = ( u_long) TYPE_ULONG;
|
|
ttbl[0].num = 2L;
|
|
bw = (long) w_swapbytes(fct->fildes, (long) sizeof (info->vert_res),
|
|
(char FAR *) info->vert_res,
|
|
(struct typetbl FAR *) ttbl, 1L, 1L );
|
|
}
|
|
else
|
|
{
|
|
bw = (long) write(fct->fildes, (char FAR *) info->vert_res,
|
|
sizeof(info->vert_res)) ;
|
|
}
|
|
|
|
if (bw < 0L)
|
|
return( (int) -1);
|
|
|
|
/* since this was already word aligned, it will still be cuz just
|
|
wrote a u_long value to file */
|
|
fct->u.tif.cur_data_offset += (u_long) bw;
|
|
|
|
/* TAG_PLANARCONFIG is here */
|
|
if (info->img_clr.img_interp == (u_long) GFS_RGB)
|
|
{
|
|
ifd->entry[n].tag = (u_short) TAG_PLANARCONFIG;
|
|
ifd->entry[n].type = (u_short) TYPE_USHORT;
|
|
ifd->entry[n].len = (u_long) 1;
|
|
ifd->entry[n++].valoffset.s =
|
|
(u_short) info->RGB_PTR.plane_config;
|
|
required_numtags++;
|
|
}
|
|
/* KMC - bug fix: used to write out a tag of 0 here */
|
|
else if (info->img_clr.img_interp == (u_long) GFS_PSEUDO) {
|
|
ifd->entry[n].tag = (u_short) TAG_PLANARCONFIG;
|
|
ifd->entry[n].type = (u_short) TYPE_USHORT;
|
|
ifd->entry[n].len = (u_long) 1;
|
|
ifd->entry[n++].valoffset.s =
|
|
(u_short) info->PSEUDO_PTR.plane_config;
|
|
required_numtags++;
|
|
}
|
|
|
|
if (info->tidbit != (struct gfstidbit FAR *) NULL )
|
|
if ( bldifde_tb((struct _gfct FAR *) fct, (struct _ifd FAR *) ifd,
|
|
(int FAR *) &n, (long FAR *) &fp, TAG_PAGENAME,
|
|
(struct gfstidbit FAR *) &info->TB_PAGENAME, TYPE_ASCII) < 0)
|
|
return( (int) -1);
|
|
|
|
/* TAG_XPOSITION is here */
|
|
/* TAG_YPOSITION is here */
|
|
/* TAG_FREEOFFSETS is here */
|
|
/* TAG_FREEBYTECOUNTS is here */
|
|
|
|
/* TAG_GRAYRESPONSEUNIT is here */
|
|
if (info->img_clr.img_interp == (u_long) GFS_GRAYSCALE)
|
|
{
|
|
ifd->entry[n].tag = (u_short) TAG_GRAYRESPONSEUNIT;
|
|
ifd->entry[n].type = (u_short) TYPE_USHORT;
|
|
ifd->entry[n].len = (u_long) 1;
|
|
ifd->entry[n++].valoffset.s =
|
|
(u_short) info->GRAY_PTR.respunit;
|
|
required_numtags++;
|
|
|
|
/* TAG_GRAYRESPONSECURVE is next */
|
|
if ( bldifde_tb((struct _gfct FAR *) fct,
|
|
(struct _ifd FAR *) ifd,
|
|
(int FAR *) &n, (long FAR *) &fp, TAG_GRAYRESPONSECURVE,
|
|
(struct gfstidbit FAR *) &info->GRAY_RCRV,
|
|
TYPE_USHORT) < 0)
|
|
return( (int) -1);
|
|
}
|
|
|
|
/* put the appropriate option value into the file, lead_eol is a GFS
|
|
bit, not TIFF, so mask it out when putting into file */
|
|
if (info->img_cmpr.type == (u_long) CCITT_GRP3_FACS)
|
|
{
|
|
ifd->entry[n].tag = (u_short) TAG_GRP3OPTIONS;
|
|
ifd->entry[n].type = (u_short) TYPE_ULONG;
|
|
ifd->entry[n].len = (u_long) 1;
|
|
ifd->entry[n++].valoffset.l = (u_long)
|
|
(info->img_cmpr.opts.grp3 & ~((u_long) LEAD_EOL));
|
|
required_numtags++;
|
|
}
|
|
else
|
|
if (info->img_cmpr.type == (u_long) CCITT_GRP4_FACS)
|
|
{
|
|
ifd->entry[n].tag = (u_short) TAG_GRP4OPTIONS;
|
|
ifd->entry[n].type = (u_short) TYPE_ULONG;
|
|
ifd->entry[n].len = (u_long) 1;
|
|
ifd->entry[n++].valoffset.l = (u_long)
|
|
(info->img_cmpr.opts.grp4 & ~((u_long) LEAD_EOL));
|
|
required_numtags++;
|
|
}
|
|
|
|
ifd->entry[n].tag = (u_short) TAG_RESOLUTIONUNIT;
|
|
ifd->entry[n].type = (u_short) TYPE_USHORT;
|
|
ifd->entry[n].len = (u_long) 1;
|
|
if ((info->res_unit == 0L) || (info->res_unit > 3) )
|
|
info->res_unit = (u_long) NO_ABSOLUTE_MEASURE;
|
|
ifd->entry[n++].valoffset.s = (u_short) info->res_unit;
|
|
|
|
/* TAG_PAGENUMBER is here */
|
|
|
|
/* only allow this to be output if the image is appropriate color type*/
|
|
if (info->img_clr.img_interp == (u_long) GFS_PSEUDO)
|
|
{
|
|
if ( bldifde_tb((struct _gfct FAR *) fct,
|
|
(struct _ifd FAR *) ifd,
|
|
(int FAR *) &n, (long FAR *) &fp, TAG_COLORRESPONSECURVE,
|
|
(struct gfstidbit FAR *) &info->PSEUDO_RCRV,
|
|
TYPE_USHORT) < 0)
|
|
return( (int) -1);
|
|
|
|
}
|
|
|
|
ifd->entry[n].tag = (u_short) TAG_SOFTWARE;
|
|
ifd->entry[n].type = (u_short) TYPE_ASCII;
|
|
ifd->entry[n].len = (u_long) sizeof( GFS_STRING);
|
|
ifd->entry[n++].valoffset.l = (u_long) fct->u.tif.cur_data_offset;
|
|
|
|
/* write out ascii data, file pointer in proper place,*/
|
|
/* ascii data does not get byte swapped. */
|
|
if (( bw = (long) write(fct->fildes, (char FAR *) GFS_STRING,
|
|
(unsigned) sizeof(GFS_STRING) )) < 0 )
|
|
return( (int) -1);
|
|
|
|
/* now make sure next offset is on a word boundary, not guarenteed
|
|
that the ascii string just written was a multiple of 4 */
|
|
if ((rem = bw % 4) != 0L)
|
|
{
|
|
rem = 4L - rem;
|
|
if ((fp = lseek(fct->fildes, (long) rem, FROM_CURRENT)) < 0L)
|
|
return( (int) -1);
|
|
}
|
|
|
|
/* if rem was 0 then just offset by bw, else get both changes */
|
|
fct->u.tif.cur_data_offset += (u_long)(bw + rem);
|
|
|
|
|
|
ifd->entrycount += required_numtags;
|
|
|
|
if (info->tidbit != (struct gfstidbit FAR *) NULL )
|
|
{
|
|
if ( bldifde_tb((struct _gfct FAR *) fct, (struct _ifd FAR *) ifd,
|
|
(int FAR *) &n, (long FAR *) &fp, TAG_DATETIME,
|
|
(struct gfstidbit FAR *) &info->TB_DATETIME, TYPE_ASCII) < 0)
|
|
return( (int) -1);
|
|
|
|
if ( bldifde_tb((struct _gfct FAR *) fct, (struct _ifd FAR *) ifd,
|
|
(int FAR *) &n, (long FAR *) &fp, TAG_ARTIST,
|
|
(struct gfstidbit FAR *) &info->TB_ARTIST, TYPE_ASCII) < 0)
|
|
return( (int) -1);
|
|
|
|
if ( bldifde_tb((struct _gfct FAR *) fct, (struct _ifd FAR *) ifd,
|
|
(int FAR *) &n, (long FAR *) &fp, TAG_HOSTCOMPUTER,
|
|
(struct gfstidbit FAR *) &info->TB_HOSTCOMPUTER, TYPE_ASCII)
|
|
< 0)
|
|
return( (int) -1);
|
|
}
|
|
|
|
/* TAG_PREDICTOR is here */
|
|
/* this code will be " shortened" later */
|
|
if (info->img_clr.img_interp == (u_long) GFS_PSEUDO)
|
|
{
|
|
/*COLORIMAGETYPE tag?*/
|
|
if (bldifde_tb((struct _gfct FAR *) fct, (struct _ifd FAR *)ifd,
|
|
(int FAR *) &n, (long FAR *) &fp, TAG_WHITEPOINT,
|
|
(struct gfstidbit FAR *) &info->PSEUDO_WHITEPOINT,
|
|
TYPE_RATIONAL) < 0)
|
|
return( (int) -1);
|
|
|
|
/*COLORLIST tag?*/
|
|
if (bldifde_tb((struct _gfct FAR *) fct, (struct _ifd FAR *)ifd,
|
|
(int FAR *) &n, (long FAR *) &fp, TAG_PRIMARYCHROMS,
|
|
(struct gfstidbit FAR *) &info->PSEUDO_PRIMARYCHROMS,
|
|
TYPE_RATIONAL) < 0)
|
|
return( (int) -1);
|
|
|
|
if (bldifde_tb((struct _gfct FAR *) fct, (struct _ifd FAR *)ifd,
|
|
(int FAR *) &n, (long FAR *) &fp, TAG_COLORMAP,
|
|
(struct gfstidbit FAR *) &info->PSEUDO_MAP, TYPE_USHORT) < 0)
|
|
return( (int) -1);
|
|
}
|
|
else
|
|
{
|
|
if (info->img_clr.img_interp == (u_long) GFS_RGB)
|
|
{
|
|
/*COLORIMAGETYPE tag?*/
|
|
if (bldifde_tb((struct _gfct FAR *) fct, (struct _ifd FAR *)ifd,
|
|
(int FAR *) &n, (long FAR *) &fp, TAG_WHITEPOINT,
|
|
(struct gfstidbit FAR *) &info->RGB_WHITEPOINT,
|
|
TYPE_RATIONAL) < 0)
|
|
return( (int) -1);
|
|
|
|
/*COLORLIST tag?*/
|
|
if (bldifde_tb((struct _gfct FAR *) fct, (struct _ifd FAR *)ifd,
|
|
(int FAR *) &n, (long FAR *) &fp, TAG_PRIMARYCHROMS,
|
|
(struct gfstidbit FAR *) &info->RGB_PRIMARYCHROMS,
|
|
TYPE_RATIONAL) < 0)
|
|
return( (int) -1);
|
|
|
|
}
|
|
} /* end else */
|
|
|
|
/* KMC - new tags for TIFF 6.0 JPEG support */
|
|
if (info->img_cmpr.type == (u_long) JPEG2)
|
|
{
|
|
/* JPEGProc tag */
|
|
ifd->entry[n].tag = (u_short) TAG_JPEGPROC;
|
|
ifd->entry[n].type = (u_short) TYPE_USHORT;
|
|
ifd->entry[n].len = (u_long) 1;
|
|
/* Currently only support Baseline Sequential process */
|
|
ifd->entry[n++].valoffset.s = (u_short) 1;
|
|
ifd->entrycount++;
|
|
|
|
/* JPEGInterchangeFormat tag */
|
|
/* Note: We always write out the interchange format tags.
|
|
*/
|
|
temp_tidbit.ptr = info->img_cmpr.opts.jpeg_info_ptr->jpeg_buffer;
|
|
temp_tidbit.cnt = info->img_cmpr.opts.jpeg_info_ptr->jpeg_buffer_size;
|
|
if ( bldifde_tb((struct _gfct FAR *) fct,
|
|
(struct _ifd FAR *) ifd, (int FAR *) &n, (long FAR *) &fp,
|
|
TAG_JPEGINTFORMAT, (struct gfstidbit FAR *) &temp_tidbit,
|
|
TYPE_ULONG) < 0)
|
|
return( (int) -1);
|
|
/* Now set jpeg_buffer to NULL since GFS doesn't need it anymore.
|
|
It is callers responsibility to free this memory after the
|
|
puti call however.
|
|
*/
|
|
info->img_cmpr.opts.jpeg_info_ptr->jpeg_buffer = NULL;
|
|
|
|
/* JPEGInterchangeFormatLength tag */
|
|
ifd->entry[n].tag = (u_short) TAG_JPEGINTFORMATLENGTH;
|
|
ifd->entry[n].type = (u_short) TYPE_ULONG;
|
|
ifd->entry[n].len = (u_long) 1;
|
|
ifd->entry[n++].valoffset.l = (u_long) info->img_cmpr.opts.jpeg_info_ptr->jpeg_buffer_size;
|
|
ifd->entrycount++;
|
|
|
|
/* JPEGRestartInterval tag */
|
|
ifd->entry[n].tag = (u_short) TAG_JPEGRESTARTINTERVAL;
|
|
ifd->entry[n].type = (u_short) TYPE_USHORT;
|
|
ifd->entry[n].len = (u_long) 1;
|
|
ifd->entry[n++].valoffset.s =
|
|
(u_short) info->img_cmpr.opts.jpeg_info_ptr->jpeg.JpegRestartInterval;
|
|
ifd->entrycount++;
|
|
|
|
/* Note: We must still write out the following 3 tags. Just make
|
|
the offsets point to the appropriate positions in the JPEG
|
|
header that was written to the file.
|
|
*/
|
|
|
|
/* JPEGQTable tag */
|
|
/* If one offset, then it will fit into valoffset field.
|
|
*/
|
|
if (info->Q_TABLE.nNumOffsets == 1)
|
|
{
|
|
ifd->entry[n].tag = (u_short) TAG_JPEGQTABLES;
|
|
ifd->entry[n].type = (u_short) TYPE_ULONG;
|
|
ifd->entry[n].len = (u_long) info->samples_per_pix;
|
|
/* Make sure you point to the right spot within the JPEG header
|
|
which has already been written to the file. Add the new offset
|
|
within the file to the offset from the original buffer to get
|
|
the new offset. Offset from original header buffer must be zero-
|
|
based for this to work.
|
|
*/
|
|
ifd->entry[n].valoffset.l = (u_short) ifd->entry[n-3].valoffset.l +
|
|
info->Q_TABLE.QOffset.Offset;
|
|
ifd->entrycount++;
|
|
n++;
|
|
}
|
|
else if (info->Q_TABLE.nNumOffsets > 1)
|
|
/* If more than one offset, then must write the list out somewhere
|
|
else in the file.
|
|
*/
|
|
{
|
|
/* Adjust the offsets from offsets to the header buffer to offsets
|
|
from the header written to the file.
|
|
*/
|
|
for (loop = 0; loop < info->Q_TABLE.nNumOffsets; ++loop)
|
|
info->Q_TABLE.QOffset.OffsetList[loop] +=
|
|
ifd->entry[n-3].valoffset.l;
|
|
temp_tidbit.ptr = (char FAR *)info->Q_TABLE.QOffset.OffsetList;
|
|
/* kmc - temp_tidbit.cnt should be total size in bytes of data
|
|
it points to, in this case the data in the OffsetList
|
|
array, not the number of values in the array. Same
|
|
applies for DC and AC tables.
|
|
*/
|
|
temp_tidbit.cnt = (info->Q_TABLE.nNumOffsets)*(sizeof(u_long));
|
|
/* Write the offset list to the file.
|
|
*/
|
|
if ( bldifde_tb((struct _gfct FAR *) fct,
|
|
(struct _ifd FAR *) ifd, (int FAR *) &n, (long FAR *) &fp,
|
|
TAG_JPEGQTABLES, (struct gfstidbit FAR *) &temp_tidbit,
|
|
TYPE_ULONG) < 0)
|
|
return( (int) -1);
|
|
}
|
|
|
|
/* JPEGDCTable tag */
|
|
/* The process for writing the DC table tag is exactly the same as
|
|
that for the Q table. See comments above for the Q table tag write
|
|
for info on the process.
|
|
*/
|
|
if (info->DC_TABLE.nNumOffsets == 1)
|
|
{
|
|
ifd->entry[n].tag = (u_short) TAG_JPEGDCTABLES;
|
|
ifd->entry[n].type = (u_short) TYPE_ULONG;
|
|
ifd->entry[n].len = (u_long) info->samples_per_pix;
|
|
ifd->entry[n].valoffset.l = (u_short) ifd->entry[n-4].valoffset.l +
|
|
info->DC_TABLE.DcOffset.Offset;
|
|
ifd->entrycount++;
|
|
n++;
|
|
}
|
|
else if (info->DC_TABLE.nNumOffsets > 1)
|
|
{
|
|
for (loop = 0; loop < info->DC_TABLE.nNumOffsets; ++loop)
|
|
info->DC_TABLE.DcOffset.OffsetList[loop] +=
|
|
ifd->entry[n-4].valoffset.l;
|
|
temp_tidbit.ptr = (char FAR *)info->DC_TABLE.DcOffset.OffsetList;
|
|
temp_tidbit.cnt = (info->DC_TABLE.nNumOffsets)*(sizeof(u_long));
|
|
if ( bldifde_tb((struct _gfct FAR *) fct,
|
|
(struct _ifd FAR *) ifd, (int FAR *) &n, (long FAR *) &fp,
|
|
TAG_JPEGDCTABLES, (struct gfstidbit FAR *) &temp_tidbit,
|
|
TYPE_ULONG) < 0)
|
|
return( (int) -1);
|
|
}
|
|
|
|
/* JPEGACTable tag */
|
|
/* The process for writing the AC table tag is exactly the same as
|
|
that for the Q table. See comments above for the Q table tag write
|
|
for info on the process.
|
|
*/
|
|
if (info->AC_TABLE.nNumOffsets == 1)
|
|
{
|
|
ifd->entry[n].tag = (u_short) TAG_JPEGACTABLES;
|
|
ifd->entry[n].type = (u_short) TYPE_ULONG;
|
|
ifd->entry[n].len = (u_long) info->samples_per_pix;
|
|
ifd->entry[n].valoffset.l = (u_short) ifd->entry[n-5].valoffset.l +
|
|
info->AC_TABLE.AcOffset.Offset;
|
|
ifd->entrycount++;
|
|
n++;
|
|
}
|
|
else if (info->AC_TABLE.nNumOffsets > 1)
|
|
{
|
|
for (loop = 0; loop < info->AC_TABLE.nNumOffsets; ++loop)
|
|
info->AC_TABLE.AcOffset.OffsetList[loop] +=
|
|
ifd->entry[n-5].valoffset.l;
|
|
temp_tidbit.ptr = (char FAR *)info->AC_TABLE.AcOffset.OffsetList;
|
|
temp_tidbit.cnt = (info->DC_TABLE.nNumOffsets)*(sizeof(u_long));
|
|
if ( bldifde_tb((struct _gfct FAR *) fct,
|
|
(struct _ifd FAR *) ifd, (int FAR *) &n, (long FAR *) &fp,
|
|
TAG_JPEGACTABLES, (struct gfstidbit FAR *) &temp_tidbit,
|
|
TYPE_ULONG) < 0)
|
|
return( (int) -1);
|
|
}
|
|
/* KMC - write out YCbCr SubSampling tag if using YCbCr color space (color images
|
|
only). NOTE: The horizontal and vertical subsample values are stored in
|
|
info->img_cmpr.opts.jpeg_info_ptr->jpegbits, which is a u_long. The first two
|
|
bytes contain the YCbCrSubsampleHoriz factor in bits 14, 15 and the last two
|
|
bytes (bits 16 - 31) contain the YCbCrSubsampleVert factor. Note, the first
|
|
2 bytes of ...jpegbits also contain the JPEG chrominance and luminance values
|
|
(they are equal to each other and also called the quality), in bits 0-6 and
|
|
7-13 respectively. Neither of these values are used here however.
|
|
*/
|
|
if (info->img_clr.img_interp == GFS_YCBCR)
|
|
{
|
|
ifd->entry[n].tag = (u_short) TAG_YCBCRSUBSAMPLING;
|
|
ifd->entry[n].type = (u_short) TYPE_USHORT;
|
|
ifd->entry[n].len = (u_long) 2;
|
|
|
|
/* KMC, get horizontal, vertical subsample info from jpegbits field in info structure.
|
|
Horizontal is in bits 14, 15 and has a value of either 0, 1, or 2 for low,
|
|
med, high resolutions respectively. Need to set actual subsample value which
|
|
corresponds to each resoluiton value (4, 2, 1 for low, med, high resolutions
|
|
respectively). Vertical resolution is in 3rd, 4th bytes (bits 16 - 31) of grp3
|
|
field. Put horizontal subsample in first 2 bytes, vertical in second 2 bytes
|
|
of the tag's value/offset.
|
|
*/
|
|
horiz_sub_sample = (info->img_cmpr.opts.jpeg_info_ptr->jpegbits & 0x0000C000);
|
|
horiz_sub_sample >>= 14; /* kmc, shift to first two bits. */
|
|
if (horiz_sub_sample == 0)
|
|
horiz_sub_sample = 4;
|
|
else if (horiz_sub_sample == 1)
|
|
horiz_sub_sample = 2;
|
|
else if (horiz_sub_sample == 2)
|
|
horiz_sub_sample = 1;
|
|
vert_sub_sample = (info->img_cmpr.opts.jpeg_info_ptr->jpegbits & 0xFFFF0000);
|
|
|
|
ifd->entry[n++].valoffset.l = (horiz_sub_sample | vert_sub_sample);
|
|
ifd->entrycount++;
|
|
}
|
|
|
|
/* Now set jpeg_info pointer to NULL because we don't need it anymore. */
|
|
/* It is caller's responsibility to free this memory however. */
|
|
info->img_cmpr.opts.jpeg_info_ptr = NULL;
|
|
|
|
} /* end of if JPEG2 */
|
|
|
|
/* If first image of page 0 then need to add the TOC tag to the ifd. */
|
|
/* Don't write old TOC tag anymore. We have a new one. */
|
|
/*
|
|
if ( (fct->curr_page == 0) &&
|
|
((fct->PAGE_STATUS & (char) PAGE_INIT ) == (char) 0 ))
|
|
{
|
|
fct->u.tif.toc_tag_index = n;
|
|
ifd->entry[n].tag = (u_short) TAG_TOC;
|
|
ifd->entry[n].type = (u_short) TYPE_ULONG;
|
|
ifd->entry[n].len = (u_long) 1;
|
|
ifd->entry[n++].valoffset.l = (u_long) NULL;
|
|
ifd->entrycount++;
|
|
}
|
|
*/
|
|
|
|
if ((fct->PAGE_STATUS & (char) PAGE_INIT) == (char) 0)
|
|
{
|
|
if (fct->curr_page == 0)
|
|
fct->u.tif.toc_tag_index = n;
|
|
ifd->entry[n].tag = (u_short) TAG_TOC2;
|
|
ifd->entry[n].type = (u_short) TYPE_ULONG;
|
|
ifd->entry[n].len = (u_long) 1;
|
|
ifd->entry[n++].valoffset.l = (u_long) NULL;
|
|
ifd->entrycount++;
|
|
}
|
|
|
|
return ( (int) 0);
|
|
}
|
|
|
|
/***************************************************************/
|
|
/*
|
|
* write out an ifd
|
|
*
|
|
*/
|
|
int FAR PASCAL writeifd(fct, last_ifd ) /*errno_KEY*/
|
|
struct _gfct FAR *fct;
|
|
char last_ifd; /* TRUE if last one for page, FALSE if more to come */
|
|
{
|
|
long fp;
|
|
int totsize; /* tmp variable for byte count */
|
|
struct _idh idh;
|
|
struct typetbl ttbl[3];
|
|
int cnt;
|
|
unsigned short i;
|
|
register struct _ifd FAR *ifd;
|
|
struct _ifd tmpifd; /* use this for stuff going into idh */
|
|
struct _ifd FAR *ptmpifd; /* use this for stuff going into idh */
|
|
int tagentry; /* for annotation options */
|
|
unsigned long prev_ifd_offset;
|
|
unsigned long prev_next_ifd;
|
|
unsigned long curr_next_ifd;
|
|
struct _ifd prev_ifd;
|
|
char flag;
|
|
WORD wbytes;
|
|
|
|
flag = (char) GFS_SKIPLOOKUP;
|
|
|
|
ifd = (struct _ifd FAR *) fct->u.tif.ifd; /* simplify addressing */
|
|
ptmpifd = ifd;
|
|
|
|
/* If there is Hi-TIFF data, add the tag to the ifd.
|
|
*/
|
|
if (fct->u.tif.hitiff_data_length)
|
|
{
|
|
/* Since we don't write any tags > TOC2 tag (and we always write TOC2 tag)
|
|
and we HAVEN'T WRITTEN THE ANNOTATION TAG YET (!!), then we can put
|
|
the Hi-TIFF tag just before the TOC2 tag, as follows. Note that the
|
|
annotation tag has to be written AFTER this one, since it's higher
|
|
numerically and will use the same shift-and-plop scheme
|
|
*/
|
|
/* First, move the TOC2 tag up one in the IFD. */
|
|
tagentry = fct->u.tif.ifd->entrycount;
|
|
fct->u.tif.ifd->entry[tagentry].tag = fct->u.tif.ifd->entry[tagentry-1].tag;
|
|
fct->u.tif.ifd->entry[tagentry].type = fct->u.tif.ifd->entry[tagentry-1].type;
|
|
fct->u.tif.ifd->entry[tagentry].len = fct->u.tif.ifd->entry[tagentry-1].len;
|
|
fct->u.tif.ifd->entry[tagentry].valoffset.l =
|
|
fct->u.tif.ifd->entry[tagentry-1].valoffset.l;
|
|
|
|
/* Now insert the Hi-TIFF tag where the TOC2 tag was. */
|
|
tagentry = fct->u.tif.ifd->entrycount;
|
|
fct->u.tif.ifd->entry[tagentry-1].tag = (u_short)TAG_HITIFF;
|
|
fct->u.tif.ifd->entry[tagentry-1].type = (u_short)TYPE_BYTE;
|
|
fct->u.tif.ifd->entry[tagentry-1].len =
|
|
(u_long)fct->u.tif.hitiff_data_length;
|
|
fct->u.tif.ifd->entry[tagentry-1].valoffset.l =
|
|
(u_long)fct->u.tif.hitiff_data_offset;
|
|
++fct->u.tif.ifd->entrycount;
|
|
}
|
|
|
|
/* If there is annotation data, add the annotation tag to the ifd.
|
|
Note that this has to be done AFTER the Hi-TIFF tag (above), since
|
|
it is numerically higher and we're just going to shift out the TOC!
|
|
*/
|
|
if (fct->u.tif.anno_data_length)
|
|
{
|
|
/* Since we don't write any tags > TOC2 tag (and we always write TOC2 tag)
|
|
and we don't write any tags in between the annotation tag and the TOC
|
|
tag, the following is OK.
|
|
*/
|
|
/* First, move the TOC2 tag up one in the IFD. */
|
|
tagentry = fct->u.tif.ifd->entrycount;
|
|
fct->u.tif.ifd->entry[tagentry].tag = fct->u.tif.ifd->entry[tagentry-1].tag;
|
|
fct->u.tif.ifd->entry[tagentry].type = fct->u.tif.ifd->entry[tagentry-1].type;
|
|
fct->u.tif.ifd->entry[tagentry].len = fct->u.tif.ifd->entry[tagentry-1].len;
|
|
fct->u.tif.ifd->entry[tagentry].valoffset.l =
|
|
fct->u.tif.ifd->entry[tagentry-1].valoffset.l;
|
|
|
|
/* Now insert the annotation tag where the TOC2 tag was. */
|
|
tagentry = fct->u.tif.ifd->entrycount;
|
|
fct->u.tif.ifd->entry[tagentry-1].tag = (u_short)TAG_ANNOTATION;
|
|
fct->u.tif.ifd->entry[tagentry-1].type = (u_short)TYPE_BYTE;
|
|
fct->u.tif.ifd->entry[tagentry-1].len =
|
|
(u_long)fct->u.tif.anno_data_length;
|
|
fct->u.tif.ifd->entry[tagentry-1].valoffset.l =
|
|
(u_long)fct->u.tif.anno_data_offset;
|
|
++fct->u.tif.ifd->entrycount;
|
|
}
|
|
|
|
/* Output the stripbytecnts and stripoffsets, this is the last physical
|
|
thing in the file for this particular image. Once this data is written
|
|
we will have the location it was written. These locations are updated
|
|
in the fct->u.tif.ifd, so then the ifd is complete and can be placed in
|
|
the file. (Except for the first ifd, the ifd is written at
|
|
cur_ifd_foffset) */
|
|
|
|
if (write_offs_cnts((struct _gfct FAR *) fct) < 0)
|
|
return( (int) -1);
|
|
|
|
if (last_ifd)
|
|
{
|
|
ifd->next_ifd = (u_long) 0;
|
|
}
|
|
else
|
|
{
|
|
/* Can't update cur_ifd_foffset yet, because have not written the
|
|
current ifd stored in the fct yet.
|
|
*/
|
|
if (GetNextIfdOffset(fct->fildes, &ifd->next_ifd,
|
|
fct->u.tif.toc2_offset) < 0)
|
|
return ((int) -1);
|
|
}
|
|
|
|
if ((fct->PAGE_STATUS & (char) PAGE_INIT ) == (char) 0 )
|
|
{
|
|
/* Check if page 0 and write to file if so. */
|
|
if (fct->curr_page == (u_short) 0)
|
|
{
|
|
if ((WriteOutFirstIFD(fct)) < 0)
|
|
return((int) -1);
|
|
|
|
return( (int) 0);
|
|
|
|
/* The PAGE_INIT bit gets set after the first image of a page is complete.
|
|
If on first image of page 0, the ifh and ifd get put into a tmp file.
|
|
This is done because the offset of the TOC is not written until all
|
|
pages are completed. The TOC offset is contained in page 0 ifd. The
|
|
data (and therefore data offsets and bytecount offsets) have already
|
|
been written to the file and updated in the ifd.
|
|
*/
|
|
if (0) /* This is for old way using TOC. We arn't writing
|
|
those TOCs anymore, but keep this here for now because
|
|
we might need to write those TOCs again at some point.
|
|
*/
|
|
{
|
|
/* Setup the ifh, ifd0 always follows the ifh. */
|
|
idh.ifh.byte_order = (u_short) fct->out_byteorder;
|
|
idh.ifh.ifd0_offset = (u_long) sizeof(struct _ifh);
|
|
|
|
cnt = (int) (sizeof(ifd->entrycount) + (ifd->entrycount * 12));
|
|
|
|
/* Always put in parameter as 0x002A. */
|
|
idh.ifh.tiff_version = (u_short) TIFFVERSION_MM;
|
|
|
|
/* The idh is never used except to put in the temp file, so, it
|
|
can be swapped internally in place, then written to the file.
|
|
*/
|
|
if (fct->out_byteorder != (u_short) SYSBYTEORDER)
|
|
{
|
|
/* (byteorder already ok) */
|
|
ttbl[0].num = 1L; /* the version */
|
|
ttbl[0].type = (u_long) TYPE_USHORT;
|
|
ttbl[1].num = 1L; /* the ifd0 offset*/
|
|
ttbl[1].type = (u_long) TYPE_ULONG;
|
|
swapbytes((char FAR *) &idh.ifh.tiff_version,
|
|
(struct typetbl FAR *) ttbl, 2L, 1L);
|
|
|
|
/* If bytes have to be swapped, still need to be sure values
|
|
in the fct->u.tif.ifd are still valid in memory, so copy
|
|
the ifd to a tmpifd and swap that, then copy it into the
|
|
ifd. Rethink this to avoid so much copying...right now this
|
|
will have to do.
|
|
*/
|
|
(void) memcpy((char FAR *) &tmpifd, (char FAR *) ifd,
|
|
(int) sizeof(struct _ifd));
|
|
|
|
ttbl[0].num = (u_long) 1;
|
|
ttbl[0].type = (u_long) TYPE_USHORT;
|
|
swapbytes((char FAR *) &(tmpifd.entrycount),
|
|
(struct typetbl FAR *) ttbl, 1L, 1L);
|
|
|
|
ttbl[0].num = (u_long) 2;
|
|
ttbl[0].type = (u_long) TYPE_USHORT; /* tag then type */
|
|
ttbl[1].num = (u_long) 1;
|
|
ttbl[1].type = (u_long) TYPE_ULONG; /* length */
|
|
ttbl[2].num = (u_long) sizeof(u_long) ;
|
|
ttbl[2].type = (u_long) TYPE_BYTE; /* skip the valueoffset */
|
|
swapbytes((char FAR *) tmpifd.entry, (struct typetbl FAR *) ttbl,
|
|
3L, (long) ifd->entrycount);
|
|
|
|
/* Now that the valoffset type has been swapped, use it to
|
|
translate valoffset, shorts or everything else as long.
|
|
*/
|
|
for (i=0; i<ifd->entrycount; i++)
|
|
{
|
|
ttbl[0].num = (u_long) 1;
|
|
if ((ifd->entry[i].type == (u_short) TYPE_USHORT) &&
|
|
(ifd->entry[i].len == 1))
|
|
ttbl[0].type = (u_long) TYPE_USHORT;
|
|
else
|
|
ttbl[0].type = (u_long) TYPE_ULONG;
|
|
swapbytes((char FAR *) &(tmpifd.entry[i].valoffset),
|
|
(struct typetbl FAR *) ttbl, 1L, 1L);
|
|
}
|
|
ptmpifd = &tmpifd; /* Use this address. */
|
|
}
|
|
|
|
/* Copy the ifd.entrycount and the ifd.entries[acutal_entries] into
|
|
the idh space. (12 bytes per entry)
|
|
*/
|
|
(void) memcpy((char FAR *) (idh.ifdstuff),
|
|
(char FAR *) &(ptmpifd->entrycount), (int) cnt);
|
|
|
|
/* Now put the ifd.next_ifd offset into location after the entries.
|
|
This value could be 0, put it in the memory loc to be sure it is
|
|
zeroed out.
|
|
*/
|
|
(void) memcpy((char FAR *) (idh.ifdstuff + (u_long) cnt),
|
|
(char FAR *) &(ptmpifd->next_ifd),
|
|
(int) (sizeof(ifd->next_ifd)));
|
|
|
|
/* Clear out ifd for potential future use */
|
|
(void) memset((char FAR *) ifd, (int) 0,
|
|
(int) (sizeof(struct _ifd)));
|
|
|
|
if ( writeidh(fct, (struct _idh FAR *) &idh ) < 0)
|
|
return( (int) -1 );
|
|
|
|
if (puttoc((struct _gfct FAR *) fct, fct->curr_page,
|
|
(u_long) sizeof(struct _ifh), (u_long) 0) < 0 )
|
|
return ( (int) -1);
|
|
|
|
/* this designates the first image of page 0 has been completed*/
|
|
fct->PAGE_STATUS |= (char) PAGE_INIT;
|
|
}
|
|
}
|
|
/* This designates the first image of a page has been completed. */
|
|
fct->PAGE_STATUS |= (char) PAGE_INIT;
|
|
}
|
|
|
|
/* now move the fp to location for output */
|
|
if ( (fp = lseek(fct->fildes, (long) fct->u.tif.cur_ifd_foffset,
|
|
(int) FROM_BEGINNING )) < 0L )
|
|
return( (int) -1 );
|
|
|
|
curr_next_ifd = fp;
|
|
|
|
/* now write the entrycount and entrycount entries of the ifd,
|
|
eliminating pad entry */
|
|
totsize = ifd->entrycount * (int) BYTES_TAGENTRY +
|
|
sizeof(ifd->entrycount);
|
|
|
|
/*********/
|
|
ptmpifd = ifd;
|
|
if (fct->out_byteorder != (u_short) SYSBYTEORDER)
|
|
{
|
|
(void) memcpy( (char FAR *) &tmpifd, (char FAR *) ifd,
|
|
(int) sizeof( struct _ifd ) );
|
|
|
|
ttbl[0].num = (u_long) 1;
|
|
ttbl[0].type = (u_long) TYPE_USHORT;
|
|
swapbytes( (char FAR *) &(tmpifd.entrycount),
|
|
(struct typetbl FAR *) ttbl, 1L, 1L );
|
|
|
|
ttbl[0].num = (u_long) 2;
|
|
ttbl[0].type = (u_long) TYPE_USHORT; /* tag then type */
|
|
ttbl[1].num = (u_long) 1;
|
|
ttbl[1].type = (u_long) TYPE_ULONG; /* length */
|
|
ttbl[2].num = (u_long) sizeof(u_long) ;
|
|
ttbl[2].type = (u_long) TYPE_BYTE; /* skip the valueoffset */
|
|
swapbytes( (char FAR *) tmpifd.entry, (struct typetbl FAR *) ttbl,
|
|
3L, (long) ifd->entrycount);
|
|
|
|
/* use the valoffset type to */
|
|
/* translate valoffset, shorts or everything else as long */
|
|
for (i=0; i<ifd->entrycount; i++)
|
|
{
|
|
ttbl[0].num = (u_long) 1;
|
|
if ((ifd->entry[i].type == (u_short) TYPE_USHORT) &&
|
|
(ifd->entry[i].len == 1) )
|
|
ttbl[0].type = (u_long) TYPE_USHORT;
|
|
else
|
|
ttbl[0].type = (u_long) TYPE_ULONG;
|
|
swapbytes( (char FAR *) &(tmpifd.entry[i].valoffset),
|
|
(struct typetbl FAR *) ttbl, 1L, 1L );
|
|
|
|
}
|
|
ptmpifd = &tmpifd; /* use this address */
|
|
}
|
|
|
|
/*********/
|
|
wbytes = write(fct->fildes, (char FAR *) &(ptmpifd->entrycount),
|
|
(unsigned) (totsize) );
|
|
if ((wbytes == HFILE_ERROR) || (wbytes == 0))
|
|
return ( (int) -1);
|
|
|
|
/* the offset to the next ifd is written next */
|
|
wbytes = write(fct->fildes, (char FAR *) &(ptmpifd->next_ifd),
|
|
(unsigned) (sizeof(ifd->next_ifd)) );
|
|
if ((wbytes == HFILE_ERROR) || (wbytes == 0))
|
|
return ( (int) -1);
|
|
|
|
/*************************************************************************/
|
|
/* The following code places the offset to the current IFD being written */
|
|
/* in the next IFD field of the previous page's IFD. If the page being */
|
|
/* written is being inserted in the file rather than just appended, then */
|
|
/* it is not neccessary to update the previous page's next IFD. */
|
|
/*************************************************************************/
|
|
if ((fct->curr_page != 0) && (fct->u.tif.action != A_INSERT))
|
|
{
|
|
if (GetOffsetFromToc2(fct, (fct->curr_page - 1), (u_long FAR *)
|
|
&prev_ifd_offset, (char) 1) < 0)
|
|
return ((int) -1);
|
|
|
|
if (tfrdifd(fct, fct->out_byteorder, (u_long) 0, prev_ifd_offset,
|
|
fct->type, (struct _ifd FAR *) &prev_ifd, (char) flag) < 0)
|
|
return ((int) -1);
|
|
|
|
prev_next_ifd = prev_ifd_offset +
|
|
(prev_ifd.entrycount*(int)BYTES_TAGENTRY + sizeof(ifd->entrycount));
|
|
|
|
if ((fp = lseek(fct->fildes, (long) prev_next_ifd,
|
|
(int) FROM_BEGINNING)) < 0L)
|
|
return((int) -1);
|
|
|
|
if (writebytes(fct->fildes, (char FAR *) &curr_next_ifd,
|
|
(unsigned) sizeof(curr_next_ifd),
|
|
1, TYPE_ULONG, fct->out_byteorder) < 0L)
|
|
return ((int) -1);
|
|
}
|
|
/*************************************************************************/
|
|
|
|
/* reinitialize the ifd for potential future use */
|
|
(void) memset( (char FAR *) ifd, (int) NULL,
|
|
(int) (sizeof(struct _ifd) ) );
|
|
|
|
/* set PAGE_MAIN of PAGE_STATUS if not set and is a main page */
|
|
/* Have this be a warning not an error, let application handle if desired*/
|
|
if (fct->uinfo.type == (u_long) GFS_MAIN)
|
|
{
|
|
if (fct->PAGE_STATUS & (char) PAGE_MAIN)
|
|
{
|
|
errno = (int) EMULTIPLEMAINSNOTALLOWED;
|
|
return((int) -1);
|
|
}
|
|
else
|
|
fct->PAGE_STATUS &= (char) PAGE_MAIN;
|
|
}
|
|
|
|
/* The following was for writing with the old TOC. It is just commented
|
|
out for now, but may be used in the future.
|
|
if (last_ifd)
|
|
if (puttoc((struct _gfct FAR *) fct,
|
|
fct->curr_page,
|
|
(u_long) fct->u.tif.cur_ifh_offset,
|
|
(u_long) 0) < 0 )
|
|
return ( (int) -1);
|
|
*/
|
|
|
|
/* This places the offset to the IFD being written into the TOC2 list
|
|
for the file. It is placed at the end of the list of offsets.
|
|
*/
|
|
if (PutOffsetInList(fct, fct->curr_page, curr_next_ifd) < 0)
|
|
return ((int) -1);
|
|
|
|
return((int) 0);
|
|
}
|
|
|
|
// NO LONGER USED ** /*****************************************************/
|
|
// NO LONGER USED ** /*
|
|
// NO LONGER USED ** * This function will write the ifh and return the offset, from the beginning
|
|
// NO LONGER USED ** * of the file, that the ifh was written at.
|
|
// NO LONGER USED ** *
|
|
// NO LONGER USED ** */
|
|
// NO LONGER USED ** int FAR PASCAL writeifh(fd, ifh_offset, out_byteorder) /*errno_KEY*/
|
|
// NO LONGER USED ** int fd;
|
|
// NO LONGER USED ** u_long FAR *ifh_offset; /* offset from beginning of file to ifh - for toc */
|
|
// NO LONGER USED ** u_short out_byteorder;
|
|
// NO LONGER USED ** {
|
|
// NO LONGER USED ** long fp;
|
|
// NO LONGER USED ** long rem;
|
|
// NO LONGER USED ** long bw; /* bytes written */
|
|
// NO LONGER USED ** char zerobuf = (char) 0;
|
|
// NO LONGER USED ** struct _ifh ifh;
|
|
// NO LONGER USED ** struct typetbl ttbl[2];
|
|
// NO LONGER USED **
|
|
// NO LONGER USED ** /* setup the ifh, ifd0 always follows the ifh */
|
|
// NO LONGER USED ** ifh.byte_order = out_byteorder;
|
|
// NO LONGER USED ** ifh.ifd0_offset = (u_long) sizeof(struct _ifh);
|
|
// NO LONGER USED **
|
|
// NO LONGER USED ** /* always put in parameter as 0x002A */
|
|
// NO LONGER USED ** ifh.tiff_version = (u_short) TIFFVERSION_MM;
|
|
// NO LONGER USED **
|
|
// NO LONGER USED **
|
|
// NO LONGER USED ** /* next ifh starts at a sector boundary after the end of the file */
|
|
// NO LONGER USED ** if ( (fp = lseek(fd, 0L, (int) FROM_END)) < 0L ) /* moves to end of file */
|
|
// NO LONGER USED ** return( (int) -1 );
|
|
// NO LONGER USED **
|
|
// NO LONGER USED ** /* determine where next sector boundary is */
|
|
// NO LONGER USED ** if ( fp <= (long) SECTOR_BOUNDARY)
|
|
// NO LONGER USED ** rem = (long) ( (long) SECTOR_BOUNDARY - fp);
|
|
// NO LONGER USED ** else
|
|
// NO LONGER USED ** rem = (long) (SECTOR_BOUNDARY - (fp % (long) SECTOR_BOUNDARY));
|
|
// NO LONGER USED **
|
|
// NO LONGER USED ** if (rem > 0)
|
|
// NO LONGER USED ** {
|
|
// NO LONGER USED ** /* pad with 0, rem bytes after curr. loc gets to sector boundary */
|
|
// NO LONGER USED ** bw = write(fd, (char FAR *) &zerobuf, (unsigned) rem);
|
|
// NO LONGER USED ** if ((bw == HFILE_ERROR) || (bw == 0))
|
|
// NO LONGER USED ** return( (int) -1);
|
|
// NO LONGER USED ** }
|
|
// NO LONGER USED **
|
|
// NO LONGER USED ** if (out_byteorder != (u_short) SYSBYTEORDER)
|
|
// NO LONGER USED ** {
|
|
// NO LONGER USED ** ttbl[0].num = 2L;
|
|
// NO LONGER USED ** ttbl[0].type = (u_long) TYPE_USHORT;
|
|
// NO LONGER USED ** ttbl[1].num = 1L;
|
|
// NO LONGER USED ** ttbl[1].type = (u_long) TYPE_ULONG;
|
|
// NO LONGER USED ** bw = (long) w_swapbytes(fd, (long) sizeof( struct _ifh),
|
|
// NO LONGER USED ** (char FAR *) &ifh,
|
|
// NO LONGER USED ** (struct typetbl FAR *) ttbl, 2L, 1L);
|
|
// NO LONGER USED ** }
|
|
// NO LONGER USED ** else
|
|
// NO LONGER USED ** {
|
|
// NO LONGER USED ** bw = (long) write(fd,(char FAR *) &ifh, (unsigned) sizeof(struct _ifh));
|
|
// NO LONGER USED ** }
|
|
// NO LONGER USED **
|
|
// NO LONGER USED ** if (bw < 0L)
|
|
// NO LONGER USED ** return( (int) -1);
|
|
// NO LONGER USED **
|
|
// NO LONGER USED ** /* this is the location the ifh was written at */
|
|
// NO LONGER USED ** *ifh_offset = (u_long) (fp + rem) ;
|
|
// NO LONGER USED **
|
|
// NO LONGER USED ** return( (int) 0);
|
|
// NO LONGER USED ** }
|
|
|
|
/********************************************************************/
|
|
/*
|
|
* calculate where image data will start, do it on a SECTOR BOUNDARY
|
|
*
|
|
*/
|
|
int getdataoffs(fct, boundary) /*errno_KEY*/
|
|
struct _gfct FAR *fct;
|
|
char boundary; /* TRUE if align on BOUNDARY */
|
|
{
|
|
long fp;
|
|
long rem;
|
|
char zerobuf = 0;
|
|
WORD bw;
|
|
|
|
/* if first image of page 0 - point to beyond idh stuff */
|
|
if ( (fct->curr_page == 0) && ((fct->PAGE_STATUS & (char) PAGE_INIT) == 0) )
|
|
{
|
|
fct->u.tif.cur_data_offset = (u_long) IDH_SIZE;
|
|
fct->u.tif.cur_ifd_foffset = 8L; /* never really writes to here*/
|
|
return( (int) 0);
|
|
}
|
|
|
|
/* data starts right after the ifd structure */
|
|
fct->u.tif.cur_data_offset = fct->u.tif.cur_ifd_foffset
|
|
+ (u_long) sizeof(struct _ifd);
|
|
/* now update the file to move there */
|
|
if ((fp = lseek( fct->fildes, (long) fct->u.tif.cur_data_offset,
|
|
(int) FROM_BEGINNING)) < 0)
|
|
return( (int) -1);
|
|
|
|
if (boundary)
|
|
{
|
|
/* determine where sector boundary is */
|
|
if (fp <= (long) SECTOR_BOUNDARY)
|
|
rem = (long) (SECTOR_BOUNDARY - fp);
|
|
else
|
|
rem = (long) (SECTOR_BOUNDARY - (fp % (long) SECTOR_BOUNDARY));
|
|
|
|
if (rem < 0)
|
|
{
|
|
/* pad with 0, rem bytes up to sector boundary */
|
|
bw = write( fct->fildes,(char FAR *) &zerobuf,(unsigned) rem);
|
|
if ((bw == HFILE_ERROR) || (bw == 0))
|
|
return( (int) -1);
|
|
}
|
|
fct->u.tif.cur_data_offset = (u_long) (fp + rem);
|
|
}
|
|
|
|
return( (int) 0);
|
|
}
|
|
|
|
/*****************************************************************
|
|
*
|
|
* output the stripbytecnts and stripoffsets, update ifd entries
|
|
*
|
|
*/
|
|
int write_offs_cnts(fct) /*errno_KEY*/
|
|
struct _gfct FAR *fct;
|
|
{
|
|
long fp;
|
|
long bw;
|
|
int sz;
|
|
struct typetbl ttbl[1];
|
|
long rem;
|
|
|
|
if (fct->u.tif.cur_strip == (int) 0)
|
|
{
|
|
/* put the value into the ifd, value will be swapped later */
|
|
fct->u.tif.ifd->entry[fct->u.tif.stripoffset_index].valoffset.l =
|
|
(u_long) *(fct->u.tif.offsets->ptr.l);
|
|
fct->u.tif.ifd->entry[fct->u.tif.bytecnt_index].valoffset.l =
|
|
(u_long) *(fct->u.tif.bytecnt->ptr.l);
|
|
}
|
|
else
|
|
{
|
|
/* put it at end of file, cur_data_offset should be pointing here */
|
|
if ( (fp = lseek( fct->fildes, 0L, FROM_END) ) < 0L)
|
|
return( (int) -1);
|
|
|
|
|
|
/* word align the fp and move file pointer there, the next offset
|
|
(the one for the offsets) will be automatically word aligned. */
|
|
if ((rem = fp % 4) != 0L)
|
|
{
|
|
rem = 4L - rem;
|
|
/* need to move the file pointer a few more bytes */
|
|
if( (fp = lseek( fct->fildes, rem, FROM_CURRENT)) < 0L)
|
|
return( (int) -1);
|
|
}
|
|
/* Write data at fp. */
|
|
fct->u.tif.ifd->entry[fct->u.tif.bytecnt_index].valoffset.l
|
|
= (u_long) fp;
|
|
|
|
sz = sizeof(u_long) * (fct->u.tif.cur_strip + 1);
|
|
|
|
/* put the bytecnts into the desired byteorder */
|
|
if (fct->out_byteorder != (u_short) SYSBYTEORDER)
|
|
{
|
|
ttbl[0].num = (u_long) (fct->u.tif.cur_strip + 1);
|
|
ttbl[0].type = (u_long) TYPE_ULONG;
|
|
bw = (long) w_swapbytes(fct->fildes, (long) sz,
|
|
(char FAR *) fct->u.tif.bytecnt->ptr.l,
|
|
(struct typetbl FAR *) ttbl, 1L, 1L);
|
|
}
|
|
else
|
|
{
|
|
bw = (long) write(fct->fildes,
|
|
(char FAR *) fct->u.tif.bytecnt->ptr.l, (unsigned) sz);
|
|
}
|
|
|
|
if (bw < 0L)
|
|
return( (int) -1);
|
|
|
|
/* the next offset value to be used in the file is guarenteed to be
|
|
a mulitple of 4, cuz already word aligned and then wrote sz number
|
|
of u_longs to the file, so no need to recheck */
|
|
|
|
fct->u.tif.ifd->entry[fct->u.tif.stripoffset_index].valoffset.l
|
|
= (u_long) fp + (u_long) bw;
|
|
|
|
fct->u.tif.cur_data_offset = (u_long) (fp + (u_long) bw);
|
|
|
|
/* put the offsets into the desired byteorder */
|
|
if (fct->out_byteorder != (u_short) SYSBYTEORDER)
|
|
{
|
|
/* ttbl has same values in it as last used, so don't redo */
|
|
bw = (long) w_swapbytes(fct->fildes, (long) sz,
|
|
(char FAR *) fct->u.tif.offsets->ptr.l,
|
|
(struct typetbl FAR *) ttbl, 1L, 1L);
|
|
}
|
|
else
|
|
{
|
|
bw = (long) write(fct->fildes,
|
|
(char FAR *) fct->u.tif.offsets->ptr.l, (unsigned) sz);
|
|
}
|
|
|
|
if (bw < 0L)
|
|
return( (int) -1);
|
|
|
|
fct->u.tif.cur_data_offset += (u_long) bw;
|
|
}
|
|
|
|
/* put the correct #of values into len field */
|
|
fct->u.tif.ifd->entry[fct->u.tif.bytecnt_index].len =
|
|
(u_long) (fct->u.tif.cur_strip + 1L);
|
|
|
|
/* put the correct #of values into len field */
|
|
fct->u.tif.ifd->entry[fct->u.tif.stripoffset_index].len =
|
|
(u_long) (fct->u.tif.cur_strip + 1L);
|
|
|
|
|
|
/* free offsets and bytecnts data space */
|
|
if (fct->u.tif.offsets != (struct _strip FAR *) NULL)
|
|
{
|
|
if ( fct->u.tif.offsets->ptr.l != (u_long FAR *) NULL)
|
|
free( (char FAR *) fct->u.tif.offsets->ptr.l);
|
|
free( (char FAR *) fct->u.tif.offsets );
|
|
fct->u.tif.offsets = (struct _strip FAR *) NULL;
|
|
}
|
|
|
|
if (fct->u.tif.bytecnt != (struct _strip FAR *) NULL)
|
|
{
|
|
if (fct->u.tif.bytecnt->ptr.l != (u_long FAR *) NULL)
|
|
free( (char FAR *) fct->u.tif.bytecnt->ptr.l);
|
|
free( (char FAR *) fct->u.tif.bytecnt );
|
|
fct->u.tif.bytecnt = (struct _strip FAR *) NULL;
|
|
}
|
|
|
|
return( (int) 0);
|
|
|
|
}
|
|
#endif
|