format_parser 1.6.0 → 1.7.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 +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +1 -1
- data/lib/format_parser/version.rb +1 -1
- data/lib/parsers/arw_parser.rb +50 -0
- data/lib/parsers/tiff_parser.rb +5 -6
- data/spec/parsers/arw_parser_spec.rb +119 -0
- data/spec/parsers/tiff_parser_spec.rb +9 -15
- metadata +8 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b3cef665ae16efd68e8da952fd4656e2d9403f3899bd58839da3d8026db91f4
|
4
|
+
data.tar.gz: 7b0ec88efc2ea62f526699a4041cb3f1b3062994d2a6e0b24c2cfdf247aaf532
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 24c6379ef4fd3b5a9f061c6fc40fd8c0498ad33213684d08dd27a8b8994ba40a98bf1fa18a6d6b3b8189aa71436ec9bb394e3b8d41a8dd3ca90a5b93d0f1718a
|
7
|
+
data.tar.gz: a2d3df2c17d2559aa99f52f04624032a9243915f2a1b28a6f3626bd3b9112eb8c325b0c9a286864d25c2b4e92a44a8939448a85d1004ac5d48c2f81f747749c1
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -194,7 +194,7 @@ Unless specified otherwise in this section the fixture files are MIT licensed an
|
|
194
194
|
- `IMG_9266_*.tif` and all it's variations were created by the project maintainers
|
195
195
|
|
196
196
|
### ARW
|
197
|
-
- ARW
|
197
|
+
- ARW examples are downloaded from http://www.rawsamples.ch/ and are Creative Common Licensed.
|
198
198
|
|
199
199
|
### ZIP
|
200
200
|
- The .zip fixture files have been created by the project maintainers
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require_relative 'exif_parser'
|
2
|
+
|
3
|
+
class FormatParser::ARWParser
|
4
|
+
include FormatParser::IOUtils
|
5
|
+
include FormatParser::EXIFParser
|
6
|
+
|
7
|
+
# Standard TIFF headers
|
8
|
+
MAGIC_LE = [0x49, 0x49, 0x2A, 0x0].pack('C4')
|
9
|
+
MAGIC_BE = [0x4D, 0x4D, 0x0, 0x2A].pack('C4')
|
10
|
+
HEADER_BYTES = [MAGIC_LE, MAGIC_BE]
|
11
|
+
ARW_MIME_TYPE = 'image/x-sony-arw'
|
12
|
+
|
13
|
+
def likely_match?(filename)
|
14
|
+
filename =~ /\.arw$/i
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(io)
|
18
|
+
io = FormatParser::IOConstraint.new(io)
|
19
|
+
|
20
|
+
return unless HEADER_BYTES.include?(safe_read(io, 4))
|
21
|
+
exif_data = exif_from_tiff_io(io)
|
22
|
+
|
23
|
+
return unless valid?(exif_data)
|
24
|
+
|
25
|
+
w = exif_data.width || exif_data.pixel_x_dimension
|
26
|
+
h = exif_data.height || exif_data.pixel_y_dimension
|
27
|
+
|
28
|
+
FormatParser::Image.new(
|
29
|
+
format: :arw,
|
30
|
+
width_px: w,
|
31
|
+
height_px: h,
|
32
|
+
display_width_px: exif_data.rotated? ? h : w,
|
33
|
+
display_height_px: exif_data.rotated? ? w : h,
|
34
|
+
orientation: exif_data.orientation_sym,
|
35
|
+
intrinsics: { exif: exif_data },
|
36
|
+
content_type: ARW_MIME_TYPE,
|
37
|
+
)
|
38
|
+
rescue EXIFR::MalformedTIFF
|
39
|
+
nil
|
40
|
+
end
|
41
|
+
|
42
|
+
def valid?(exif_data)
|
43
|
+
# taken directly from tiff_parser.rb
|
44
|
+
# Similar to how exiftool determines the image type as ARW, we are implementing a check here
|
45
|
+
# https://github.com/exiftool/exiftool/blob/e969456372fbaf4b980fea8bb094d71033ac8bf7/lib/Image/ExifTool/Exif.pm#L929
|
46
|
+
exif_data.compression == 6 && exif_data.new_subfile_type == 1 && exif_data.make&.start_with?('SONY')
|
47
|
+
end
|
48
|
+
|
49
|
+
FormatParser.register_parser new, natures: :image, formats: :arw
|
50
|
+
end
|
data/lib/parsers/tiff_parser.rb
CHANGED
@@ -6,7 +6,6 @@ class FormatParser::TIFFParser
|
|
6
6
|
MAGIC_BE = [0x4D, 0x4D, 0x0, 0x2A].pack('C4')
|
7
7
|
HEADER_BYTES = [MAGIC_LE, MAGIC_BE]
|
8
8
|
TIFF_MIME_TYPE = 'image/tiff'
|
9
|
-
ARW_MIME_TYPE = 'image/x-sony-arw'
|
10
9
|
|
11
10
|
def likely_match?(filename)
|
12
11
|
filename =~ /\.tiff?$/i
|
@@ -28,20 +27,20 @@ class FormatParser::TIFFParser
|
|
28
27
|
exif_data = exif_from_tiff_io(io)
|
29
28
|
return unless exif_data
|
30
29
|
|
30
|
+
return if arw?(exif_data)
|
31
|
+
|
31
32
|
w = exif_data.width || exif_data.pixel_x_dimension
|
32
33
|
h = exif_data.height || exif_data.pixel_y_dimension
|
33
34
|
|
34
|
-
format = arw?(exif_data) ? :arw : :tif
|
35
|
-
mime_type = arw?(exif_data) ? ARW_MIME_TYPE : TIFF_MIME_TYPE
|
36
35
|
FormatParser::Image.new(
|
37
|
-
format:
|
36
|
+
format: :tif,
|
38
37
|
width_px: w,
|
39
38
|
height_px: h,
|
40
39
|
display_width_px: exif_data.rotated? ? h : w,
|
41
40
|
display_height_px: exif_data.rotated? ? w : h,
|
42
41
|
orientation: exif_data.orientation_sym,
|
43
42
|
intrinsics: {exif: exif_data},
|
44
|
-
content_type:
|
43
|
+
content_type: TIFF_MIME_TYPE,
|
45
44
|
)
|
46
45
|
rescue EXIFR::MalformedTIFF
|
47
46
|
nil
|
@@ -55,7 +54,7 @@ class FormatParser::TIFFParser
|
|
55
54
|
# Similar to how exiftool determines the image type as ARW, we are implementing a check here
|
56
55
|
# https://github.com/exiftool/exiftool/blob/e969456372fbaf4b980fea8bb094d71033ac8bf7/lib/Image/ExifTool/Exif.pm#L929
|
57
56
|
def arw?(exif_data)
|
58
|
-
exif_data.compression == 6 && exif_data.new_subfile_type == 1 && exif_data.make
|
57
|
+
exif_data.compression == 6 && exif_data.new_subfile_type == 1 && exif_data.make&.start_with?('SONY')
|
59
58
|
end
|
60
59
|
|
61
60
|
FormatParser.register_parser new, natures: :image, formats: :tif
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FormatParser::ARWParser do
|
4
|
+
shared_examples 'likely_match for file' do |filename_with_extension|
|
5
|
+
it "matches '#{filename_with_extension}'" do
|
6
|
+
expect(subject.likely_match?(filename_with_extension)).to be_truthy
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
shared_examples 'no likely_match for file' do |filename_with_extension|
|
11
|
+
it "does not match '#{filename_with_extension}'" do
|
12
|
+
expect(subject.likely_match?(filename_with_extension)).to be_falsey
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe 'likely_match' do
|
17
|
+
filenames = ['raw_file', 'another raw file', 'and.another', 'one-more']
|
18
|
+
valid_extensions = ['.arw', '.Arw', '.aRw', '.arW', '.ARw', '.ArW', '.aRW', '.ARW']
|
19
|
+
invalid_extensions = ['.tiff', '.cr2', '.new', '.jpeg']
|
20
|
+
filenames.each do |filename|
|
21
|
+
valid_extensions.each do |extension|
|
22
|
+
include_examples 'likely_match for file', filename + extension
|
23
|
+
end
|
24
|
+
invalid_extensions.each do |extension|
|
25
|
+
include_examples 'no likely_match for file', filename + extension
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe 'parses Sony ARW fixtures as arw format file' do
|
31
|
+
expected_parsed_dimensions = {
|
32
|
+
'RAW_SONY_A100.ARW' => {
|
33
|
+
width_px: 3872,
|
34
|
+
height_px: 2592,
|
35
|
+
display_width_px: 3872,
|
36
|
+
display_height_px: 2592,
|
37
|
+
orientation: :top_left
|
38
|
+
},
|
39
|
+
'RAW_SONY_A700.ARW' => {
|
40
|
+
width_px: 4288,
|
41
|
+
height_px: 2856,
|
42
|
+
display_width_px: 4288,
|
43
|
+
display_height_px: 2856,
|
44
|
+
orientation: :top_left
|
45
|
+
},
|
46
|
+
'RAW_SONY_A900.ARW' => {
|
47
|
+
width_px: 6080,
|
48
|
+
height_px: 4048,
|
49
|
+
display_width_px: 6080,
|
50
|
+
display_height_px: 4048,
|
51
|
+
orientation: :top_left
|
52
|
+
},
|
53
|
+
# rotated 90 degree image
|
54
|
+
'RAW_SONY_DSC-RX100M2.ARW' => {
|
55
|
+
width_px: 5472,
|
56
|
+
height_px: 3648,
|
57
|
+
display_width_px: 3648,
|
58
|
+
display_height_px: 5472,
|
59
|
+
orientation: :right_top,
|
60
|
+
},
|
61
|
+
'RAW_SONY_ILCE-7RM2.ARW' => {
|
62
|
+
width_px: 7952,
|
63
|
+
height_px: 5304,
|
64
|
+
display_width_px: 7952,
|
65
|
+
display_height_px: 5304,
|
66
|
+
orientation: :top_left,
|
67
|
+
},
|
68
|
+
'RAW_SONY_NEX7.ARW' => {
|
69
|
+
width_px: 6000,
|
70
|
+
height_px: 4000,
|
71
|
+
display_width_px: 6000,
|
72
|
+
display_height_px: 4000,
|
73
|
+
orientation: :top_left,
|
74
|
+
},
|
75
|
+
'RAW_SONY_SLTA55V.ARW' => {
|
76
|
+
width_px: 4928,
|
77
|
+
height_px: 3280,
|
78
|
+
display_width_px: 4928,
|
79
|
+
display_height_px: 3280,
|
80
|
+
orientation: :top_left,
|
81
|
+
},
|
82
|
+
}
|
83
|
+
|
84
|
+
Dir.glob(fixtures_dir + '/ARW/*.ARW').each do |arw_path|
|
85
|
+
it "is able to parse #{File.basename(arw_path)}" do
|
86
|
+
expected_dimension = expected_parsed_dimensions[File.basename(arw_path)]
|
87
|
+
# error if a new .arw test file is added without specifying the expected dimensions
|
88
|
+
expect(expected_dimension).not_to be_nil
|
89
|
+
|
90
|
+
parsed = subject.call(File.open(arw_path, 'rb'))
|
91
|
+
expect(parsed).not_to be_nil
|
92
|
+
expect(parsed.nature).to eq(:image)
|
93
|
+
expect(parsed.format).to eq(:arw)
|
94
|
+
expect(parsed.intrinsics[:exif]).not_to be_nil
|
95
|
+
expect(parsed.content_type).to eq('image/x-sony-arw')
|
96
|
+
|
97
|
+
expect(parsed.width_px).to eq(expected_dimension[:width_px])
|
98
|
+
expect(parsed.height_px).to eq(expected_dimension[:height_px])
|
99
|
+
expect(parsed.display_width_px).to eq(expected_dimension[:display_width_px])
|
100
|
+
expect(parsed.display_height_px).to eq(expected_dimension[:display_height_px])
|
101
|
+
expect(parsed.orientation).to eq(expected_dimension[:orientation])
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
shared_examples 'invalid filetype' do |filetype, fixture_path|
|
106
|
+
it "should fail to parse #{filetype}" do
|
107
|
+
file_path = fixtures_dir + fixture_path
|
108
|
+
parsed = subject.call(File.open(file_path, 'rb'))
|
109
|
+
expect(parsed).to be_nil
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
include_examples 'invalid filetype', 'NEF', '/NEF/RAW_NIKON_1S2.NEF'
|
114
|
+
include_examples 'invalid filetype', 'TIFF', '/TIFF/Shinbutsureijoushuincho.tiff'
|
115
|
+
include_examples 'invalid filetype', 'JPG', '/JPEG/orient_6.jpg'
|
116
|
+
include_examples 'invalid filetype', 'PNG', '/PNG/cat.png'
|
117
|
+
include_examples 'invalid filetype', 'CR2', '/CR2/RAW_CANON_1DM2.CR2'
|
118
|
+
end
|
119
|
+
end
|
@@ -47,21 +47,6 @@ describe FormatParser::TIFFParser do
|
|
47
47
|
expect(parsed.intrinsics[:exif]).not_to be_nil
|
48
48
|
end
|
49
49
|
|
50
|
-
it 'parses Sony ARW fixture as arw format file' do
|
51
|
-
arw_path = fixtures_dir + '/ARW/RAW_SONY_ILCE-7RM2.ARW'
|
52
|
-
|
53
|
-
parsed = subject.call(File.open(arw_path, 'rb'))
|
54
|
-
|
55
|
-
expect(parsed).not_to be_nil
|
56
|
-
expect(parsed.nature).to eq(:image)
|
57
|
-
expect(parsed.format).to eq(:arw)
|
58
|
-
|
59
|
-
expect(parsed.width_px).to eq(7952)
|
60
|
-
expect(parsed.height_px).to eq(5304)
|
61
|
-
expect(parsed.intrinsics[:exif]).not_to be_nil
|
62
|
-
expect(parsed.content_type).to eq('image/x-sony-arw')
|
63
|
-
end
|
64
|
-
|
65
50
|
describe 'correctly extracts dimensions from various TIFF flavors of the same file' do
|
66
51
|
Dir.glob(fixtures_dir + '/TIFF/IMG_9266*.tif').each do |tiff_path|
|
67
52
|
it "is able to parse #{File.basename(tiff_path)}" do
|
@@ -100,4 +85,13 @@ describe FormatParser::TIFFParser do
|
|
100
85
|
end
|
101
86
|
end
|
102
87
|
end
|
88
|
+
|
89
|
+
describe 'bails out on ARW files, such as' do
|
90
|
+
Dir.glob(fixtures_dir + '/ARW/*.ARW').each do |arw_path|
|
91
|
+
it "skips #{File.basename(arw_path)}" do
|
92
|
+
parsed = subject.call(File.open(arw_path, 'rb'))
|
93
|
+
expect(parsed).to be_nil
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
103
97
|
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: format_parser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Noah Berman
|
8
8
|
- Julik Tarkhanov
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2022-
|
12
|
+
date: 2022-10-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ks
|
@@ -232,6 +232,7 @@ files:
|
|
232
232
|
- lib/parsers/aac_parser.rb
|
233
233
|
- lib/parsers/aac_parser/adts_header_info.rb
|
234
234
|
- lib/parsers/aiff_parser.rb
|
235
|
+
- lib/parsers/arw_parser.rb
|
235
236
|
- lib/parsers/bmp_parser.rb
|
236
237
|
- lib/parsers/cr2_parser.rb
|
237
238
|
- lib/parsers/dpx_parser.rb
|
@@ -278,6 +279,7 @@ files:
|
|
278
279
|
- spec/parsers/aac_parser_spec.rb
|
279
280
|
- spec/parsers/adts_header_info_spec.rb
|
280
281
|
- spec/parsers/aiff_parser_spec.rb
|
282
|
+
- spec/parsers/arw_parser_spec.rb
|
281
283
|
- spec/parsers/bmp_parser_spec.rb
|
282
284
|
- spec/parsers/cr2_parser_spec.rb
|
283
285
|
- spec/parsers/dpx_parser_spec.rb
|
@@ -310,7 +312,7 @@ licenses:
|
|
310
312
|
- MIT (Hippocratic)
|
311
313
|
metadata:
|
312
314
|
allowed_push_host: https://rubygems.org
|
313
|
-
post_install_message:
|
315
|
+
post_install_message:
|
314
316
|
rdoc_options: []
|
315
317
|
require_paths:
|
316
318
|
- lib
|
@@ -325,8 +327,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
325
327
|
- !ruby/object:Gem::Version
|
326
328
|
version: '0'
|
327
329
|
requirements: []
|
328
|
-
rubygems_version: 3.
|
329
|
-
signing_key:
|
330
|
+
rubygems_version: 3.3.7
|
331
|
+
signing_key:
|
330
332
|
specification_version: 4
|
331
333
|
summary: A library for efficient parsing of file metadata
|
332
334
|
test_files: []
|