a8193c438f
- Existing EXIF field definition of tags is upgraded to EXIF version 2.3.2
- EXIF-GPS structure, tags and access functions are added as special CustomDirectory (like it was done for EXIF).
- Test program custom_dir_EXIF_231.c added to test writing/reading of EXID IFD and GPS IFD tags
and to highlight some quirks of IFD-handling and peculiarities of reading/writing the different data types.
- Reading error for FileSource and SceneType tags corrected.
- EXIF_GPS_upgrade rebased onto c8c5309b76
(Merge branch 'Rational2DoublePrecision_correction' into 'master')
and adapted:
- tif_dirinfo.c: All rational tags set to TIFF_SETGET_FLOAT but only the GPSTAG_ tags set to TIFF_SETGET_DOUBLE.
- custom_dir_EXIF_231.c: Editorials amended and gcc warnigs fixed.
- CMakeLists.txt: add_test(NAME "custom_dir_EXIF_231" COMMAND "custom_dir_EXIF_231") added.
1399 lines
58 KiB
C
1399 lines
58 KiB
C
|
|
/*
|
|
* Copyright (c) 2012, Frank Warmerdam <warmerdam@pobox.com>
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software and
|
|
* its documentation for any purpose is hereby granted without fee, provided
|
|
* that (i) the above copyright notices and this permission notice appear in
|
|
* all copies of the software and related documentation, and (ii) the names of
|
|
* Sam Leffler and Silicon Graphics may not be used in any advertising or
|
|
* publicity relating to the software without the specific, prior written
|
|
* permission of Sam Leffler and Silicon Graphics.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
|
|
* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
|
*
|
|
* IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
|
|
* ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
|
|
* OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
|
* WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
|
|
* LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
|
* OF THIS SOFTWARE.
|
|
*/
|
|
|
|
/*
|
|
* TIFF Library
|
|
*
|
|
* -- Module copied from custom_dir.c --
|
|
*=========== Purpose ===================================================================================
|
|
* Extended and amended version for testing of EXIF 2.32, GPS and handling of custom fields.
|
|
* EXIF 2.32 and GPS are defined in amended files tif_dirinfo.c, tif_dirread.c, tiff.h, tiffio.h, tif_dir.h, tif_dir.c
|
|
*
|
|
*-- ATTENTION: After the upgrade with Rational2Double, the GPSTAG values are defined as double precision
|
|
* and need to be written and also read in double precision!
|
|
* In order to maintain this code for both cases, it is checked above if the TiffLibrary is
|
|
* compiled with the new interface with Rational2Double or still uses the old definitions,
|
|
* by setting blnIsRational2Double above.
|
|
*
|
|
*/
|
|
|
|
|
|
/*------------
|
|
* This version writes the GPS and EXIF tags correctly, without additonal main-IFD and parameters!
|
|
* In contrary, custom_dir.c does write additional main-IFD and parameters to file.
|
|
-------------*/
|
|
|
|
|
|
#define FOR_AUTO_TESTING
|
|
#ifdef FOR_AUTO_TESTING
|
|
/* Only for automake and CMake infrastructure the test should:
|
|
a.) delete any written testfiles when test passed (otherwise autotest will fail)
|
|
b.) goto failure, if any failure is detected, which is not necessary when test is initiated manually for debugging
|
|
*/
|
|
#define GOTOFAILURE goto failure;
|
|
#define GOTOFAILURE_GPS goto failure;
|
|
#define GOTOFAILURE_ALL_EXIF goto failure;
|
|
#else
|
|
#define GOTOFAILURE
|
|
#define GOTOFAILURE_GPS
|
|
#define GOTOFAILURE_ALL_EXIF
|
|
#endif
|
|
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning( disable : 4101)
|
|
#endif
|
|
|
|
#include "tif_config.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <errno.h>
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
# include <unistd.h>
|
|
#endif
|
|
|
|
#include "tiffio.h"
|
|
#include "tiffiop.h"
|
|
#include "tif_dir.h"
|
|
#include "tifftest.h"
|
|
|
|
|
|
|
|
int write_test_tiff(TIFF *tif, const char *filenameRead);
|
|
|
|
static const char filename[] = "custom_dir_EXIF_231.tif";
|
|
static const char filenameBigTiff[] = "custom_dir_EXIF_231_Big.tif";
|
|
|
|
#define SPP 3 /* Samples per pixel */
|
|
const uint16 width = 1;
|
|
const uint16 length = 1;
|
|
const uint16 bps = 8;
|
|
const uint16 photometric = PHOTOMETRIC_RGB;
|
|
const uint16 rows_per_strip = 1;
|
|
const uint16 planarconfig = PLANARCONFIG_CONTIG;
|
|
|
|
|
|
int
|
|
main()
|
|
{
|
|
TIFF *tif;
|
|
int ret, ret1, ret2;
|
|
|
|
fprintf(stderr, "==== Test automatically if all EXIF and GPS tags are written/read correctly. ====\n");
|
|
/* --- Test with Classic-TIFF ---*/
|
|
/* delete file, if exists */
|
|
ret = unlink(filename);
|
|
if (ret != 0 && errno != ENOENT) {
|
|
fprintf(stderr, "Can't delete test TIFF file %s.\n", filename);
|
|
}
|
|
|
|
/* We write the main directory as a simple image. */
|
|
tif = TIFFOpen(filename, "w+");
|
|
if (!tif) {
|
|
fprintf(stderr, "Can't create test TIFF file %s.\n", filename);
|
|
return 1;
|
|
}
|
|
fprintf(stderr, "-------- Test with ClassicTIFF started ----------\n");
|
|
ret1 = write_test_tiff(tif, filename);
|
|
|
|
if (ret1 > 0) return(ret1);
|
|
|
|
/*--- Test with BIG-TIFF ---*/
|
|
/* delete file, if exists */
|
|
ret = unlink(filenameBigTiff);
|
|
if (ret != 0 && errno != ENOENT) {
|
|
fprintf(stderr, "Can't delete test TIFF file %s.\n", filenameBigTiff);
|
|
}
|
|
|
|
tif = TIFFOpen(filenameBigTiff, "w8");
|
|
if (!tif) {
|
|
fprintf(stderr, "Can't create test TIFF file %s.\n", filenameBigTiff);
|
|
return 1;
|
|
}
|
|
fprintf(stderr, "\n\n-------- Test with BigTIFF started ----------\n");
|
|
ret2 = write_test_tiff(tif, filenameBigTiff);
|
|
|
|
if (ret2 > 0) return(ret2 + 10); else return(ret2);
|
|
|
|
} /* main() */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
write_test_tiff(TIFF *tif, const char *filenameRead)
|
|
{
|
|
unsigned char buf[SPP] = { 0, 127, 255 };
|
|
uint64 dir_offset = 0;
|
|
uint64 dir_offset_GPS = 0, dir_offset_EXIF = 0;
|
|
uint64 read_dir_offset = 0;
|
|
/*-- Additional variables --*/
|
|
int retCode, retCode2;
|
|
unsigned char exifVersion[4] = {'0','2','3','1'}; /* EXIF 2.31 version is 4 characters of a string! */
|
|
unsigned char gpsVersion[4] = {2,2,0,1}; /* GPS Version is 4 numbers! */
|
|
unsigned char *pGpsVersion;
|
|
float auxFloat = 0.0f;
|
|
double auxDouble = 0.0;
|
|
char auxChar = 0;
|
|
uint32 auxUint32 = 0;
|
|
short auxShort=0;
|
|
long auxLong = 0;
|
|
void *pVoid;
|
|
int blnIsRational2Double;
|
|
|
|
int i, j;
|
|
long nTags;
|
|
|
|
const TIFFFieldArray* tFieldArray;
|
|
unsigned long tTag;
|
|
TIFFDataType tType;
|
|
short tWriteCount;
|
|
TIFFSetGetFieldType tSetFieldType;
|
|
char *tFieldName;
|
|
const TIFFField *fip;
|
|
|
|
char blnFillGPSManually = 1;
|
|
|
|
#define STRSIZE 1000
|
|
#define N_SIZE 120
|
|
#define VARIABLE_ARRAY_SIZE 6
|
|
|
|
/* -- Test data for writing -- */
|
|
char auxCharArrayW[N_SIZE];
|
|
short auxShortArrayW[N_SIZE];
|
|
long auxLongArrayW[N_SIZE];
|
|
float auxFloatArrayW[N_SIZE];
|
|
double auxDoubleArrayW[N_SIZE];
|
|
char auxTextArrayW[N_SIZE][STRSIZE];
|
|
double auxDoubleArrayGPS1[3] = {1.0/7.0, 61.23456789012345, 62.0};
|
|
double auxDoubleArrayGPS2[3] = {1.0/19.0, 88.34434, 15.12345678901234567890};
|
|
double auxDoubleArrayGPSTime[3] = {22.0, 17.0, 15.3456789};
|
|
double auxDoubleGPSAltitude = 3456.0;
|
|
double auxDoubleGPSDirection = 63.7;
|
|
float auxFloatArrayN1[3] = { 1.0f / 7.0f, 61.23456789012345f, 62.3f };
|
|
float auxFloatArrayN2[3] = { -1.0f / 7.0f, -61.23456789012345f, -62.3f };
|
|
|
|
/* -- Variables for reading -- */
|
|
uint16 count16 = 0;
|
|
union {
|
|
long Long;
|
|
short Short1;
|
|
short Short2[2];
|
|
char Char[4];
|
|
} unionLong;
|
|
union {
|
|
double dbl;
|
|
float flt1;
|
|
float flt2;
|
|
} auxDblUnion;
|
|
void *pVoidArray;
|
|
char *pAscii;
|
|
char auxCharArray[2*STRSIZE];
|
|
short auxShortArray[2*N_SIZE];
|
|
long auxLongArray[2*N_SIZE];
|
|
float auxFloatArray[2*N_SIZE];
|
|
double auxDoubleArray[2*N_SIZE];
|
|
double dblDiff, dblDiffLimit;
|
|
#define RATIONAL_EPS (1.0/30000.0) /* reduced difference of rational values, approx 3.3e-5 */
|
|
|
|
/*-- Fill test data arrays for writing ----------- */
|
|
for (i=0; i<N_SIZE; i++) {
|
|
sprintf(auxTextArrayW[i],"N%d-String-%d_tttttttttttttttttttttttttttttx", i, i);
|
|
}
|
|
for (i=0; i<N_SIZE; i++) {
|
|
auxCharArrayW[i] = (char)(i+1);
|
|
}
|
|
for (i=0; i<N_SIZE; i++) {
|
|
auxShortArrayW[i] = (short)(i+1)*7;
|
|
}
|
|
for (i=0; i<N_SIZE; i++) {
|
|
auxLongArrayW[i] = (i+1)*133;
|
|
}
|
|
for (i=0; i<N_SIZE; i++) {
|
|
auxFloatArrayW[i] = (float)((i+1)*133)/3.3f;
|
|
}
|
|
for (i=0; i<N_SIZE; i++) {
|
|
auxDoubleArrayW[i] = (double)((i+1)*3689)/4.5697;
|
|
}
|
|
|
|
/*-- Setup standard tags of a simple tiff file --*/
|
|
if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width)) {
|
|
fprintf (stderr, "Can't set ImageWidth tag.\n");
|
|
goto failure;
|
|
}
|
|
if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH, length)) {
|
|
fprintf (stderr, "Can't set ImageLength tag.\n");
|
|
goto failure;
|
|
}
|
|
if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps)) {
|
|
fprintf (stderr, "Can't set BitsPerSample tag.\n");
|
|
goto failure;
|
|
}
|
|
if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, SPP)) {
|
|
fprintf (stderr, "Can't set SamplesPerPixel tag.\n");
|
|
goto failure;
|
|
}
|
|
if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rows_per_strip)) {
|
|
fprintf (stderr, "Can't set SamplesPerPixel tag.\n");
|
|
goto failure;
|
|
}
|
|
if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, planarconfig)) {
|
|
fprintf (stderr, "Can't set PlanarConfiguration tag.\n");
|
|
goto failure;
|
|
}
|
|
if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photometric)) {
|
|
fprintf (stderr, "Can't set PhotometricInterpretation tag.\n");
|
|
goto failure;
|
|
}
|
|
|
|
#define ADDITIONAL_TAGS
|
|
#ifdef ADDITIONAL_TAGS
|
|
/*-- Additional tags to check Rational standard tags, which are also defined as FIELD_CUSTOM */
|
|
|
|
/*- TIFFTAG_INKSET is a SHORT parameter (TIFF_SHORT, TIFF_SETGET_UINT16) with field_bit=FIELD_CUSTOM !! -*/
|
|
if (!TIFFSetField(tif, TIFFTAG_INKSET, 34)) {
|
|
fprintf(stderr, "Can't set TIFFTAG_INKSET tag.\n");
|
|
goto failure;
|
|
}
|
|
|
|
/*- TIFFTAG_PIXAR_FOVCOT is a FLOAT parameter ( TIFF_FLOAT, TIFF_SETGET_FLOAT) with field_bit=FIELD_CUSTOM !! -*/
|
|
/* - can be written with Double but has to be read with float parameter */
|
|
#define PIXAR_FOVCOT_VAL 5.123456789123456789
|
|
auxFloat = (float)PIXAR_FOVCOT_VAL;
|
|
auxDouble = (double)PIXAR_FOVCOT_VAL;
|
|
if (!TIFFSetField(tif, TIFFTAG_PIXAR_FOVCOT, auxDouble)) {
|
|
fprintf(stderr, "Can't set TIFFTAG_PIXAR_FOVCOT tag.\n");
|
|
goto failure;
|
|
}
|
|
/*- TIFFTAG_STONITS is a DOUBLE parameter (TIFF_DOUBLE, TIFF_SETGET_DOUBLE) with field_bit=FIELD_CUSTOM!
|
|
* Only TIFFTAG_STONITS is a TIFF_DOUBLE, which has to be read as DOUBLE!!
|
|
*/
|
|
#define STONITS_VAL 6.123456789123456789
|
|
auxDouble = STONITS_VAL;
|
|
auxFloat = (float)auxDouble;
|
|
if (!TIFFSetField(tif, TIFFTAG_STONITS, auxDouble)) {
|
|
fprintf(stderr, "Can't set TIFFTAG_STONITS tag.\n");
|
|
goto failure;
|
|
}
|
|
|
|
/*- TIFFTAG_YCBCRPOSITIONING is a SHORT parameter */
|
|
auxLong = auxShort = 5;
|
|
if (!TIFFSetField(tif, TIFFTAG_YCBCRPOSITIONING, auxLong )) {
|
|
fprintf (stderr, "Can't set TIFFTAG_YCBCRPOSITIONING tag.\n");
|
|
goto failure;
|
|
}
|
|
|
|
/* - TIFFTAG_BESTQUALITYSCALE is a Rational parameter, FIELD_CUSTOM and TIFF_SETGET_DOUBLE */
|
|
/* With Rational2Double upgrade tag is redefined to TIFF_SETGET_FLOAT, but can be still written with double. */
|
|
#define BESTQUALITYSCALE_VAL 15.3
|
|
auxDouble = BESTQUALITYSCALE_VAL;
|
|
if (!TIFFSetField(tif, TIFFTAG_BESTQUALITYSCALE, auxDouble )) {
|
|
fprintf (stderr, "Can't set TIFFTAG_BESTQUALITYSCALE tag.\n");
|
|
goto failure;
|
|
}
|
|
|
|
/* - TIFFTAG_BASELINENOISE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT */
|
|
if (!TIFFSetField(tif, TIFFTAG_BASELINENOISE, auxDouble)) {
|
|
fprintf(stderr, "Can't set TIFFTAG_BASELINENOISE tag.\n");
|
|
goto failure;
|
|
}
|
|
|
|
|
|
/*--- For static or variable ARRAYs the case is different ---*/
|
|
/*- Variable Array: TIFFTAG_DECODE is a SRATIONAL parameter TIFF_SETGET_C16_FLOAT type FIELD_CUSTOM with passcount=1 and variable length of array. */
|
|
if (!TIFFSetField(tif, TIFFTAG_DECODE, 3, auxFloatArrayN2)) {
|
|
fprintf(stderr, "Can't set TIFFTAG_DECODE tag.\n");
|
|
goto failure;
|
|
}
|
|
|
|
/*- Varable Array: TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT */
|
|
if (!TIFFSetField(tif, TIFFTAG_BLACKLEVEL, 3, auxFloatArrayN1)) {
|
|
fprintf(stderr, "Can't set TIFFTAG_BLACKLEVEL tag.\n");
|
|
goto failure;
|
|
}
|
|
|
|
/*- Fixed Array: TIFFTAG_DEFAULTCROPSIZE, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT */
|
|
if (!TIFFSetField(tif, TIFFTAG_DEFAULTCROPSIZE, &auxFloatArrayW[0])) {
|
|
fprintf(stderr, "Can't set TIFFTAG_DEFAULTCROPSIZE tag.\n");
|
|
goto failure;
|
|
}
|
|
#endif /* -- ADDITIONAL_TAGS -- */
|
|
|
|
/*================== Rational2Double Interface Check =====================*/
|
|
/*-- Check, if the TiffLibrary is compiled with the new interface with Rational2Double or still uses the old definitions.
|
|
For that, TIFF_RATIONAL tags with FIELD_CUSTOM are changed from TIFF_SETGET_DOUBLE to TIFF_SETGET_FLOAT for the
|
|
new interface in order to prevent the old reading behaviour.
|
|
Tags to check: TIFFTAG_BESTQUALITYSCALE, TIFFTAG_BASELINENOISE, TIFFTAG_BASELINESHARPNESS
|
|
*/
|
|
fip = TIFFFindField(tif, TIFFTAG_BESTQUALITYSCALE, TIFF_ANY);
|
|
tSetFieldType = fip->set_field_type;
|
|
if (tSetFieldType == TIFF_SETGET_DOUBLE) {
|
|
blnIsRational2Double = FALSE;
|
|
} else {
|
|
blnIsRational2Double = TRUE;
|
|
fprintf(stderr, "-- Rational2Double from TIFF tag detected --\n");
|
|
}
|
|
|
|
/*================== Write GPS and EXIF tags =====================*/
|
|
|
|
/*-- Set dummy EXIF/GPS tag in original tiff-structure in order to reserve space for final dir_offset value, */
|
|
/* which is properly written at the end. */
|
|
dir_offset = 0; /* Zero, in case no Custom-IFD is written */
|
|
|
|
#define WRITE_GPS_TAGS
|
|
#ifdef WRITE_GPS_TAGS
|
|
if (!TIFFSetField(tif, TIFFTAG_GPSIFD, dir_offset )) {
|
|
fprintf (stderr, "Can't write TIFFTAG_GPSIFD\n" );
|
|
}
|
|
#endif
|
|
|
|
/*------- And also do the same for the EXIF IFD tag here, because we have to save the main directory next ------*/
|
|
/*-- Set dummy EXIF/GPS tag in original tiff-structure in order to reserve space for final dir_offset value,
|
|
* which is properly written at the end.
|
|
*/
|
|
#define WRITE_EXIF_TAGS
|
|
#ifdef WRITE_EXIF_TAGS
|
|
if (!TIFFSetField(tif, TIFFTAG_EXIFIFD, dir_offset )) {
|
|
fprintf (stderr, "Can't write TIFFTAG_EXIFIFD\n" );
|
|
}
|
|
#endif
|
|
|
|
#ifndef WRITEPIXELLAST
|
|
/*-- Write dummy pixel data. --*/
|
|
if (TIFFWriteScanline(tif, buf, 0, 0) < 0) {
|
|
fprintf (stderr, "Can't write image data.\n");
|
|
goto failure;
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef WRITE_GPS_TAGS
|
|
#define READ_GPS_TAGS
|
|
/*================== Write GPS tags =====================*/
|
|
|
|
/*-- Save current tiff-directory to file before directory is changed. Otherwise it will be lost! */
|
|
/* The tif-structure is overwritten/ freshly initialized by any "CreateDirectory" */
|
|
/*retCode = TIFFCheckpointDirectory(tif);*/ /* does not cleanup Tiff-Structure */
|
|
retCode = TIFFWriteDirectory(tif); /* cleanup Tiff-structure */
|
|
|
|
/*-- Now create a GPS directory. */
|
|
if (TIFFCreateGPSDirectory(tif) != 0) {
|
|
fprintf (stderr, "TIFFCreateGPSDirectory() failed.\n" );
|
|
goto failure;
|
|
}
|
|
|
|
if (!TIFFSetField( tif, GPSTAG_VERSIONID, gpsVersion)) {
|
|
fprintf (stderr, "Can't write GPSTAG_VERSIONID\n" );
|
|
goto failure;
|
|
}
|
|
|
|
if (blnFillGPSManually) {
|
|
/*================= Write manually valid data to the GPS fields ==============*/
|
|
if (!TIFFSetField( tif, GPSTAG_LATITUDEREF, "N\0")) {
|
|
fprintf (stderr, "Can't write GPSTAG_LATITUDEREF\n" );
|
|
goto failure;
|
|
}
|
|
/*-- Unfortunately, Rational values are defined as SETGET_DOUBLE but are internally always stored as float.
|
|
* Single Rational values do not matter for writing, because TIFFSetField() uses va_arg() which performs "variables promotion" from type float to type double!
|
|
* However, for reading of Rational values ONLY float-variables are allowed - in contrary to the SETGET_DOUBLE specification at tiffFields[] in tif_dirinfo.c.
|
|
*/
|
|
/*-- ATTENTION: After the upgrade with Rational2Double, the GPSTAG values are defined as double precision
|
|
* and need to be written and also read in double precision!
|
|
* In order to maintain this code for both cases, it is checked above if the TiffLibrary is
|
|
* compiled with the new interface with Rational2Double or still uses the old definitions,
|
|
* by setting blnIsRational2Double above.
|
|
*/
|
|
if (blnIsRational2Double) {
|
|
fprintf(stderr, "-- GPS tags are written using Rational2Double --\n");
|
|
} else {
|
|
fprintf(stderr, "-- GPS tags are written using standard --\n");
|
|
}
|
|
if (!blnIsRational2Double) {
|
|
for (j = 0; j < 3; j++) auxFloatArray[j] = (float)auxDoubleArrayGPS1[j];
|
|
if (!TIFFSetField(tif, GPSTAG_LATITUDE, auxFloatArray)) {
|
|
fprintf(stderr, "Can't write GPSTAG_LATITUDE\n");
|
|
goto failure;
|
|
}
|
|
} else {
|
|
/* Rational2Double interface for GPSTAG */
|
|
if (!TIFFSetField(tif, GPSTAG_LATITUDE, auxDoubleArrayGPS1)) {
|
|
fprintf(stderr, "Can't write GPSTAG_LATITUDE\n");
|
|
goto failure;
|
|
}
|
|
}
|
|
if (!TIFFSetField( tif, GPSTAG_LONGITUDEREF, "W\0")) {
|
|
fprintf (stderr, "Can't write GPSTAG_LONGITUDEREF\n" );
|
|
goto failure;
|
|
}
|
|
if (!blnIsRational2Double) {
|
|
for (j=0; j<3; j++) auxFloatArray[j] = (float)auxDoubleArrayGPS2[j];
|
|
if (!TIFFSetField( tif, GPSTAG_LONGITUDE, auxFloatArray)) {
|
|
fprintf (stderr, "Can't write GPSTAG_LONGITUDE\n" );
|
|
goto failure;
|
|
}
|
|
} else {
|
|
/* Rational2Double interface for GPSTAG */
|
|
if (!TIFFSetField(tif, GPSTAG_LONGITUDE, auxDoubleArrayGPS2)) {
|
|
fprintf(stderr, "Can't write GPSTAG_LATITUDE\n");
|
|
goto failure;
|
|
}
|
|
}
|
|
/*-- AltitudeRef: default is above sea level!! */
|
|
if (!TIFFSetField( tif, GPSTAG_ALTITUDEREF, 0)) {
|
|
fprintf (stderr, "Can't write GPSTAG_ALTITUDEREF\n" );
|
|
goto failure;
|
|
}
|
|
if (!TIFFSetField( tif, GPSTAG_ALTITUDE, auxDoubleGPSAltitude)) {
|
|
fprintf (stderr, "Can't write GPSTAG_ALTITUDE\n" );
|
|
goto failure;
|
|
}
|
|
/*-- TimeStamp is only hh:mm:ss. See also DateTime string */
|
|
if (!TIFFSetField( tif, GPSTAG_TIMESTAMP, auxDoubleArrayGPSTime)) {
|
|
fprintf (stderr, "Can't write GPSTAG_TIMESTAMP\n" );
|
|
goto failure;
|
|
}
|
|
if (!TIFFSetField( tif, GPSTAG_DATESTAMP, "2012:11:04")) {
|
|
fprintf (stderr, "Can't write GPSTAG_DATESTAMP\n" );
|
|
goto failure;
|
|
}
|
|
|
|
if (!TIFFSetField( tif, GPSTAG_IMGDIRECTIONREF, "T\0")) {
|
|
fprintf (stderr, "Can't write GPSTAG_IMGDIRECTIONREF\n" );
|
|
goto failure;
|
|
}
|
|
if (!TIFFSetField( tif, GPSTAG_IMGDIRECTION, auxDoubleGPSDirection)) {
|
|
fprintf (stderr, "Can't write GPSTAG_IMGDIRECTION\n" );
|
|
goto failure;
|
|
}
|
|
|
|
/*-- Type TIFF_UNDEFINED */
|
|
if (!TIFFSetField( tif, GPSTAG_PROCESSINGMETHOD, 3, &auxCharArrayW[10])) {
|
|
fprintf (stderr, "Can't write GPSTAG_PROCESSINGMETHOD\n" );
|
|
goto failure;
|
|
}
|
|
if (!TIFFSetField( tif, GPSTAG_AREAINFORMATION, 4, &auxCharArrayW[20])) {
|
|
fprintf (stderr, "Can't write GPSTAG_AREAINFORMATION\n" );
|
|
goto failure;
|
|
}
|
|
|
|
/*-- PSTAG_DIFFERENTIAL , 1, 1, TIFF_SHORT , 0, TIFF_SETGET_UINT16 */
|
|
if (!TIFFSetField( tif, GPSTAG_DIFFERENTIAL, auxShortArrayW[5])) {
|
|
fprintf (stderr, "Can't write GPSTAG_DIFFERENTIAL\n" );
|
|
goto failure;
|
|
}
|
|
|
|
/* GPSTAG_GPSHPOSITIONINGERROR , 1, 1, TIFF_RATIONAL , 0, TIFF_SETGET_DOUBLE but here written in float-precision */
|
|
#define GPSHPOSITIONINGERROR_VAL 0.369
|
|
auxFloat = (float)GPSHPOSITIONINGERROR_VAL;
|
|
if (!TIFFSetField( tif, GPSTAG_GPSHPOSITIONINGERROR, auxFloat)) {
|
|
fprintf (stderr, "Can't write GPSTAG_GPSHPOSITIONINGERROR\n" );
|
|
goto failure;
|
|
}
|
|
|
|
} else {
|
|
/*================= Write arbitrary data to the GPS fields ==============*/
|
|
|
|
/*-- Get array, where GPS tag fields are defined --*/
|
|
tFieldArray = _TIFFGetGpsFields();
|
|
nTags = tFieldArray->count;
|
|
|
|
/*-- TODO: fill in the for / switch part of EXIF writing, when finished and tested!! */
|
|
|
|
} /*-- if (blnFillGPSManually) --*/
|
|
|
|
|
|
|
|
|
|
/*-- GPS - write custom directory GPS into file...---*/
|
|
/* (Get back the offset of GPS directory) */
|
|
if (!TIFFWriteCustomDirectory( tif, &dir_offset_GPS )) {
|
|
fprintf (stderr, "TIFFWriteCustomDirectory() with GPS failed.\n");
|
|
goto failure;
|
|
}
|
|
|
|
/*--- CheckpointDirectory at this place generates a second Main-IFD!!! */
|
|
/* retCode = TIFFCheckpointDirectory(tif); */
|
|
|
|
/*-- Set / reload previously saved main directory from file ---*/
|
|
if (!TIFFSetDirectory(tif, 0)) {
|
|
fprintf (stderr, "TIFFSetDirectory() within GPS failed.\n");
|
|
goto failure;
|
|
}
|
|
|
|
/*-- Write GPS tag reference / offset into GPSIFD tag in main directory --*/
|
|
if (!TIFFSetField(tif, TIFFTAG_GPSIFD, dir_offset_GPS )) {
|
|
fprintf (stderr, "Can't write TIFFTAG_GPSIFD\n");
|
|
goto failure;
|
|
}
|
|
|
|
/*=============== END writing GPS tags ==========================*/
|
|
#endif /*-- WRITE_GPS_TAGS --*/
|
|
|
|
|
|
/*================== Write EXIF 2.31 tags =====================*/
|
|
|
|
/*-- Set dummy EXIF/GPS tag in original tiff-structure in order to reserve space for final dir_offset value, */
|
|
/* which is properly written at the end.*/
|
|
/*- We did this already above together with the GPS IFD-tag. Otherwise we would do this here !! --------*/
|
|
/* if (!TIFFSetField(tif, TIFFTAG_EXIFIFD, dir_offset )) {
|
|
fprintf (stderr, "Can't write TIFFTAG_EXIFIFD\n" );
|
|
}
|
|
*/
|
|
|
|
#ifdef WRITE_EXIF_TAGS
|
|
#define READ_EXIF_TAGS
|
|
/*-- Save current tiff-directory to file before directory is changed. Otherwise it will be lost!
|
|
* The tif-structure is overwritten/ freshly initialized by any "CreateDirectory"
|
|
*/
|
|
|
|
/*----- What is needed here ??? ----
|
|
* In custom_dir.c only TIFFFreeDirectory( tif ); is used to set fields of another Sub-Directory
|
|
* TIFFFreeDirectory(tif); *-- Release storage associated with a directory, especially custom-fields.
|
|
*-- Using only TIFFFreeDirectory() here leads to an error!!
|
|
*-- Using here TIFFCheckpointDirectory() leads to an additional Main-IFD ??
|
|
*/
|
|
/*retCode = TIFFCheckpointDirectory(tif);*/ /* does not cleanup Tiff-Structure */
|
|
retCode = TIFFWriteDirectory(tif); /* cleanup Tiff-structure */
|
|
|
|
/*-- Now create an EXIF directory. */
|
|
if (TIFFCreateEXIFDirectory(tif) != 0) {
|
|
fprintf (stderr, "TIFFCreateEXIFDirectory() failed.\n" );
|
|
goto failure;
|
|
}
|
|
|
|
#define WRITE_ALL_EXIF_TAGS
|
|
#ifdef WRITE_ALL_EXIF_TAGS
|
|
#define READ_ALL_EXIF_TAGS
|
|
/*================= EXIF: Write arbitrary data to the EXIF fields ==============*/
|
|
/*-- Get array, where EXIF tag fields are defined
|
|
* EXIF tags are written automatically with the defined precision according to its tSetFieldType using the code below --*/
|
|
tFieldArray = _TIFFGetExifFields();
|
|
nTags = tFieldArray->count;
|
|
|
|
for (i=0; i<nTags; i++) {
|
|
tTag = tFieldArray->fields[i].field_tag;
|
|
tType = tFieldArray->fields[i].field_type; /* e.g. TIFF_RATIONAL */
|
|
tWriteCount = tFieldArray->fields[i].field_writecount;
|
|
tSetFieldType = tFieldArray->fields[i].set_field_type; /* e.g. TIFF_SETGET_C0_FLOAT */
|
|
tFieldName = tFieldArray->fields[i].field_name;
|
|
pVoid = NULL;
|
|
|
|
/*-- dependent on set_field_type write value --*/
|
|
switch (tSetFieldType)
|
|
{
|
|
case TIFF_SETGET_ASCII:
|
|
/* Either the stringlength is defined as a fixed length in .field_writecount or a NULL-terminated string is used. */
|
|
/* Shorter strings than in auxTextArraxW need a NULL-termination. Therefore copy the string. */
|
|
if (tWriteCount > 0) auxLong = tWriteCount-1; else auxLong = (long)strlen(auxTextArrayW[i])-1;
|
|
strncpy(auxCharArray, auxTextArrayW[i], auxLong);
|
|
auxCharArray[auxLong] = 0;
|
|
if (!TIFFSetField( tif, tTag, auxCharArray)) {
|
|
fprintf (stderr, "Can't write %s\n", tFieldArray->fields[i].field_name);
|
|
goto failure;
|
|
}
|
|
break;
|
|
case TIFF_SETGET_UINT8:
|
|
case TIFF_SETGET_UINT16:
|
|
case TIFF_SETGET_UINT32:
|
|
case TIFF_SETGET_IFD8:
|
|
case TIFF_SETGET_INT:
|
|
/*-- All those can be written with char, short or long parameter. Only value range should be in line. */
|
|
if (!TIFFSetField( tif, tTag, auxLongArrayW[i])) {
|
|
fprintf (stderr, "Can't write %s\n", tFieldArray->fields[i].field_name);
|
|
goto failure;
|
|
}
|
|
break;
|
|
case TIFF_SETGET_SINT8:
|
|
case TIFF_SETGET_SINT16:
|
|
case TIFF_SETGET_SINT32:
|
|
/*-- All those can be written with char, short or long parameter. Only value range should be in line. */
|
|
if (!TIFFSetField( tif, tTag, -1.0*auxLongArrayW[i])) {
|
|
fprintf (stderr, "Can't write %s\n", tFieldArray->fields[i].field_name);
|
|
goto failure;
|
|
}
|
|
break;
|
|
case TIFF_SETGET_FLOAT:
|
|
case TIFF_SETGET_DOUBLE:
|
|
if (tWriteCount == 1) {
|
|
/*-- All single values can be written with float or double parameter. Only value range should be in line. */
|
|
if (!TIFFSetField( tif, tTag, auxDoubleArrayW[i])) {
|
|
fprintf (stderr, "Can't write %s\n", tFieldArray->fields[i].field_name);
|
|
goto failure;
|
|
}
|
|
} else {
|
|
fprintf (stderr, "WriteCount for .set_field_type %d should be 1! %s\n", tSetFieldType, tFieldArray->fields[i].field_name);
|
|
}
|
|
break;
|
|
case TIFF_SETGET_C0_FLOAT:
|
|
case TIFF_SETGET_C0_DOUBLE:
|
|
case TIFF_SETGET_C16_FLOAT:
|
|
case TIFF_SETGET_C16_DOUBLE:
|
|
case TIFF_SETGET_C32_FLOAT:
|
|
case TIFF_SETGET_C32_DOUBLE:
|
|
/* _Cxx_ just defines the size of the count parameter for the array as C0=char, C16=short or C32=long */
|
|
/*-- Check, if it is a single parameter, a fixed array or a variable array */
|
|
if (tWriteCount == 1) {
|
|
fprintf (stderr, "WriteCount for .set_field_type %d should be -1 or greather than 1! %s\n", tSetFieldType, tFieldArray->fields[i].field_name);
|
|
} else {
|
|
/*-- Either fix or variable array --*/
|
|
/* For arrays, distinguishing between float or double is essential, even for writing */
|
|
if (tSetFieldType == TIFF_SETGET_C0_FLOAT || tSetFieldType == TIFF_SETGET_C16_FLOAT || tSetFieldType == TIFF_SETGET_C32_FLOAT)
|
|
pVoid = &auxFloatArrayW[i]; else pVoid = &auxDoubleArrayW[i];
|
|
/* Now decide between fixed or variable array */
|
|
if (tWriteCount > 1) {
|
|
/* fixed array with needed arraysize defined in .field_writecount */
|
|
if (!TIFFSetField( tif, tTag, pVoid)) {
|
|
fprintf (stderr, "Can't write %s\n", tFieldArray->fields[i].field_name);
|
|
goto failure;
|
|
}
|
|
} else {
|
|
/* special treatment of variable array */
|
|
/* for test, use always arraysize of VARIABLE_ARRAY_SIZE */
|
|
if (!TIFFSetField( tif, tTag, VARIABLE_ARRAY_SIZE, pVoid)) {
|
|
fprintf (stderr, "Can't write %s\n", tFieldArray->fields[i].field_name);
|
|
goto failure;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case TIFF_SETGET_C0_UINT8:
|
|
case TIFF_SETGET_C0_SINT8:
|
|
case TIFF_SETGET_C16_UINT8:
|
|
case TIFF_SETGET_C16_SINT8:
|
|
case TIFF_SETGET_C32_UINT8:
|
|
case TIFF_SETGET_C32_SINT8:
|
|
/* For arrays, distinguishing between float or double is essential, even for writing */
|
|
pVoid = &auxCharArrayW[i];
|
|
case TIFF_SETGET_C0_UINT16:
|
|
case TIFF_SETGET_C0_SINT16:
|
|
case TIFF_SETGET_C16_UINT16:
|
|
case TIFF_SETGET_C16_SINT16:
|
|
case TIFF_SETGET_C32_UINT16:
|
|
case TIFF_SETGET_C32_SINT16:
|
|
if (pVoid == NULL) pVoid = &auxShortArrayW[i];
|
|
case TIFF_SETGET_C0_UINT32:
|
|
case TIFF_SETGET_C0_SINT32:
|
|
case TIFF_SETGET_C16_UINT32:
|
|
case TIFF_SETGET_C16_SINT32:
|
|
case TIFF_SETGET_C32_UINT32:
|
|
case TIFF_SETGET_C32_SINT32:
|
|
if (pVoid == NULL) pVoid = &auxLongArrayW[i];
|
|
/* _Cxx_ just defines the size of the count parameter for the array as C0=char, C16=short or C32=long */
|
|
/*-- Check, if it is a single parameter, a fixed array or a variable array */
|
|
if (tWriteCount == 1) {
|
|
fprintf (stderr, "WriteCount for .set_field_type %d should be -1 or greather than 1! %s\n", tSetFieldType, tFieldArray->fields[i].field_name);
|
|
} else {
|
|
/*-- Either fix or variable array --*/
|
|
/* Now decide between fixed or variable array */
|
|
if (tWriteCount > 1) {
|
|
/* fixed array with needed arraysize defined in .field_writecount */
|
|
if (!TIFFSetField( tif, tTag, pVoid)) {
|
|
fprintf (stderr, "Can't write %s\n", tFieldArray->fields[i].field_name);
|
|
goto failure;
|
|
}
|
|
} else {
|
|
/* special treatment of variable array */
|
|
/* for test, use always arraysize of VARIABLE_ARRAY_SIZE */
|
|
if (!TIFFSetField( tif, tTag, VARIABLE_ARRAY_SIZE, pVoid)) {
|
|
fprintf (stderr, "Can't write %s\n", tFieldArray->fields[i].field_name);
|
|
goto failure;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
fprintf (stderr, "SetFieldType %d not defined within writing switch for %s.\n", tSetFieldType, tFieldName);
|
|
}; /*-- switch() --*/
|
|
} /*-- for() --*/
|
|
/*================= EXIF: END Writing arbitrary data to the EXIF fields END END END ==============*/
|
|
#endif /*-- WRITE_ALL_EXIF_TAGS --*/
|
|
|
|
/*--- Set valid EXIF version, which is a 4 byte string --*/
|
|
if (!TIFFSetField( tif, EXIFTAG_EXIFVERSION, exifVersion)) {
|
|
fprintf (stderr, "Can't write EXIFTAG_EXIFVERSION\n" );
|
|
goto failure;
|
|
}
|
|
|
|
|
|
/*-- EXIF - write custom directory EXIF into file...---*/
|
|
/* (Get back the offset of EXIF directory) */
|
|
if (!TIFFWriteCustomDirectory( tif, &dir_offset_EXIF )) {
|
|
fprintf (stderr, "TIFFWriteCustomDirectory() with EXIF failed.\n");
|
|
goto failure;
|
|
}
|
|
|
|
/*-- Go back to the first (main) directory, and set correct value of the EXIFIFD pointer. */
|
|
/* (directory is reloaded from file!) */
|
|
TIFFSetDirectory(tif, 0);
|
|
TIFFSetField(tif, TIFFTAG_EXIFIFD, dir_offset_EXIF );
|
|
#endif /*-- WRITE_EXIF_TAGS --*/
|
|
|
|
#ifdef WRITEPIXELLAST
|
|
/*-- Write dummy pixel data. --*/
|
|
if (TIFFWriteScanline(tif, buf, 0, 0) < 0) {
|
|
fprintf (stderr, "Can't write image data.\n");
|
|
goto failure;
|
|
}
|
|
#endif
|
|
/*-- Write directory to file --*/
|
|
/* Always WriteDirectory before using/creating another directory. */
|
|
/* Not necessary before TIFFClose(), however, TIFFClose() uses TIFFReWriteDirectory(), which forces directory to be written at another location. */
|
|
retCode = TIFFWriteDirectory(tif);
|
|
|
|
/*-- Write File to disk and close file --*/
|
|
/* TIFFClose() uses TIFFReWriteDirectory(), which forces directory to be written at another location. */
|
|
/* Therefore, better use TIFFWriteDirectory() before. */
|
|
TIFFClose(tif);
|
|
|
|
fprintf (stderr, "-------- Continue Test ---------- reading ...\n");
|
|
|
|
/*========================= READING ============= READING ========================================*/
|
|
/* Ok, now test whether we can read written values correctly. */
|
|
tif = TIFFOpen(filenameRead, "r");
|
|
|
|
|
|
/*-- Read some parameters out of the main directory --*/
|
|
|
|
/*-- IMAGEWIDTH and -LENGTH are defined as TIFF_SETGET_UINT32 */
|
|
retCode = TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &auxUint32 );
|
|
if (!retCode) { fprintf(stderr, "Can't read %s\n", "TIFFTAG_IMAGEWIDTH"); }
|
|
if (auxUint32 != width) {
|
|
fprintf (stderr, "Read value of IMAGEWIDTH %d differs from set value %d\n", auxUint32, width);
|
|
}
|
|
retCode = TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &auxUint32 );
|
|
if (!retCode) { fprintf(stderr, "Can't read %s\n", "TIFFTAG_IMAGELENGTH"); }
|
|
if (auxUint32 != width) {
|
|
fprintf (stderr, "Read value of TIFFTAG_IMAGELENGTH %d differs from set value %d\n", auxUint32, length);
|
|
}
|
|
|
|
#ifdef ADDITIONAL_TAGS
|
|
/*- TIFFTAG_PIXAR_FOVCOT is a FLOAT parameter of type FIELD_CUSTOM !! */
|
|
retCode = TIFFGetField(tif, TIFFTAG_PIXAR_FOVCOT, &auxFloat );
|
|
if (!retCode) { fprintf(stderr, "Can't read %s\n", "TIFFTAG_PIXAR_FOVCOT"); }
|
|
if (auxFloat != (float)PIXAR_FOVCOT_VAL) {
|
|
fprintf (stderr, "Read value of TIFFTAG_PIXAR_FOVCOT %f differs from set value %f\n", auxFloat, PIXAR_FOVCOT_VAL);
|
|
}
|
|
|
|
/* - TIFFTAG_BESTQUALITYSCALE is a Rational parameter, FIELD_CUSTOM and TIFF_SETGET_FLOAT */
|
|
retCode = TIFFGetField(tif, TIFFTAG_BESTQUALITYSCALE, &auxFloat );
|
|
if (!retCode) { fprintf(stderr, "Can't read %s\n", "TIFFTAG_BESTQUALITYSCALE"); }
|
|
if (auxFloat != (float)BESTQUALITYSCALE_VAL) {
|
|
fprintf (stderr, "Read value of TIFFTAG_BESTQUALITYSCALE %f differs from set value %f\n", auxFloat, BESTQUALITYSCALE_VAL);
|
|
}
|
|
|
|
/* - TIFFTAG_BASELINENOISE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT */
|
|
retCode = TIFFGetField(tif, TIFFTAG_BASELINENOISE, &auxDblUnion.dbl);
|
|
if (!retCode) { fprintf(stderr, "Can't read %s\n", "TIFFTAG_BASELINENOISE"); }
|
|
if (auxDblUnion.flt1 != (float)BESTQUALITYSCALE_VAL) {
|
|
fprintf(stderr, "Read float value of TIFFTAG_BASELINENOISE %f differs from set value %f\n", auxDblUnion.flt1, BESTQUALITYSCALE_VAL);
|
|
}
|
|
|
|
|
|
/*- Variable Array: TIFFTAG_DECODE is a SRATIONAL parameter TIFF_SETGET_C16_FLOAT type FIELD_CUSTOM with passcount=1 and variable length of array. */
|
|
retCode = TIFFGetField(tif, TIFFTAG_DECODE, &count16, &pVoidArray );
|
|
if (!retCode) { fprintf(stderr, "Can't read %s\n", "TIFFTAG_DECODE"); }
|
|
/*- pVoidArray points to a Tiff-internal temporary memorypart. Thus, contents needs to be saved. */
|
|
memcpy(&auxFloatArray, pVoidArray,(count16 * sizeof(auxFloatArray[0])));
|
|
for (i=0; i<count16; i++) {
|
|
dblDiffLimit = RATIONAL_EPS*auxFloatArrayN2[i];
|
|
dblDiff = auxFloatArray[i] - auxFloatArrayN2[i];
|
|
if (fabs(dblDiff) > fabs(dblDiffLimit)) {
|
|
fprintf (stderr, "Read value %d of TIFFTAG_DECODE Array %f differs from set value %f\n", i, auxFloatArray[i], auxFloatArrayN2[i]);
|
|
}
|
|
}
|
|
|
|
retCode = TIFFGetField(tif, TIFFTAG_BLACKLEVEL, &count16, &pVoidArray);
|
|
if (!retCode) { fprintf(stderr, "Can't read %s\n", "TIFFTAG_BLACKLEVEL"); }
|
|
/*- pVoidArray points to a Tiff-internal temporary memorypart. Thus, contents needs to be saved. */
|
|
memcpy(&auxFloatArray, pVoidArray, (count16 * sizeof(auxFloatArray[0])));
|
|
for (i = 0; i<count16; i++) {
|
|
dblDiffLimit = RATIONAL_EPS*auxFloatArrayN1[i];
|
|
dblDiff = auxFloatArray[i] - auxFloatArrayN1[i];
|
|
if (fabs(dblDiff) > fabs(dblDiffLimit)) {
|
|
fprintf(stderr, "Read value %d of TIFFTAG_BLACKLEVEL Array %f differs from set value %f\n", i, auxFloatArray[i], auxFloatArrayN1[i]);
|
|
}
|
|
}
|
|
|
|
/*- Fixed Array: TIFFTAG_DEFAULTCROPSIZE, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT */
|
|
retCode = TIFFGetField(tif, TIFFTAG_DEFAULTCROPSIZE, &pVoidArray);
|
|
if (!retCode) { fprintf(stderr, "Can't read %s\n", "TIFFTAG_DEFAULTCROPSIZE"); }
|
|
/*- pVoidArray points to a Tiff-internal temporary memorypart. Thus, contents needs to be saved. */
|
|
memcpy(&auxFloatArray, pVoidArray, (2 * sizeof(auxFloatArray[0])));
|
|
for (i = 0; i < 2; i++) {
|
|
dblDiffLimit = RATIONAL_EPS * auxFloatArrayW[i];
|
|
dblDiff = auxFloatArray[i] - auxFloatArrayW[i];
|
|
if (fabs(dblDiff) > fabs(dblDiffLimit)) {
|
|
fprintf(stderr, "Read value %d of TIFFTAG_DEFAULTCROPSIZE Array %f differs from set value %f\n", i, auxFloatArray[i], auxFloatArrayW[i]);
|
|
}
|
|
}
|
|
|
|
#endif /*-- ADDITIONAL_TAGS --*/
|
|
|
|
|
|
#ifdef READ_GPS_TAGS
|
|
/*================== Reading GPS tags =====================*/
|
|
/*-- First get offset to GPS-directory and set it active (this will destroy previously main directory fields in memory!) */
|
|
retCode = TIFFGetField(tif, TIFFTAG_GPSIFD, &read_dir_offset );
|
|
if (!retCode) {fprintf(stderr, "Can't read %s\n", "TIFFTAG_GPSIFD"); }
|
|
retCode = TIFFReadGPSDirectory(tif, read_dir_offset);
|
|
if (!retCode) { fprintf(stderr, "Can't read %s\n", "TIFFReadGPSDirectory()"); }
|
|
|
|
/*-- Now read some parameters from GPS-directory --*/
|
|
|
|
/*-- Fixed Array: GPS-Version is a fixed array (of 4 characters) */
|
|
retCode = TIFFGetField(tif, GPSTAG_VERSIONID, &pGpsVersion);
|
|
if (!retCode) { fprintf(stderr, "Can't read %s\n", "GPSTAG_VERSIONID"); }
|
|
else {
|
|
memcpy(auxCharArray, pGpsVersion, sizeof(gpsVersion));
|
|
for (i = 0; i < 4; i++) {
|
|
if (auxCharArray[i] != pGpsVersion[i]) {
|
|
fprintf(stderr, "Read value %d of GPSTAG_VERSIONID %d differs from set value %d\n", i, auxCharArray[i], pGpsVersion[i]);
|
|
}
|
|
}
|
|
}
|
|
/*-- LATITUDEREF is a fixed String of one character plus ending zero. */
|
|
retCode = TIFFGetField(tif, GPSTAG_LATITUDEREF, &pAscii);
|
|
if (!retCode) { fprintf(stderr, "Can't read %s\n", "GPSTAG_LATITUDEREF"); }
|
|
retCode2 = strncmp("N", pAscii, 1);
|
|
if (retCode2 != 0) {
|
|
fprintf (stderr, "Read value %d of GPSTAG_LATITUDEREF %s differs from set value %s\n", i, "N", pAscii);
|
|
}
|
|
|
|
/*-- Fixed Array: Latitude is an array of 3 Rational-values. TIFFGetField() returns a pointer to a temporary float-/double-array. */
|
|
/*-- ATTENTION: After the upgrade with Rational2Double, the GPSTAG values are defined as double precision
|
|
* and need to be written and also read in double precision!
|
|
* In order to maintain this code for both cases, it is checked above if the TiffLibrary is
|
|
* compiled with the new interface with Rational2Double or still uses the old definitions,
|
|
* by setting blnIsRational2Double above.
|
|
*/
|
|
if (blnIsRational2Double) {
|
|
fprintf(stderr, "-- GPS tags are read using Rational2Double --\n");
|
|
} else {
|
|
fprintf(stderr, "-- GPS tags are read using standard --\n");
|
|
}
|
|
retCode = TIFFGetField(tif, GPSTAG_LATITUDE, &pVoidArray);
|
|
if (!retCode) { fprintf(stderr, "Can't read %s\n", "GPSTAG_LATITUDE"); }
|
|
if (!blnIsRational2Double) {
|
|
/* Reset arrays for debugging purpose first */
|
|
memset(auxFloatArray, 0, sizeof(auxFloatArray));
|
|
memcpy(auxFloatArray, pVoidArray, 3*sizeof(float));
|
|
/* for comparison copy to doubleArray */
|
|
for (i=0; i<3; i++) auxDoubleArray[i] = (double)auxFloatArray[i];
|
|
} else {
|
|
/* Rational2Double interface for GPSTAG reads double array */
|
|
memset(auxDoubleArray, 0, sizeof(auxDoubleArray));
|
|
memcpy(auxDoubleArray, pVoidArray, 3 * sizeof(double));
|
|
}
|
|
for (i=0; i<3; i++) {
|
|
dblDiffLimit = RATIONAL_EPS*auxDoubleArrayGPS1[i];
|
|
dblDiff = auxDoubleArray[i] - auxDoubleArrayGPS1[i];
|
|
if (fabs(dblDiff) > fabs(dblDiffLimit)) {
|
|
fprintf (stderr, "Read value %d of GPSTAG_LATITUDE %f differs from set value %f\n", i, auxDoubleArray[i], auxDoubleArrayGPS1[i]);
|
|
}
|
|
}
|
|
|
|
/*-- LONGITUDEREF is a fixed String of one character plus ending zero. */
|
|
retCode = TIFFGetField(tif, GPSTAG_LONGITUDEREF, &pAscii);
|
|
if (!retCode) { fprintf(stderr, "Can't read %s\n", "GPSTAG_LONGITUDEREF"); }
|
|
retCode2 = strncmp("W", pAscii, 1);
|
|
if (retCode2 != 0) {
|
|
fprintf(stderr, "Read value %d of GPSTAG_LONGITUDEREF %s differs from set value %s\n", i, "W", pAscii);
|
|
}
|
|
|
|
retCode = TIFFGetField(tif, GPSTAG_LONGITUDE, &pVoidArray);
|
|
if (!retCode) { fprintf(stderr, "Can't read %s\n", "GPSTAG_LONGITUDE"); }
|
|
if (!blnIsRational2Double) {
|
|
/* Reset arrays for debugging purpose first */
|
|
memset(auxFloatArray, 0, sizeof(auxFloatArray));
|
|
memcpy(auxFloatArray, pVoidArray, 3 * sizeof(float));
|
|
/* for comparison copy to doubleArray */
|
|
for (i = 0; i < 3; i++) auxDoubleArray[i] = (double)auxFloatArray[i];
|
|
} else {
|
|
/* Rational2Double interface for GPSTAG reads double array */
|
|
memset(auxDoubleArray, 0, sizeof(auxDoubleArray));
|
|
memcpy(auxDoubleArray, pVoidArray, 3 * sizeof(double));
|
|
}
|
|
for (i = 0; i < 3; i++) {
|
|
dblDiffLimit = RATIONAL_EPS * auxDoubleArrayGPS2[i];
|
|
dblDiff = auxDoubleArray[i] - auxDoubleArrayGPS2[i];
|
|
if (fabs(dblDiff) > fabs(dblDiffLimit)) {
|
|
fprintf(stderr, "Read value %d of GPSTAG_LONGITUDE %f differs from set value %f\n", i, auxDoubleArray[i], auxDoubleArrayGPS2[i]);
|
|
}
|
|
}
|
|
|
|
/* TIFF_RATIONAL, TIFF_SETGET_DOUBLE */
|
|
if (!TIFFGetField(tif, GPSTAG_ALTITUDE, &auxDblUnion.dbl)) {
|
|
fprintf(stderr, "Can't read GPSTAG_ALTITUDE\n");
|
|
GOTOFAILURE_GPS
|
|
}
|
|
if (blnIsRational2Double) {
|
|
/* New interface allows also double precision for TIFF_RATIONAL */
|
|
auxDouble = auxDblUnion.dbl;
|
|
} else {
|
|
/* Old interface reads TIFF_RATIONAL defined as TIFF_SETGET_DOUBLE alwasy as FLOAT */
|
|
auxDouble = (double)auxDblUnion.flt1;
|
|
}
|
|
/* compare read values with written ones */
|
|
dblDiffLimit = RATIONAL_EPS * auxDoubleGPSAltitude;
|
|
dblDiff = auxDouble - auxDoubleGPSAltitude;
|
|
if (fabs(dblDiff) > fabs(dblDiffLimit)) {
|
|
fprintf(stderr, "Read value of GPSTAG_ALTITUDE %f differs from set value %f\n", auxDouble, auxDoubleGPSAltitude);
|
|
GOTOFAILURE_GPS
|
|
}
|
|
|
|
/*-- TimeStamp is only hh:mm:ss. See also DateTime string 3, TIFF_RATIONAL, TIFF_SETGET_C0_DOUBLE */
|
|
retCode = TIFFGetField(tif, GPSTAG_TIMESTAMP, &pVoidArray);
|
|
if (!retCode) { fprintf(stderr, "Can't read %s\n", "GPSTAG_TIMESTAMP"); }
|
|
if (!blnIsRational2Double) {
|
|
/* Reset arrays for debugging purpose first */
|
|
memset(auxFloatArray, 0, sizeof(auxFloatArray));
|
|
memcpy(auxFloatArray, pVoidArray, 3 * sizeof(float));
|
|
/* for comparison copy to doubleArray */
|
|
for (i = 0; i < 3; i++) auxDoubleArray[i] = (double)auxFloatArray[i];
|
|
} else {
|
|
/* Rational2Double interface for GPSTAG reads double array */
|
|
memset(auxDoubleArray, 0, sizeof(auxDoubleArray));
|
|
memcpy(auxDoubleArray, pVoidArray, 3 * sizeof(double));
|
|
}
|
|
for (i = 0; i < 3; i++) {
|
|
dblDiffLimit = RATIONAL_EPS * auxDoubleArrayGPSTime[i];
|
|
dblDiff = auxDoubleArray[i] - auxDoubleArrayGPSTime[i];
|
|
if (fabs(dblDiff) > fabs(dblDiffLimit)) {
|
|
fprintf(stderr, "Read value %d of GPSTAG_TIMESTAMP %f differs from set value %f\n", i, auxDoubleArray[i], auxDoubleArrayGPS2[i]);
|
|
GOTOFAILURE_GPS
|
|
}
|
|
}
|
|
|
|
/* GPSTAG_IMGDIRECTION --- TIFF_RATIONAL, TIFF_SETGET_DOUBLE */
|
|
if (!TIFFGetField(tif, GPSTAG_IMGDIRECTION, &auxDblUnion.dbl)) {
|
|
fprintf(stderr, "Can't read GPSTAG_IMGDIRECTION\n");
|
|
GOTOFAILURE_GPS
|
|
}
|
|
if (blnIsRational2Double) {
|
|
/* New interface allows also double precision for TIFF_RATIONAL */
|
|
auxDouble = auxDblUnion.dbl;
|
|
} else {
|
|
/* Old interface reads TIFF_RATIONAL defined as TIFF_SETGET_DOUBLE alwasy as FLOAT */
|
|
auxDouble = (double)auxDblUnion.flt1;
|
|
}
|
|
/* compare read values with written ones */
|
|
dblDiffLimit = RATIONAL_EPS * auxDoubleGPSDirection;
|
|
dblDiff = auxDouble - auxDoubleGPSDirection;
|
|
if (fabs(dblDiff) > fabs(dblDiffLimit)) {
|
|
fprintf(stderr, "Read value of GPSTAG_IMGDIRECTION %f differs from set value %f\n", auxDouble, auxDoubleGPSDirection);
|
|
GOTOFAILURE_GPS
|
|
}
|
|
|
|
/*-- GPSTAG_DIFFERENTIAL , 1, 1, TIFF_SHORT , 0, TIFF_SETGET_UINT16 */
|
|
retCode = TIFFGetField(tif, GPSTAG_DIFFERENTIAL, &auxShort);
|
|
if (!retCode) { fprintf(stderr, "Can't read %s\n", "GPSTAG_DIFFERENTIAL"); }
|
|
if (auxShort != auxShortArrayW[5]) {
|
|
fprintf(stderr, "Read value of GPSTAG_DIFFERENTIAL %d differs from set value %d\n", auxShort, auxShortArrayW[5]);
|
|
GOTOFAILURE_GPS
|
|
}
|
|
|
|
/*-- GPSHPOSITIONINGERROR - new tag for EXIF 2.31 --*/
|
|
if (!TIFFGetField(tif, GPSTAG_GPSHPOSITIONINGERROR, &auxDblUnion.dbl)) {
|
|
fprintf(stderr, "Can't read GPSTAG_GPSHPOSITIONINGERROR\n");
|
|
GOTOFAILURE_GPS
|
|
}
|
|
if (blnIsRational2Double) {
|
|
/* New interface allows also double precision for TIFF_RATIONAL */
|
|
auxDouble = auxDblUnion.dbl;
|
|
} else {
|
|
/* Old interface reads TIFF_RATIONAL defined as TIFF_SETGET_DOUBLE alwasy as FLOAT */
|
|
auxDouble = (double)auxDblUnion.flt1;
|
|
}
|
|
/* compare read values with written ones */
|
|
auxFloat = (float)GPSHPOSITIONINGERROR_VAL;
|
|
dblDiffLimit = RATIONAL_EPS * auxFloat;
|
|
dblDiff = auxDouble - auxFloat;
|
|
if (fabs(dblDiff) > fabs(dblDiffLimit)) {
|
|
fprintf(stderr, "Read value of GPSTAG_GPSHPOSITIONINGERROR %f differs from set value %f\n", auxDouble, auxFloat);
|
|
GOTOFAILURE_GPS
|
|
}
|
|
|
|
/*=============== END reading GPS tags ==========================*/
|
|
#endif /*-- READ_GPS_TAGS --*/
|
|
|
|
|
|
|
|
/*================== Reading EXIF 2.31 tags =====================*/
|
|
|
|
/*--- Firstly, get EXIF directory offset from main directory. */
|
|
|
|
/*-- Go back to the first (main) directory, and get value of the EXIFIFD directory- offset. */
|
|
/* (directory is reloaded from file!) */
|
|
TIFFSetDirectory(tif, 0);
|
|
retCode = TIFFGetField(tif, TIFFTAG_EXIFIFD, &read_dir_offset );
|
|
|
|
#ifdef READ_EXIF_TAGS
|
|
/*-- Now read EXIF directory from file into memory --*/
|
|
retCode = TIFFReadEXIFDirectory(tif, read_dir_offset);
|
|
|
|
/*-- Now get some parameters from EXIF-directory (already read into memory) --*/
|
|
retCode = TIFFGetField(tif, EXIFTAG_EXIFVERSION, &pAscii);
|
|
|
|
|
|
#ifdef READ_ALL_EXIF_TAGS
|
|
/*-- Get array, where EXIF tag fields are defined --*/
|
|
tFieldArray = _TIFFGetExifFields();
|
|
nTags = tFieldArray->count;
|
|
/*-- Check, if the TiffLibrary is compiled with the new interface with Rational2Double or still uses the old definitions. */
|
|
/* tif points to EXIF tags, so TIFFFindField() can only access the EXIF tag fields */
|
|
fip = TIFFFindField(tif, EXIFTAG_EXPOSURETIME, TIFF_ANY);
|
|
tSetFieldType = fip->set_field_type;
|
|
if (tSetFieldType == TIFF_SETGET_DOUBLE) {
|
|
blnIsRational2Double = FALSE;
|
|
fprintf(stderr, "-- EXIF tags read with standard --\n");
|
|
} else {
|
|
blnIsRational2Double = TRUE;
|
|
fprintf(stderr, "-- Rational2Double for reading EXIF tags detected --\n");
|
|
}
|
|
|
|
for (i=0; i<nTags; i++) {
|
|
tTag = tFieldArray->fields[i].field_tag;
|
|
tType = tFieldArray->fields[i].field_type; /* e.g. TIFF_RATIONAL */
|
|
tWriteCount = tFieldArray->fields[i].field_writecount;
|
|
tSetFieldType = tFieldArray->fields[i].set_field_type; /* e.g. TIFF_SETGET_C0_FLOAT */
|
|
tFieldName = tFieldArray->fields[i].field_name;
|
|
pVoid = NULL;
|
|
|
|
/*-- dependent on set_field_type read value --*/
|
|
switch (tSetFieldType)
|
|
{
|
|
case TIFF_SETGET_ASCII:
|
|
/* Either the stringlength is defined as a fixed length in .field_writecount or a NULL-terminated string is used. */
|
|
if (!TIFFGetField( tif, tTag, &pAscii)) {
|
|
fprintf (stderr, "Can't read %s\n", tFieldArray->fields[i].field_name);
|
|
GOTOFAILURE_ALL_EXIF
|
|
break;
|
|
}
|
|
/* Save string from temporary buffer and compare with written string. */
|
|
strncpy(auxCharArray, pAscii, sizeof(auxCharArray));
|
|
if (tWriteCount > 0) auxLong = tWriteCount-1; else auxLong = (long)strlen(auxCharArray);
|
|
retCode2 = strncmp(auxCharArray, auxTextArrayW[i], auxLong);
|
|
if (retCode2 != 0) {
|
|
fprintf (stderr, "%d:Read value of %s %s differs from set value %s\n", i, tFieldName, auxCharArray, auxTextArrayW[i]);
|
|
GOTOFAILURE_ALL_EXIF
|
|
}
|
|
break;
|
|
/*-- For reading, the parameter size is to be observed !! */
|
|
case TIFF_SETGET_UINT8:
|
|
case TIFF_SETGET_SINT8:
|
|
if (!TIFFGetField( tif, tTag, &auxChar)) {
|
|
fprintf (stderr, "Can't read %s\n", tFieldArray->fields[i].field_name);
|
|
GOTOFAILURE_ALL_EXIF
|
|
break;
|
|
}
|
|
/* compare read values with written ones */
|
|
auxLong = auxChar;
|
|
if (auxLong != (char)auxLongArrayW[i]) {
|
|
fprintf (stderr, "%d:Read value of %s %ld differs from set value %ld\n", i, tFieldName, auxLong, auxLongArrayW[i]);
|
|
}
|
|
break;
|
|
case TIFF_SETGET_UINT16:
|
|
case TIFF_SETGET_SINT16:
|
|
if (!TIFFGetField( tif, tTag, &auxShort)) {
|
|
fprintf (stderr, "Can't read %s\n", tFieldArray->fields[i].field_name);
|
|
GOTOFAILURE_ALL_EXIF
|
|
break;
|
|
}
|
|
/* compare read values with written ones */
|
|
auxLong = auxShort;
|
|
if (auxLong != (short)auxLongArrayW[i]) {
|
|
fprintf (stderr, "%d:Read value of %s %ld differs from set value %ld\n", i, tFieldName, auxLong, auxLongArrayW[i]);
|
|
}
|
|
break;
|
|
case TIFF_SETGET_UINT32:
|
|
case TIFF_SETGET_SINT32:
|
|
case TIFF_SETGET_IFD8:
|
|
case TIFF_SETGET_INT:
|
|
if (!TIFFGetField( tif, tTag, &auxUint32)) {
|
|
fprintf (stderr, "Can't read %s\n", tFieldArray->fields[i].field_name);
|
|
GOTOFAILURE_ALL_EXIF
|
|
break;
|
|
}
|
|
/* compare read values with written ones */
|
|
auxLong = auxUint32;
|
|
if (auxLong != auxLongArrayW[i]) {
|
|
fprintf (stderr, "%d:Read value of %s %ld differs from set value %ld\n", i, tFieldName, auxLong, auxLongArrayW[i]);
|
|
}
|
|
break;
|
|
case TIFF_SETGET_FLOAT:
|
|
if (!TIFFGetField( tif, tTag, &auxFloat)) {
|
|
fprintf (stderr, "Can't read %s\n", tFieldArray->fields[i].field_name);
|
|
GOTOFAILURE_ALL_EXIF
|
|
break;
|
|
}
|
|
/* compare read values with written ones */
|
|
if (tType == TIFF_RATIONAL || tType == TIFF_SRATIONAL) dblDiffLimit = RATIONAL_EPS*auxDoubleArrayW[i]; else dblDiffLimit = 1e-6;
|
|
dblDiff = auxFloat - auxDoubleArrayW[i];
|
|
if (fabs(dblDiff) > fabs(dblDiffLimit)) {
|
|
/*--: EXIFTAG_SUBJECTDISTANCE: LibTiff returns value of "-1.0" if numerator equals 4294967295 (0xFFFFFFFF) to indicate infinite distance!
|
|
* However, there are two other EXIF tags where numerator indicates a special value and six other cases where the denominator indicates special values,
|
|
* which are not treated within LibTiff!!
|
|
*/
|
|
if (!(tTag == EXIFTAG_SUBJECTDISTANCE && auxFloat == -1.0)) {
|
|
fprintf (stderr, "%d:Read value of %s %f differs from set value %f\n", i, tFieldName, auxFloat, auxDoubleArrayW[i]);
|
|
GOTOFAILURE_ALL_EXIF
|
|
}
|
|
}
|
|
break;
|
|
case TIFF_SETGET_DOUBLE:
|
|
/*-- Unfortunately, TIFF_SETGET_DOUBLE is used for TIFF_RATIONAL but those have to be read with FLOAT !!! */
|
|
/* Only TIFFTAG_STONITS is a TIFF_DOUBLE, which has to be read as DOUBLE!! */
|
|
/*-- ATTENTION: ----
|
|
* Only after update with Rational2Double feature, also TIFF_RATIONAL can be read in double precision!!!
|
|
* Therefore, use a union to avoid overflow in TIFFGetField() return value
|
|
* and depending on version check for the right interface here:
|
|
* - old interface: correct value should be here a float
|
|
* - new interface: correct value should be here a double
|
|
* Interface version (old/new) is determined above.
|
|
-------------------*/
|
|
if (!TIFFGetField(tif, tTag, &auxDblUnion.dbl)) {
|
|
fprintf(stderr, "Can't read %s\n", tFieldArray->fields[i].field_name);
|
|
GOTOFAILURE_ALL_EXIF
|
|
break;
|
|
}
|
|
if (tType == TIFF_RATIONAL || tType == TIFF_SRATIONAL) {
|
|
if (blnIsRational2Double) {
|
|
/* New interface allows also double precision for TIFF_RATIONAL */
|
|
auxDouble = auxDblUnion.dbl;
|
|
}
|
|
else {
|
|
/* Old interface reads TIFF_RATIONAL defined as TIFF_SETGET_DOUBLE alwasy as FLOAT */
|
|
auxDouble = (double)auxDblUnion.flt1;
|
|
}
|
|
}
|
|
else {
|
|
auxDouble = auxDblUnion.dbl;
|
|
}
|
|
/* compare read values with written ones */
|
|
if (tType == TIFF_RATIONAL || tType == TIFF_SRATIONAL) dblDiffLimit = RATIONAL_EPS*auxDoubleArrayW[i]; else dblDiffLimit = 1e-6;
|
|
dblDiff = auxDouble - auxDoubleArrayW[i];
|
|
if (fabs(dblDiff) > fabs(dblDiffLimit)) {
|
|
/*--: EXIFTAG_SUBJECTDISTANCE: LibTiff returns value of "-1.0" if numerator equals 4294967295 (0xFFFFFFFF) to indicate infinite distance! */
|
|
if (!(tTag == EXIFTAG_SUBJECTDISTANCE && auxDouble == -1.0)) {
|
|
fprintf (stderr, "%d:Read value of %s %f differs from set value %f\n", i, tFieldName, auxDouble, auxDoubleArrayW[i]);
|
|
GOTOFAILURE_ALL_EXIF
|
|
}
|
|
}
|
|
break;
|
|
|
|
case TIFF_SETGET_C0_FLOAT:
|
|
case TIFF_SETGET_C0_DOUBLE:
|
|
case TIFF_SETGET_C16_FLOAT:
|
|
case TIFF_SETGET_C16_DOUBLE:
|
|
case TIFF_SETGET_C32_FLOAT:
|
|
case TIFF_SETGET_C32_DOUBLE:
|
|
/* _Cxx_ just defines the size of the count parameter for the array as C0=char, C16=short or C32=long */
|
|
/*-- Check, if it is a single parameter, a fixed array or a variable array */
|
|
if (tWriteCount == 1) {
|
|
fprintf (stderr, "Reading: WriteCount for .set_field_type %d should be -1 or greather than 1! %s\n", tSetFieldType, tFieldArray->fields[i].field_name);
|
|
} else {
|
|
/*-- Either fix or variable array --*/
|
|
/* For arrays, distinguishing between float or double is essential. */
|
|
/* Now decide between fixed or variable array */
|
|
if (tWriteCount > 1) {
|
|
/* fixed array with needed arraysize defined in .field_writecount */
|
|
if (!TIFFGetField( tif, tTag, &pVoidArray)) {
|
|
fprintf (stderr, "Can't read %s\n", tFieldArray->fields[i].field_name);
|
|
GOTOFAILURE_ALL_EXIF
|
|
break;
|
|
}
|
|
/* set tWriteCount to number of read samples for next steps */
|
|
auxLong = tWriteCount;
|
|
} else {
|
|
/* Special treatment of variable array. */
|
|
/* Dependent on Cxx, the count parameter is char, short or long. Therefore use unionLong! */
|
|
if (!TIFFGetField( tif, tTag, &unionLong, &pVoidArray)) {
|
|
fprintf (stderr, "Can't read %s\n", tFieldArray->fields[i].field_name);
|
|
GOTOFAILURE_ALL_EXIF
|
|
break;
|
|
}
|
|
/* set tWriteCount to number of read samples for next steps */
|
|
auxLong = unionLong.Short1;
|
|
}
|
|
/* Save values from temporary array */
|
|
if (tSetFieldType == TIFF_SETGET_C0_FLOAT || tSetFieldType == TIFF_SETGET_C16_FLOAT || tSetFieldType == TIFF_SETGET_C32_FLOAT) {
|
|
memcpy(&auxFloatArray, pVoidArray,(auxLong * sizeof(auxFloatArray[0])));
|
|
/* compare read values with written ones */
|
|
if (tType == TIFF_RATIONAL || tType == TIFF_SRATIONAL) dblDiffLimit = RATIONAL_EPS*auxDoubleArrayW[i]; else dblDiffLimit = 1e-6;
|
|
for (j=0; j<auxLong; j++) {
|
|
dblDiff = auxFloatArray[j] - auxFloatArrayW[i+j];
|
|
if (fabs(dblDiff) > fabs(dblDiffLimit)) {
|
|
/*if (auxFloatArray[j] != (float)auxFloatArrayW[i+j]) { */
|
|
fprintf (stderr, "Read value %d of %s #%d %f differs from set value %f\n", i, tFieldName, j, auxFloatArray[j], auxFloatArrayW[i+j]);
|
|
GOTOFAILURE_ALL_EXIF
|
|
}
|
|
}
|
|
} else {
|
|
memcpy(&auxDoubleArray, pVoidArray,(auxLong * sizeof(auxDoubleArray[0])));
|
|
/* compare read values with written ones */
|
|
if (tType == TIFF_RATIONAL || tType == TIFF_SRATIONAL) dblDiffLimit = RATIONAL_EPS*auxDoubleArrayW[i]; else dblDiffLimit = 1e-6;
|
|
for (j=0; j<auxLong; j++) {
|
|
dblDiff = auxDoubleArray[j] - auxDoubleArrayW[i+j];
|
|
if (fabs(dblDiff) > fabs(dblDiffLimit)) {
|
|
/*if (auxDoubleArray[j] != auxDoubleArrayW[i+j]) { */
|
|
fprintf (stderr, "Read value %d of %s #%d %f differs from set value %f\n", i, tFieldName, j, auxDoubleArray[j], auxDoubleArrayW[i+j]);
|
|
GOTOFAILURE_ALL_EXIF
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case TIFF_SETGET_C0_UINT8:
|
|
case TIFF_SETGET_C0_SINT8:
|
|
case TIFF_SETGET_C16_UINT8:
|
|
case TIFF_SETGET_C16_SINT8:
|
|
case TIFF_SETGET_C32_UINT8:
|
|
case TIFF_SETGET_C32_SINT8:
|
|
/* For arrays, distinguishing between float or double is essential, even for writing */
|
|
pVoid = &auxCharArrayW[i];
|
|
case TIFF_SETGET_C0_UINT16:
|
|
case TIFF_SETGET_C0_SINT16:
|
|
case TIFF_SETGET_C16_UINT16:
|
|
case TIFF_SETGET_C16_SINT16:
|
|
case TIFF_SETGET_C32_UINT16:
|
|
case TIFF_SETGET_C32_SINT16:
|
|
if (pVoid == NULL) pVoid = &auxShortArrayW[i];
|
|
case TIFF_SETGET_C0_UINT32:
|
|
case TIFF_SETGET_C0_SINT32:
|
|
case TIFF_SETGET_C16_UINT32:
|
|
case TIFF_SETGET_C16_SINT32:
|
|
case TIFF_SETGET_C32_UINT32:
|
|
case TIFF_SETGET_C32_SINT32:
|
|
if (pVoid == NULL) pVoid = &auxLongArrayW[i];
|
|
/* _Cxx_ just defines the size of the count parameter for the array as C0=char, C16=short or C32=long */
|
|
/*-- Check, if it is a single parameter, a fixed array or a variable array */
|
|
if (tWriteCount == 1) {
|
|
fprintf (stderr, "WriteCount for .set_field_type %d should be -1 or greather than 1! %s\n", tSetFieldType, tFieldArray->fields[i].field_name);
|
|
} else {
|
|
/*-- Either fix or variable array --*/
|
|
/* Now decide between fixed or variable array */
|
|
if (tWriteCount > 1) {
|
|
/* fixed array with needed arraysize defined in .field_writecount */
|
|
if (!TIFFGetField( tif, tTag, &pVoidArray)) {
|
|
fprintf (stderr, "Can't read %s\n", tFieldArray->fields[i].field_name);
|
|
GOTOFAILURE_ALL_EXIF
|
|
break;
|
|
}
|
|
/* set tWriteCount to number of read samples for next steps */
|
|
auxLong = tWriteCount;
|
|
} else {
|
|
/* special treatment of variable array */
|
|
/* for test, use always arraysize of VARIABLE_ARRAY_SIZE */
|
|
if (!TIFFGetField( tif, tTag, &unionLong, &pVoidArray)) {
|
|
fprintf (stderr, "Can't read %s\n", tFieldArray->fields[i].field_name);
|
|
GOTOFAILURE_ALL_EXIF
|
|
break;
|
|
}
|
|
/* set tWriteCount to number of read samples for next steps */
|
|
auxLong = unionLong.Short1;
|
|
}
|
|
/* Save values from temporary array */
|
|
if (tSetFieldType == TIFF_SETGET_C0_UINT8 || tSetFieldType == TIFF_SETGET_C0_SINT8 ||
|
|
tSetFieldType == TIFF_SETGET_C16_UINT8 || tSetFieldType == TIFF_SETGET_C16_SINT8 ||
|
|
tSetFieldType == TIFF_SETGET_C32_UINT8 || tSetFieldType == TIFF_SETGET_C32_SINT8 ) {
|
|
memcpy(&auxCharArray, pVoidArray,(auxLong * sizeof(auxCharArray[0])));
|
|
/* Compare and check values */
|
|
for (j=0; j<auxLong; j++) {
|
|
if (tTag == EXIFTAG_EXIFVERSION) {
|
|
/*-- Use exifVersion[] instead of auxCharArrayW[] for differently set EXIFVERSION tag */
|
|
if (auxCharArray[j] != exifVersion[j]) {
|
|
fprintf(stderr, "Read value %d of %s #%d %d differs from set value %d\n", i, tFieldName, j, auxCharArray[j], auxCharArrayW[i + j]);
|
|
GOTOFAILURE_ALL_EXIF
|
|
}
|
|
} else {
|
|
if (auxCharArray[j] != auxCharArrayW[i + j]) {
|
|
fprintf(stderr, "Read value %d of %s #%d %d differs from set value %d\n", i, tFieldName, j, auxCharArray[j], auxCharArrayW[i + j]);
|
|
GOTOFAILURE_ALL_EXIF
|
|
}
|
|
}
|
|
}
|
|
} else if (tSetFieldType == TIFF_SETGET_C0_UINT16 || tSetFieldType == TIFF_SETGET_C0_SINT16 ||
|
|
tSetFieldType == TIFF_SETGET_C16_UINT16 || tSetFieldType == TIFF_SETGET_C16_SINT16 ||
|
|
tSetFieldType == TIFF_SETGET_C32_UINT16 || tSetFieldType == TIFF_SETGET_C32_SINT16 ) {
|
|
memcpy(&auxShortArray, pVoidArray,(auxLong * sizeof(auxShortArray[0])));
|
|
/* Compare and check values */
|
|
for (j=0; j<auxLong; j++) {
|
|
if (auxShortArray[j] != auxShortArrayW[i+j]) {
|
|
fprintf (stderr, "Read value %d of %s #%d %d differs from set value %d\n", i, tFieldName, j, auxShortArray[j], auxShortArrayW[i+j]);
|
|
GOTOFAILURE_ALL_EXIF
|
|
}
|
|
}
|
|
} else if (tSetFieldType == TIFF_SETGET_C0_UINT32 || tSetFieldType == TIFF_SETGET_C0_SINT32 ||
|
|
tSetFieldType == TIFF_SETGET_C16_UINT32 || tSetFieldType == TIFF_SETGET_C16_SINT32 ||
|
|
tSetFieldType == TIFF_SETGET_C32_UINT32 || tSetFieldType == TIFF_SETGET_C32_SINT32 ) {
|
|
memcpy(&auxLongArray, pVoidArray,(auxLong * sizeof(auxLongArray[0])));
|
|
/* Compare and check values */
|
|
for (j=0; j<auxLong; j++) {
|
|
if (auxLongArray[j] != auxLongArrayW[i+j]) {
|
|
fprintf (stderr, "Read value %d of %s #%d %ld differs from set value %ld\n", i, tFieldName, j, auxLongArray[j], auxLongArrayW[i+j]);
|
|
GOTOFAILURE_ALL_EXIF
|
|
}
|
|
}
|
|
} else {
|
|
fprintf (stderr, "SetFieldType %d not defined within switch case reading for UINT for %s.\n", tSetFieldType, tFieldName);
|
|
GOTOFAILURE
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
fprintf (stderr, "SetFieldType %d not defined within writing switch for %s.\n", tSetFieldType, tFieldName);
|
|
GOTOFAILURE
|
|
}; /*-- switch() --*/
|
|
} /*-- for() --*/
|
|
/*================= EXIF: END Reading arbitrary data to the EXIF fields END END END ==============*/
|
|
#endif /*-- READ_ALL_EXIF_TAGS --*/
|
|
#endif /*-- READ_EXIF_TAGS --*/
|
|
|
|
|
|
|
|
|
|
TIFFClose(tif);
|
|
|
|
/* All tests passed; delete file and exit with success status. */
|
|
#ifdef FOR_AUTO_TESTING
|
|
unlink(filenameRead);
|
|
#endif
|
|
fprintf(stderr, "-------- Test finished OK ----------\n");
|
|
return 0;
|
|
|
|
failure:
|
|
/*
|
|
* Something goes wrong; close file and return unsuccessful status.
|
|
* Do not remove the file for further manual investigation.
|
|
*/
|
|
TIFFClose(tif);
|
|
fprintf(stderr, "-------- Test finished with FAILURE --------\n");
|
|
return 1;
|
|
}
|