# Preserving EXIF Data in Appfarm: Is It Possible?

**URL:** <https://community.appfarm.io/t/preserving-exif-data-in-appfarm-is-it-possible/1441>\
**Category:** Ask the community\
**Created:** [October 10, 2024, 2:50pm UTC](https://community.appfarm.io/t/preserving-exif-data-in-appfarm-is-it-possible/1441 "2024-10-10T14:50:28Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![lbj](https://dub1.discourse-cdn.com/flex013/user_avatar/community.appfarm.io/lbj/32/82_2.png) [@lbj](https://community.appfarm.io/u/lbj)\
**Post date:** [October 10, 2024, 2:50pm UTC](https://community.appfarm.io/t/preserving-exif-data-in-appfarm-is-it-possible/1441/1 "2024-10-10T14:50:28Z")

</div>

It seems that Appfarm is removing EXIF data from photos when the photo is stored as a file on the server. I can read the EXIF data from the image when it’s a runtime object, but as soon as I save the file and retrieve it, the information appears to be lost. I’ve experimented with various settings, such as compression, but the issue doesn’t seem to be related to that.

Is there any way to preserve EXIF data when storing photos in Appfarm? I would appreciate having built-in support for EXIF data as an optional feature for images.

Has anyone managed to preserve this data in Appfarm?

---

<div class="post-metadata">

**Author:** ![kristian](https://dub1.discourse-cdn.com/flex013/user_avatar/community.appfarm.io/kristian/32/58_2.png) [@kristian](https://community.appfarm.io/u/kristian)\
**Post date:** [October 11, 2024, 5:58am UTC](https://community.appfarm.io/t/preserving-exif-data-in-appfarm-is-it-possible/1441/2 "2024-10-11T05:58:38Z")

</div>

Hi!

I believe the EXIF metadata is removed if you use `Compress image` or `Max Image Size` with the upload (Create File Object). I just tested with a jpeg with some metadata, uploaded to Appfarm with Create File Object, and downloaded with Open URL:

- With Compression: The metadata was removed
- Without Compression: The metadata was intact

There are external libraries to be used if you want to access this EXIF metadata with javascript inside your application. If you need to compress images, I also believe you may e.g. use coded component and HTML5 to extract the EXIF data before the upload, store it, and apply it on download (not 100% sure, but looks like a possibility).

---

<div class="post-metadata">

**Author:** ![lbj](https://dub1.discourse-cdn.com/flex013/user_avatar/community.appfarm.io/lbj/32/82_2.png) [@lbj](https://community.appfarm.io/u/lbj)\
**Post date:** [October 11, 2024, 8:31am UTC](https://community.appfarm.io/t/preserving-exif-data-in-appfarm-is-it-possible/1441/3 "2024-10-11T08:31:41Z")

</div>

You are correct that some EXIF data survive when you turn off compression. But most information is still lost. Comparing the same image before and after save (no compression) gives me this:

 ![image](https://europe1.discourse-cdn.com/flex013/uploads/appfarm/original/2X/6/6e3c338b2404cb73eb954c5ee29ce9110f1ee7e5.png)  
In my case, all the important information like GPS position, SubjectDistance and OriginalDate was lost.

I’m currently using an approach where I use a coded component when photos are uploaded. I’m using this library: [https://cdnjs.cloudflare.com/ajax/libs/exif-js/2.3.0/exif.js](https://cdnjs.cloudflare.com/ajax/libs/exif-js/2.3.0/exif.js)

I then extract the data I need and store on the file object. This is the current code in case anyone else need to do the same:

```auto
function displayImageAndExif(fileUrl) {
  const img = new Image(); // Create a new image object
  img.src = fileUrl;

  console.log("Attempting to load image from URL:", fileUrl); // Debug info for the URL

  img.onload = function() {
    console.log("Image loaded successfully.");
    console.log("Image dimensions:", img.width, "x", img.height); // Display image dimensions
    console.log("Image source:", img.src); // Display the image source URL

    EXIF.getData(img, function() {
      const allMetaData = EXIF.getAllTags(this);
      let dateTimeOriginal = allMetaData.DateTimeOriginal || null;
      let latitude = null;
      let longitude = null;

      // Convert Latitude and Longitude to decimal format
      if (allMetaData.GPSLatitude && allMetaData.GPSLongitude) {
        latitude = convertDMSToDecimal(allMetaData.GPSLatitude, allMetaData.GPSLatitudeRef);
        longitude = convertDMSToDecimal(allMetaData.GPSLongitude, allMetaData.GPSLongitudeRef);
      }

      // Format DateTimeOriginal to ISO 8601 format (yyyy-MM-ddTHH:mm:ss.SSSZ)
      if (dateTimeOriginal) {
        dateTimeOriginal = formatDateTimeToISO(dateTimeOriginal);
      }

      // Output EXIF data to the console and update the respective Appfarm data fields
      if (dateTimeOriginal) {
        console.log("DateTimeOriginal:", dateTimeOriginal);
        exifextractor.data.dateTimeOriginal.set(dateTimeOriginal);
      } else {
        console.log("DateTimeOriginal not found.");
        exifextractor.data.dateTimeOriginal.set('');
      }

      if (latitude && longitude) {
        console.log("Latitude:", latitude, "Longitude:", longitude);
        exifextractor.data.latitude.set(latitude);
        exifextractor.data.longitude.set(longitude);
      } else {
        console.log("Latitude and/or Longitude not found.");
        exifextractor.data.latitude.set('');
        exifextractor.data.longitude.set('');
      }
    });
  };

  img.onerror = function() {
    console.error("Failed to load image. Please check the URL.");
  };
}

// Helper function to convert DMS to Decimal format
function convertDMSToDecimal(dms, ref) {
  const degrees = dms[0];
  const minutes = dms[1];
  const seconds = dms[2];
  let decimal = degrees + minutes / 60 + seconds / 3600;
  if (ref === "S" || ref === "W") {
    decimal = -decimal;
  }
  return decimal;
}

// Helper function to format DateTimeOriginal to ISO 8601 format
function formatDateTimeToISO(dateTime) {
  const [date, time] = dateTime.split(" ");
  const formattedDate = date.replace(/:/g, "-"); // Convert yyyy:mm:dd to yyyy-mm-dd
  const formattedTime = time + ".000Z"; // Add milliseconds and Zulu time zone
  return formattedDate + "T" + formattedTime;
}

// Listen for changes in the file URL
exifextractor.data.fileContent.on("change", () => {
  const fileUrl = exifextractor.data.fileContent.get(); // Get the updated image URL
  if (fileUrl) {
    displayImageAndExif(fileUrl); // Call the function to display the image and extract EXIF data
  }
});

```

I would personally prefer if Appfarm could offer a way to preserve all of EXIF data even when using compression.

---

<div class="post-metadata">

**Author:** ![kristian](https://dub1.discourse-cdn.com/flex013/user_avatar/community.appfarm.io/kristian/32/58_2.png) [@kristian](https://community.appfarm.io/u/kristian)\
**Post date:** [October 11, 2024, 8:54am UTC](https://community.appfarm.io/t/preserving-exif-data-in-appfarm-is-it-possible/1441/4 "2024-10-11T08:54:25Z")

</div>

Hi!

Strange. Not sure why, but in my case - uploading a jpg of 5.4MB taken with a mobile phone - the EXIF metadata are the same (see attached image). I used the following tool to analyze both:

> **[Image Metadata Viewer - Online EXIF Data Viewer](https://pics.io/photo-metadata-viewer)**
>
> FREE SERVICE: Online metadata (EXIF) viewer for your photos and images.

But, if you are able to solve this with coded component - go for it 😉

BEFORE:

```auto
FileName Example photo.jpg 
FileSize 5.4 MB 
FileModifyDate 2024:10:11 08:47:40+0000 
FileAccessDate 2024:10:11 08:47:40+0000 
FileInodeChangeDate 2024:10:11 08:47:40+0000 
FilePermissions -rw-rw-r-- 
FileType JPEG 
FileTypeExtension jpg 
MIMEType image/jpeg 
ExifByteOrder Big-endian (Motorola, MM) 
ImageWidth 4000 
ImageHeight 3000 
EncodingProcess Baseline DCT, Huffman coding 
BitsPerSample 8 
ColorComponents 3 
YCbCrSubSampling YCbCr4:2:0 (2 2) 
ImageDescription Kristians example photo 
Make samsung 
Model Galaxy S24 Ultra 
Orientation Rotate 90 CW 
XResolution 72 
YResolution 72 
ResolutionUnit inches 
Software S928BXXU3AXH7 
ModifyDate 2024:10:10 20:09:40+0000 
Artist Kristian Mella 
YCbCrPositioning Centered 
ExposureTime 1/100 
FNumber 1.7 
ExposureProgram Program AE 
ISO 1000 
ExifVersion 0220 
DateTimeOriginal 2024:10:10 20:09:40+0000 
CreateDate 2024:10:10 20:09:40+0000 
OffsetTime +02:00 
OffsetTimeOriginal +02:00 
ShutterSpeedValue 1 
ApertureValue 1.7 
ExposureCompensation 0 
MaxApertureValue 1.7 
MeteringMode Center-weighted average 
Flash No Flash 
FocalLength 6.3 mm 
SubSecTime 868 
SubSecTimeOriginal 868 
SubSecTimeDigitized 868 
FlashpixVersion 0100 
ColorSpace Uncalibrated 
ExifImageWidth 4000 
ExifImageHeight 3000 
ExposureMode Auto 
WhiteBalance Auto 
DigitalZoomRatio 1 
FocalLengthIn35mmFormat 23 mm 
SceneCaptureType Standard 
ImageUniqueID HK0XLQE00VM 
GPSLatitudeRef North 
GPSLatitude +59.9021866000 
GPSLongitudeRef East 
GPSLongitude +10.5365771000 
GPSAltitudeRef Above Sea Level 
GPSAltitude 80 m Above Sea Level 
XPTitle Kristians example photo 
XPAuthor Kristian Mella 
XPSubject Testing metadata 
Padding (Binary data 268 bytes, use -b option to extract) 
Compression JPEG (old-style) 
ThumbnailOffset 1772 
ThumbnailLength 23080 
ThumbnailImage (Binary data 23080 bytes, use -b option to extract) 
ProfileCMMType 	  
ProfileVersion 4.3.0 
ProfileClass Display Device Profile 
ColorSpaceData RGB  
ProfileConnectionSpace XYZ  
ProfileDateTime 2022:07:01 00:00:00+0000 
ProfileFileSignature acsp 
PrimaryPlatform Unknown (SEC) 
CMMFlags Not Embedded, Independent 
DeviceManufacturer Unknown (SEC) 
DeviceModel 	  
DeviceAttributes Reflective, Glossy, Positive, Color 
RenderingIntent Perceptual 
ConnectionSpaceIlluminant 0.9642 1 0.82491 
ProfileCreator Unknown (SEC) 
ProfileID 0 
ProfileDescription DCI-P3 D65 Gamut with sRGB Transfer 
ProfileCopyright Copyright (c) 2022 Samsung Electronics Co., Ltd. 
MediaWhitePoint 0.9642 1 0.82491 
ChromaticAdaptation 1.04781 0.02289 -0.05013 0.02954 0.99048 -0.01704 -0.00923 0.01505 0.75214 
RedMatrixColumn 0.51508 0.24117 -0.00105 
GreenMatrixColumn 0.29195 0.69223 0.04189 
BlueMatrixColumn 0.15718 0.06659 0.78455 
RedTRC (Binary data 32 bytes, use -b option to extract) 
GreenTRC (Binary data 32 bytes, use -b option to extract) 
BlueTRC (Binary data 32 bytes, use -b option to extract) 
XMPToolkit Adobe XMP Core 5.1.2 
Version 1 
DirectoryItemSemantic Primary 
DirectoryItemMime image/jpeg 
DirectoryItemLength 40637 
About uuid:faf5bdd5-ba3d-11da-ad31-d33d75182f1b 
Creator Kristian Mella 
Title Kristians example photo 
Description Kristians example photo 
MPFVersion 0100 
NumberOfImages 2 
MPImageFlags (none) 
MPImageFormat JPEG 
MPImageType Undefined 
MPImageLength 40637 
MPImageStart 5404096 
DependentImage1EntryNumber 0 
DependentImage2EntryNumber 0 
MPImage2 (Binary data 40637 bytes, use -b option to extract) 
Aperture 1.7 
ImageSize 4000x3000 
Megapixels 12 
ScaleFactor35efl 3.7 
ShutterSpeed 1/100 
SubSecCreateDate 2024:10:10 20:09:40+0000 
SubSecDateTimeOriginal 2024:10:10 20:09:40+0200 
SubSecModifyDate 2024:10:10 20:09:40+0200 
CircleOfConfusion 0.008 mm 
FOV 76.1 deg 
FocalLength35efl 6.3 mm (35 mm equivalent: 23.0 mm) 
GPSPosition +59.9021866000, +10.5365771000 
HyperfocalDistance 2.84 m 
LightValue 4.9

```

AFTER:

```auto
FileName Example photo (4).jpg 
FileSize 5.4 MB 
FileModifyDate 2024:10:11 08:48:17+0000 
FileAccessDate 2024:10:11 08:48:16+0000 
FileInodeChangeDate 2024:10:11 08:48:17+0000 
FilePermissions -rw-rw-r-- 
FileType JPEG 
FileTypeExtension jpg 
MIMEType image/jpeg 
ExifByteOrder Big-endian (Motorola, MM) 
ImageWidth 4000 
ImageHeight 3000 
EncodingProcess Baseline DCT, Huffman coding 
BitsPerSample 8 
ColorComponents 3 
YCbCrSubSampling YCbCr4:2:0 (2 2) 
ImageDescription Kristians example photo 
Make samsung 
Model Galaxy S24 Ultra 
Orientation Rotate 90 CW 
XResolution 72 
YResolution 72 
ResolutionUnit inches 
Software S928BXXU3AXH7 
ModifyDate 2024:10:10 20:09:40+0000 
Artist Kristian Mella 
YCbCrPositioning Centered 
ExposureTime 1/100 
FNumber 1.7 
ExposureProgram Program AE 
ISO 1000 
ExifVersion 0220 
DateTimeOriginal 2024:10:10 20:09:40+0000 
CreateDate 2024:10:10 20:09:40+0000 
OffsetTime +02:00 
OffsetTimeOriginal +02:00 
ShutterSpeedValue 1 
ApertureValue 1.7 
ExposureCompensation 0 
MaxApertureValue 1.7 
MeteringMode Center-weighted average 
Flash No Flash 
FocalLength 6.3 mm 
SubSecTime 868 
SubSecTimeOriginal 868 
SubSecTimeDigitized 868 
FlashpixVersion 0100 
ColorSpace Uncalibrated 
ExifImageWidth 4000 
ExifImageHeight 3000 
ExposureMode Auto 
WhiteBalance Auto 
DigitalZoomRatio 1 
FocalLengthIn35mmFormat 23 mm 
SceneCaptureType Standard 
ImageUniqueID HK0XLQE00VM 
GPSLatitudeRef North 
GPSLatitude +59.9021866000 
GPSLongitudeRef East 
GPSLongitude +10.5365771000 
GPSAltitudeRef Above Sea Level 
GPSAltitude 80 m Above Sea Level 
XPTitle Kristians example photo 
XPAuthor Kristian Mella 
XPSubject Testing metadata 
Padding (Binary data 268 bytes, use -b option to extract) 
Compression JPEG (old-style) 
ThumbnailOffset 1772 
ThumbnailLength 23080 
ThumbnailImage (Binary data 23080 bytes, use -b option to extract) 
ProfileCMMType 	  
ProfileVersion 4.3.0 
ProfileClass Display Device Profile 
ColorSpaceData RGB  
ProfileConnectionSpace XYZ  
ProfileDateTime 2022:07:01 00:00:00+0000 
ProfileFileSignature acsp 
PrimaryPlatform Unknown (SEC) 
CMMFlags Not Embedded, Independent 
DeviceManufacturer Unknown (SEC) 
DeviceModel 	  
DeviceAttributes Reflective, Glossy, Positive, Color 
RenderingIntent Perceptual 
ConnectionSpaceIlluminant 0.9642 1 0.82491 
ProfileCreator Unknown (SEC) 
ProfileID 0 
ProfileDescription DCI-P3 D65 Gamut with sRGB Transfer 
ProfileCopyright Copyright (c) 2022 Samsung Electronics Co., Ltd. 
MediaWhitePoint 0.9642 1 0.82491 
ChromaticAdaptation 1.04781 0.02289 -0.05013 0.02954 0.99048 -0.01704 -0.00923 0.01505 0.75214 
RedMatrixColumn 0.51508 0.24117 -0.00105 
GreenMatrixColumn 0.29195 0.69223 0.04189 
BlueMatrixColumn 0.15718 0.06659 0.78455 
RedTRC (Binary data 32 bytes, use -b option to extract) 
GreenTRC (Binary data 32 bytes, use -b option to extract) 
BlueTRC (Binary data 32 bytes, use -b option to extract) 
XMPToolkit Adobe XMP Core 5.1.2 
Version 1 
DirectoryItemSemantic Primary 
DirectoryItemMime image/jpeg 
DirectoryItemLength 40637 
About uuid:faf5bdd5-ba3d-11da-ad31-d33d75182f1b 
Creator Kristian Mella 
Title Kristians example photo 
Description Kristians example photo 
MPFVersion 0100 
NumberOfImages 2 
MPImageFlags (none) 
MPImageFormat JPEG 
MPImageType Undefined 
MPImageLength 40637 
MPImageStart 5404096 
DependentImage1EntryNumber 0 
DependentImage2EntryNumber 0 
MPImage2 (Binary data 40637 bytes, use -b option to extract) 
Aperture 1.7 
ImageSize 4000x3000 
Megapixels 12 
ScaleFactor35efl 3.7 
ShutterSpeed 1/100 
SubSecCreateDate 2024:10:10 20:09:40+0000 
SubSecDateTimeOriginal 2024:10:10 20:09:40+0200 
SubSecModifyDate 2024:10:10 20:09:40+0200 
CircleOfConfusion 0.008 mm 
FOV 76.1 deg 
FocalLength35efl 6.3 mm (35 mm equivalent: 23.0 mm) 
GPSPosition +59.9021866000, +10.5365771000 
HyperfocalDistance 2.84 m 
LightValue 4.9

```

---

<div class="post-metadata">

**Author:** ![lbj](https://dub1.discourse-cdn.com/flex013/user_avatar/community.appfarm.io/lbj/32/82_2.png) [@lbj](https://community.appfarm.io/u/lbj)\
**Post date:** [October 11, 2024, 1:24pm UTC](https://community.appfarm.io/t/preserving-exif-data-in-appfarm-is-it-possible/1441/5 "2024-10-11T13:24:19Z")

</div>

Debugging this issue is tricky because the results vary depending on how the UI is set up. It appears that enabling “Responsive image” affects the EXIF data displayed in the UI. The current challenge is to find a way to extract EXIF data while also storing the images in a compressed format. These two tasks don’t seem compatible at the moment. I can extract EXIF data from a file object if compression isn’t applied, but I haven’t found a way to copy that image to another file and compress it afterward. Given the high resolution of phone cameras today, I’m hesitant to store all photos at full size.

---

<div class="post-metadata">

**Author:** ![lbj](https://dub1.discourse-cdn.com/flex013/user_avatar/community.appfarm.io/lbj/32/82_2.png) [@lbj](https://community.appfarm.io/u/lbj)\
**Post date:** [October 11, 2024, 2:32pm UTC](https://community.appfarm.io/t/preserving-exif-data-in-appfarm-is-it-possible/1441/6 "2024-10-11T14:32:41Z")

</div>

As a follow-up question; Apart from taking up more space, will storing the images in full-size have a performance impact as well, if I use **Responsive Image** when showing the image in the UI?

---

<div class="post-metadata">

**Author:** ![kristian](https://dub1.discourse-cdn.com/flex013/user_avatar/community.appfarm.io/kristian/32/58_2.png) [@kristian](https://community.appfarm.io/u/kristian)\
**Post date:** [October 14, 2024, 12:54pm UTC](https://community.appfarm.io/t/preserving-exif-data-in-appfarm-is-it-possible/1441/7 "2024-10-14T12:54:21Z")

</div>

Responsive images make the image resize “runtime and on the fly” server side before the image is served to the client/browser. I.e. if the photo is stored with very high resolution (e.g. 50 Mpixels / 50 Mbytes) it may be resized to 0.6 Mbytes on small devices (not a precise number, just to illustrate). So the benefit of responsive images should be high for high-res photos.

The stored image itself is not tampered with, but if you e.g. use the Image UI Component with “Responsive image”, and the user right clicks the image in the client and downloads the image, then the metadata will be removed, since that image is compressed. However, if you use the “Open URL” action node, you will download the original file with its metadata intact.
