delphifreeimage

Can't add a metadata to a JPEG image using FreeImage


I try to add metadata to an existing JPEG file and saving the image in another file. I'm using Delphi 11 and FreeImage (Delphi wrapper). The image is produced identical to the existing image, without the added metadata tag. No error at all.

Here is a simple stand alone procedure to reproduce the issue:

procedure AddTagArtistTest;
var
    fif      : FREE_IMAGE_FORMAT;
    dib      : PFIBITMAP;
    Tag      : PFITAG;
    TagValue : AnsiString;
    TagKey   : AnsiString;
    TagID    : WORD;
    Filename : String;
    Success  : Boolean;
begin
    Filename := 'F:\Images\ExistingImage.jpg'; // Already has metadata but no TAG_ARTIST
    dib      := nil;
    Success  := FALSE;
    try
        fif := FreeImage_GetFileTypeU(PChar(FileName), 0);
        if fif = FIF_UNKNOWN then
            fif := FreeImage_GetFIFFromFilenameU(PChar(FileName));
        if fif = FIF_UNKNOWN then
            Exit;
        if not FreeImage_FIFSupportsReading(fif) then
            Exit;
        dib    := FreeImage_LoadU(fif, PChar(Filename), 0);
        if dib = nil then
            Exit;
        Tag      := FreeImage_CreateTag();
        TagValue := 'FRANCOIS PIETTE';
        TagKey   := 'Artist';
        TagID    := $013B; // TAG_ARTIST;
        if not FreeImage_SetTagID(Tag, TagID) then
            Exit;
        if not FreeImage_SetTagKey(Tag, PAnsiChar(TagKey)) then
            Exit;
        if not FreeImage_SetTagType(Tag, FIDT_ASCII) then
            Exit;
        if not FreeImage_SetTagLength(Tag, Length(TagValue) + 1) then
            Exit;
        if not FreeImage_SetTagCount(Tag,  Length(TagValue) + 1) then
            Exit;
        if not FreeImage_SetTagValue(Tag, PAnsiChar(TagValue)) then
            Exit;
        if not FreeImage_SetMetadata(FIMD_EXIF_MAIN,
                                     dib,
                                     PAnsiChar(TagKey),
                                     Tag) then
            Exit;
        if not FreeImage_SaveU(FIF_JPEG,
                               dib,
                               PChar(ChangeFileExt(FileName, '_2.jpg')),
                               0) then
            Exit;
        Success := TRUE;
    finally
        if dib <> nil then
            FreeImage_Unload(dib);
        if Success then
            WriteLn('Success')
        else
            WriteLn('Failed');
    end;
end;

Any idea about what I'm doing wrong?


Solution

  • As per the documentation, page 76, Table 13 writing EXIF_MAIN to a JPEG is not supported - only reading is:

    FIF_JPEG FIF_TIFF FIF_PNG FIF_GIF FIF_RAW FIF_JXR FIF_WEBP
    0 = FIMD_COMMENTS R/W - R/W R/W - - -
    1 = FIMD_EXIF_MAIN R R/W - - R R/W R
    2 = FIMD_EXIF_EXIF R R - - R R/W R
    3 = FIMD_EXIF_GPS R - - - R R/W R
    4 = FIMD_EXIF_MAKERNOTE R - - - R R R
    5 = FIMD_EXIF_INTEROP R - - - R R R
    6 = FIMD_IPTC R/W R/W - - - R/W -
    7 = FIMD_XMP R/W R/W R/W - - R/W R/W
    8 = FIMD_GEOTIFF - R/W - - - - -
    9 = FIMD_ANIMATION - - - R/W - - -
    10 = FIMD_CUSTOM - - - - - - -
    11 = FIMD_EXIF_RAW R/W - - - - - R/W

    Which means: if you save it as i.e. FIF_TIFF you'll get a picture with your newly set metadata in it. Simply change your code into:

            if not FreeImage_SaveU(FIF_TIFF,
                                   dib,
                                   PChar(ChangeFileExt(FileName, '_2.tif')),
                                   0) then
    

    And don't forget to free the tag again:

    FreeImage_DeleteTag( Tag );
    

    Successfully tested this with FreeImage 3.18.0 and D7. A counter example would be to use IPTC or XMP instead of EXIF, as those have write support for a JPEG picture.