From fa9266f3c7dbcc81879d849f0f24826510b19b17 Mon Sep 17 00:00:00 2001 From: Kurt Schwehr Date: Thu, 31 Dec 2020 10:27:53 -0800 Subject: custom_dir_EXIF_231.c: dos2unix and codespell additonal, Varable, greather, alwasy --- test/custom_dir_EXIF_231.c | 2795 ++++++++++++++++++++++---------------------- 1 file 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 - * - * 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 -#include -#include -#include - -#ifdef HAVE_UNISTD_H -# include -#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; iset_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; ifields[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 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 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; ifields[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 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 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 + * + * 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 +#include +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#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; iset_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; ifields[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 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 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; ifields[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 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 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