diff options
-rw-r--r-- | test/custom_dir_EXIF_231.c | 2795 |
1 files changed, 1397 insertions, 1398 deletions
diff --git a/test/custom_dir_EXIF_231.c b/test/custom_dir_EXIF_231.c index 854b19a9..627edf84 100644 --- a/test/custom_dir_EXIF_231.c +++ b/test/custom_dir_EXIF_231.c @@ -1,1398 +1,1397 @@ -
-/*
- * 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;
-}
+/* + * 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 additional 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; + } + + /*- Variable 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 greater 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 greater 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 always 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 always 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 always 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 always 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 greater 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 greater 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; +} |