Jára
Jára

Reputation: 21

How to store EXIF tags into a TIFF file

I want to transfer EXIF from JPG/PNG/WEBP into a TIFF. The TIFF does not allow EXIF to be a solid blob.

The worst think is that I cannot store tags that tifflib does not recognise. I cannot use custom tags because tag numbers are obtained from EXIF and not known during compillation.

It is too bad that I know Tag/Field/Long2/Value and I cannot directly store them into a newly created TIFF file. I know only one way how to create field: TIFFSetField. And this function does not allow me to influence directly all items inside TIFF file.

Is there any way how to bypass this and force field that is needed?

The following code copies only known tags to TIFF library.

int AddExifFields(TIFF *tiff, const unsigned char *profile_data, size_t profile_length, MagickBool logging)
{
const TIFFField *fip;
  .......................

  IFDpos = 4;
  do
  {
    Value = LD_UINT32(profile_data+IFDpos);
    if(Value<=IFDpos || Value<8) return FieldCount; // 0 means stop; IFDPOS should progress.
    IFDpos = Value;

    EntryNum = LD_UINT16(profile_data+IFDpos);
    IFDpos += 2;
    while(EntryNum>0)
    {
      Tag = LD_UINT16(profile_data+IFDpos);
      Field = LD_UINT16(profile_data+IFDpos+2);
      Long2 = LD_UINT32(profile_data+IFDpos+4);
      Value = LD_UINT32(profile_data+IFDpos+8);

      fip = TIFFFindField(tiff, Tag, TIFF_ANY);

      if(logging)
        (void)LogMagickEvent(CoderEvent,GetMagickModule(),"Extracted tag from EXIF %xh, Field %d, Long2 %d, val %d %s",
                             Tag, Field, Long2, Value, FipFieldName(fip));

      if(fip!=NULL)     /* libtiff doesn't understand these */
      {
        const TIFFDataType FDT = TIFFFieldDataType(fip);
/*
        if(FieldCount==0)
        {
          if(TIFFCreateEXIFDirectory(tiff) != 0)
            if (logging)
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                                "TIFFCreateEXIFDirectory() failed.");
        }
*/
        switch(Field)
        {
          case TIFF_ASCII:
                            if(FDT!=TIFF_ASCII)
                               break;   /* Incompatible recipe.*/
                           if(Value>=profile_length-1) break;       /* String outside EXIF boundary. */
                           if(TIFFSetField(tiff, Tag, profile_data+Value))
                               FieldCount++;
                           break;
          case TIFF_BYTE:
          case TIFF_SHORT:
          case TIFF_LONG:
                           if(FDT!=TIFF_BYTE && FDT!=TIFF_SHORT && FDT!=TIFF_LONG)
                               break;
                           if(TIFFSetField(tiff, Tag, Value))
                               FieldCount++;
                           break;
          //case TIFF_SRATIONAL:  ??
          case TIFF_RATIONAL:
                           if(FDT == TIFF_RATIONAL)
                           {
                             double d = Value / (double)Long2;
                             if(TIFFSetField(tiff, Tag, d))
                                 FieldCount++;
                           }
                           break;
        }
      }
      IFDpos += 12; // Go to a next direntry.
      if(IFDpos+12>=profile_length) return FieldCount;
      EntryNum--;
    }
  } while(IFDpos+4 < profile_length);

  return FieldCount;
}


uint64_t dir_offset = 0;
TIFFCreateEXIFDirectory(tiff);
AddExifFields(tiff,profile_data,profile_length,logging);
TIFFWriteCustomDirectory(tiff, &dir_offset);
TIFFSetDirectory(tiff, 0);
TIFFSetField(tiff, TIFFTAG_EXIFIFD, dir_offset);

Upvotes: 1

Views: 101

Answers (0)

Related Questions