Skip to content

Commit

Permalink
Fix decoding invalid Exif dates. Closes #163
Browse files Browse the repository at this point in the history
  • Loading branch information
kipcole9 committed Sep 5, 2024
1 parent fb7bd03 commit 855dfac
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 9 deletions.
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
# Changelog

## Image 0.54.3

This is the changelog for Image version 0.54.3 released on September 6th, 2024. For older changelogs please consult the release tag on [GitHub](https://github.com/elixir-image/image/tags)

### Bug Fixes

* Fix parsing invalid date time in Exif data. When invalid, the raw underlying string is returned.

* Trim strings in Exif data. As a result, empty strings will be returned now as `nil` rather than `""`.

* Replace a ``<<0, ....>>` sequence in an Exif string value with `nil`.

* Decode additional tags:

* Exif tag `0xA005`, Interop Offset. The value is in internal file pointer so has no meaningful interpretation in `image`.

* TIFF tag `0xC4A5`, Print Image Matching. According to [this source](https://www.loc.gov/preservation/digital/formats/content/tiff_tags.shtml) the field has no standardised values so the raw value is returned.

## Image 0.54.2

This is the changelog for Image version 0.54.2 released on September 1st, 2024. For older changelogs please consult the release tag on [GitHub](https://github.com/elixir-image/image/tags)
Expand Down
30 changes: 23 additions & 7 deletions lib/image/exif/decode.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,22 @@ defmodule Image.Exif.Decode do
def tag(:tiff, 0x0100, value), do: {:image_width, value}
def tag(:tiff, 0x0101, value), do: {:image_height, value}
def tag(:tiff, 0x010D, value), do: {:document_name, value}
def tag(:tiff, 0x010E, value), do: {:image_description, value}
def tag(:tiff, 0x010F, value), do: {:make, value}
def tag(:tiff, 0x0110, value), do: {:model, value}
def tag(:tiff, 0x010E, value), do: {:image_description, trim(value)}
def tag(:tiff, 0x010F, value), do: {:make, trim(value)}
def tag(:tiff, 0x0110, value), do: {:model, trim(value)}
def tag(:tiff, 0x0112, value), do: {:orientation, orientation(value)}
def tag(:tiff, 0x011A, value), do: {:x_resolution, value}
def tag(:tiff, 0x011B, value), do: {:y_resolution, value}
def tag(:tiff, 0x0128, value), do: {:resolution_units, resolution(value)}
def tag(:tiff, 0x0131, value), do: {:software, value}
def tag(:tiff, 0x0131, value), do: {:software, trim(value)}
def tag(:tiff, 0x0132, value), do: {:modify_date, date_time(value)}
def tag(:tiff, 0x0213, value), do: {:YCbCr_positioning, ycbcr_positioning(value)}

def tag(:tiff, 0x8769, value), do: {:exif, value}
def tag(:tiff, 0x8825, value), do: {:gps, value}

def tag(:tiff, 0xC4A5, value), do: {:print_image_matching, value}

def tag(:exif, 0x0201, value), do: {:thumbnail_offset, value}
def tag(:exif, 0x0202, value), do: {:thumbnail_size, value}

Expand Down Expand Up @@ -66,6 +68,7 @@ defmodule Image.Exif.Decode do
def tag(_, 0xA002, value), do: {:exif_image_width, value}
def tag(_, 0xA003, value), do: {:exif_image_height, value}
def tag(_, 0xA004, value), do: {:related_sound_file, value}
def tag(_, 0xA005, value), do: {:interopt_offset, value}
def tag(_, 0xA20B, value), do: {:flash_energy, value}
def tag(_, 0xA20C, value), do: {:spatial_frequency_response, value}
def tag(_, 0xA20E, value), do: {:focal_plane_x_resolution, value}
Expand Down Expand Up @@ -98,8 +101,8 @@ defmodule Image.Exif.Decode do
def tag(_, 0xA434, value), do: {:lens_model, value}
def tag(_, 0xA435, value), do: {:lens_serial_number, value}

def tag(_, 0x8298, value), do: {:copyright, value}
def tag(_, 0x13B, value), do: {:artist, value}
def tag(_, 0x8298, value), do: {:copyright, trim(value)}
def tag(_, 0x13B, value), do: {:artist, trim(value)}
def tag(_, 0x9010, value), do: {:time_offset, value}
def tag(_, 0xA431, value), do: {:body_serial_number, value}

Expand All @@ -120,13 +123,26 @@ defmodule Image.Exif.Decode do
defp date_time(date_time) do
case String.split(date_time, [":", "-", "T", " "]) do
[y, m, d, h, mm, s] ->
NaiveDateTime.new!(int(y), int(m), int(d), int(h), int(mm), int(s))
case NaiveDateTime.new(int(y), int(m), int(d), int(h), int(mm), int(s)) do
{:ok, naive_datetime} -> naive_datetime
{:error, _} -> date_time
end

_other ->
date_time
end
end

def trim(value) do
cond do
<<0::size(byte_size(value) * 8)>> == value ->
nil

true ->
String.trim(value)
end
end

@compile {:inline, int: 1}
defp int(string), do: String.to_integer(string)

Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule Image.MixProject do
use Mix.Project

@version "0.54.2"
@version "0.54.3"

@app_name "image"

Expand Down
2 changes: 1 addition & 1 deletion test/exif_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ defmodule Image.ExitTest do
image = image_path("kodak-dc210.jpg")
{:ok, image} = Image.open(image, access: :random)

assert {:ok, %{copyright: "", image_description: ""}} = Image.exif(image)
assert {:ok, %{copyright: nil, image_description: nil}} = Image.exif(image)
end
end

0 comments on commit 855dfac

Please sign in to comment.