file_data 5.2.3 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 441d9a1d1481ac066af3b8c0bcd2bae00e7b54b88c322ef251a7579ee79f270b
4
- data.tar.gz: af5797dd26aefac7eddee225a81012b7942283bee76e5add1911d67cb5158d4b
3
+ metadata.gz: 4f9ac51b8c0f2d6388b07ab1f6614de4a1fac558c21689fa61d198d70c18a8b4
4
+ data.tar.gz: 4da0fada39336b0346d0846ee6c04a6962c0c4f34909463ded2c0aa2c97511fe
5
5
  SHA512:
6
- metadata.gz: ea6f2869ffa5b4f2a54d5767b7affc853c546e65866d55d6b655a6ddfddb00f732370abeea3e431cc3a951fb8cf4789d155d9321974181b84cefe8619591db3d
7
- data.tar.gz: efb5a79f2b6297ef5b1f85a7acd6f6d33e8b313a47e6c3cfc0b69080819d6fca5d116158341ede91c5e6b3e0a34c7f641fc27f1fd63c08c9bf28ec11f89ce15b
6
+ metadata.gz: 74284cdbc2af387ad6e0b058d25ec38ade9bb5021eaec62be513b923ad6a38398ae199698d1aa78226306e3a60856a1c1658b59fe4d460fe7e600345ef555dba
7
+ data.tar.gz: 3f7a040e99bc6a47da21c759c687f831014ba7e1823f7b63d8e8af2bfb1ab79fb8abbfd5f49059fdb9ad77aa0c0358585f1a935204104597ea580786a46ee6ec
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- file_data (5.2.3)
4
+ file_data (6.0.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -34,7 +34,6 @@ GEM
34
34
  docile (1.1.5)
35
35
  fakefs (0.10.2)
36
36
  ffi (1.9.25)
37
- ffi (1.9.25-x64-mingw32)
38
37
  highline (2.0.0)
39
38
  json (2.6.0)
40
39
  method_source (0.9.0)
data/README.md CHANGED
@@ -8,69 +8,42 @@ file_data
8
8
 
9
9
  Ruby library that reads file metadata.
10
10
 
11
- The api provides a basic usage and an advanced usage. The basic usage will reopen and reparse the file every time it is called which is no problem when reading a single value but can be a performance drain for multiple values. The advanced usage allows the user to grab more than one value without having to read the file more than once.
12
-
13
- ## Basic Usage
11
+ ## Basic Usage for an Exif File
14
12
 
15
13
  ```ruby
16
- filepath = '...' # Path to a jpeg or mpeg4 file
17
-
18
- # Get the date when the file content originated. When a photo was taken, when a movie was recorded, etc
19
- FileData::FileInfo.origin_date(filepath)
20
-
21
- # Get the date when the file was considered to be created. This is usually tied in some way to when the file itself was created on a disk somewhere (not usually as useful as origin date)
22
- FileData::FileInfo.creation_date(filepath)
23
- ```
24
-
25
- ## Advanced Usage
14
+ require 'file_data'
26
15
 
27
- Varies by file format type. Currently there are low level classes for parsing exif and mpeg4 metadata
16
+ ## Step 1: Read in the exif data using either a file path or a stream
28
17
 
29
- ## Exif documentation
18
+ # Using a file path...
19
+ file_path = '/home/user/desktop/my_file.jpg' # Path to an exif file
20
+ exif_data = FileData::Exif.all_data(file_path) # read in all of the exif data from the file path
30
21
 
31
- Exif data is hierarchical and consists of tag/value pairs. The first level is whether or not the tag applies to the image or the image's thumbnail. Next a tag may be one of several sections and within the section it will have a unique numeric value. So given this terminology a unique key for an exif tag would be something like image/section1/123 for a tag that applies to the image in section 1 with a tag id of 123.
32
-
33
- To read exif data a stream of the jpeg data should be used as input. For performance reasons all of the data that is desired should be extracted in a single method from FileData::Exif. All methods will manipulate the stream position after they are called and the user should not count on the stream position being at a specific location after a FileData::Exif method call.
22
+ # Or using a stream...
23
+ exif_data = File.open(file_path, 'rb') do |f|
24
+ FileData::Exif.all_data(f)
25
+ end
34
26
 
35
- Examples:
27
+ ## Step 2: Data is divided into image data and thumbnail data. Pick which you want to work with.
36
28
 
37
- ```ruby
38
- ## Get Exif data from a file path or stream
29
+ # Both objects are hash-like and should respond to all hash method except .length which instead will return the value of :Image_Structure_Length,
30
+ image_data = exif_data.image
31
+ thumbnail_data = exif_data.thumbnail
39
32
 
40
- # The file path or stream is passed as a parameter to class methods on FileData::Exif
41
- # rather than having the file path or stream set in the constructor and the methods
42
- # be instance methods to ensure that the user falls into a "pit of success" by only
43
- # opening the file once to get tag values rather than potentially multiple times
33
+ ## Step 3: Extract the tag values
44
34
 
45
- # Get image exif data from a file path...
46
- hash = FileData::Exif.image_data_only('/path/to/file.jpg')
47
-
48
- # Get thumbnail exif data from a file stream...
49
- File.open('/path/to/file.jpg', 'rb') do |f|
50
- hash = FileData::Exif.thumbnail_data_only(f)
51
- end
35
+ ### Step 3A: Extract tags with a known name (ones that are listed in the "Known Tag Keys" section below)
52
36
 
53
- ## Extract values depending on how much data is returned
37
+ # Convenience methods are added for the names after the last underscore in the known tag names (casing and underscores are ignored in the convenince method names)
54
38
 
55
- # Image and thumbnail data are returned as a hash with keys
56
- # being the full tag name if it exists in FileData::ExifTags (see below listing)
57
- # or "#{ifd_id}-#{tag_id}" if there is no existing name for the tag in FileData::ExifTags
58
- image_hash = FileData::Exif.image_data_only(file_path_or_stream)
59
- image_description_value = image_hash[:Other_ImageDescription]
60
- unknown_gps_tag_value = image_hash["34853-99999"]
39
+ bits_per_sample = image_data.BitsPerSample # Gets :Image_Structure_BitsPerSample from the :Tiff section
40
+ bits_per_sample = image_data.bits_per_sample # Also gets :Image_Structure_BitsPerSample from the :Tiff section
61
41
 
62
- thumbnail_hash = FileData::Exif.thumbnail_data_only(file_path_or_stream)
63
- image_width_tag_value = thumbnail_hash[:Image_Structure_Width]
64
- unknown_gps_tag_value = thumbnail_hash["Tiff-99999"]
42
+ ### Step 3B: Extract tags without a known name (ones NOT listed in the "Known Tag Keys" section below)
65
43
 
66
- all_data = FileData::Exif.all_data(file_path_or_stream)
67
- image_hash = all_data.image
68
- thumbnail_hash = all_data.thumbnail
44
+ # Use the format "#{ifd_id}-#{tag_id}" for the unknown tag to key into the data
45
+ unknown_gps_tag_value = image_data["34853-99999"]
69
46
 
70
- # For extracting only a specific tag the value is returned and the search key must be
71
- # an array matching the keys needed to get traverse FileData:ExifTags (see below listing)
72
- image_description_value = FileData::Exif.only_image_tag(file_path_or_stream, [:Tiff, 270])
73
- unknown_exif_tag_value = FileData::Exif.only_thumbnail_tag(file_path_or_stream, [34665, 2])
74
47
  ```
75
48
 
76
49
  ## Known Tag Keys
@@ -1,3 +1,5 @@
1
+ require 'set'
2
+
1
3
  module FileData
2
4
  # Container for Exif tag values
3
5
  class ExifData
@@ -5,12 +7,52 @@ module FileData
5
7
  SECTIONS.each { |section| define_method(section[1]) { @hash[section[0]] } }
6
8
 
7
9
  def initialize
8
- @hash = SECTIONS.each_with_object({}) { |pair, hash| hash[pair[0]] = {} }
10
+ @hash = SECTIONS.each_with_object({}) { |pair, hash| hash[pair[0]] = ExifHash.new }
9
11
  end
10
12
 
11
13
  def add_tag(index, ifd_id, tag_id, tag_value)
12
- name = ExifTags.get_tag_name(ifd_id, tag_id)
13
- @hash[index][name] = tag_value
14
+ name_info = ExifTags.get_tag_name(ifd_id, tag_id)
15
+ @hash[index][name_info.name] = tag_value
16
+ end
17
+ end
18
+
19
+ # Hash with convenience methods for accessing known Exif tag values by name
20
+ class ExifHash < BasicObject
21
+ all_tags = ExifTags.tag_groups.values.map{|x| x.values}.flatten
22
+ tags_map = all_tags.each_with_object({}) do |tag, hash|
23
+ hash[tag.to_s.split('_').last.upcase] = tag
24
+ end
25
+
26
+ define_method(:method_missing) do |method_name, *args, &block|
27
+ known_name = tags_map[method_name.to_s.tr('_', '').upcase]
28
+
29
+ if known_name.nil?
30
+ @hash.send(method_name, *args, &block)
31
+ else
32
+ @hash[known_name]
33
+ end
34
+ end
35
+
36
+ define_method(:respond_to_missing?) do |method_name, include_private|
37
+ known_name = tags_map[method_name.to_s.tr('_', '').upcase]
38
+
39
+ if known_name.nil?
40
+ @hash.respond_to?(known_name) || super
41
+ else
42
+ true
43
+ end
44
+ end
45
+
46
+ def initialize
47
+ @hash = {}
48
+ end
49
+
50
+ def [](key)
51
+ @hash[key]
52
+ end
53
+
54
+ def []=(key, value)
55
+ @hash[key] = value
14
56
  end
15
57
  end
16
58
  end
@@ -1,11 +1,14 @@
1
1
  module FileData
2
+ TagNameInfo = Struct.new(:name, :is_known);
3
+
2
4
  # Contains tag number to name information taken from the exif spec
3
5
  class ExifTags
4
6
  singleton_class.class_eval { attr_accessor :tag_groups }
5
7
  @tag_groups = {}
6
8
 
7
9
  def self.get_tag_name(ifd_id, tag_id)
8
- get_known_name(ifd_id, tag_id) || "#{ifd_id}-#{tag_id}".to_sym
10
+ known_name = get_known_name(ifd_id, tag_id)
11
+ TagNameInfo.new(known_name || "#{ifd_id}-#{tag_id}".to_sym, known_name != nil)
9
12
  end
10
13
 
11
14
  def self.get_known_name(ifd_id, tag_id)
@@ -1,3 +1,3 @@
1
1
  module FileData
2
- VERSION = '5.2.3'.freeze
2
+ VERSION = '6.0.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: file_data
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.2.3
4
+ version: 6.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-10-21 00:00:00.000000000 Z
11
+ date: 2021-11-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler