ruby-exiv2 0.2 → 0.3
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.
- data/README +12 -0
- data/lib/Makefile +1 -1
- data/lib/exif.cpp +76 -7
- data/lib/exiv2.cpp +15 -0
- data/lib/exiv2.hpp +3 -0
- data/lib/extconf.rb +3 -2
- data/test/image.rb +53 -25
- metadata +2 -2
data/README
CHANGED
data/lib/Makefile
CHANGED
@@ -40,7 +40,7 @@ CFLAGS = -fno-common -O -pipe -I/opt/local/include -fno-common -pipe -fno-co
|
|
40
40
|
CPPFLAGS = -I. -I$(topdir) -I$(hdrdir) -I$(srcdir) -DHAVE_EXIF_HPP -O -pipe -I/opt/local/include -Wall -I/usr/local/include/exiv2 -I/usr/include/exiv2
|
41
41
|
CXXFLAGS = $(CFLAGS)
|
42
42
|
DLDFLAGS = -L/opt/local/lib -lstdc++
|
43
|
-
LDSHARED =
|
43
|
+
LDSHARED = cc -dynamic -bundle -undefined suppress -flat_namespace
|
44
44
|
AR = ar
|
45
45
|
EXEEXT =
|
46
46
|
|
data/lib/exif.cpp
CHANGED
@@ -9,7 +9,7 @@ static VALUE unmarshall_value(const Exiv2::Value& value) {
|
|
9
9
|
|
10
10
|
Exiv2::TypeId type_id = value.typeId();
|
11
11
|
switch(type_id) {
|
12
|
-
case Exiv2::invalidTypeId:
|
12
|
+
case Exiv2::invalidTypeId:
|
13
13
|
{
|
14
14
|
rb_warn("Trying to demarshall invalid type id");
|
15
15
|
return Qnil;
|
@@ -31,16 +31,17 @@ static VALUE unmarshall_value(const Exiv2::Value& value) {
|
|
31
31
|
VALUE str = rb_str_buf_new(value.size() - 1);
|
32
32
|
value.copy((Exiv2::byte *)STR(str), Exiv2::littleEndian);
|
33
33
|
LEN(str) = value.size() - 1;
|
34
|
+
STR(str)[LEN(str)] = '\0';
|
35
|
+
LEN(str) = strlen(STR(str));
|
34
36
|
return str;
|
35
37
|
}
|
36
38
|
|
37
39
|
case Exiv2::unsignedRational:
|
38
40
|
case Exiv2::signedRational:
|
39
41
|
{
|
40
|
-
return rb_str_new2(value.toString().c_str());
|
41
42
|
Exiv2::Rational r = value.toRational();
|
42
43
|
ID rational_id = rb_intern("Rational");
|
43
|
-
if(
|
44
|
+
if(rb_const_defined(rb_cObject, rational_id)) {
|
44
45
|
VALUE rational = rb_const_get(rb_cObject, rational_id);
|
45
46
|
return rb_funcall(rational, rb_intern("new!"), 2, INT2NUM(r.first), INT2NUM(r.second));
|
46
47
|
}
|
@@ -95,6 +96,67 @@ static VALUE exiv2_exif_get(VALUE self, VALUE key) {
|
|
95
96
|
__NIL_END
|
96
97
|
}
|
97
98
|
|
99
|
+
/*
|
100
|
+
* First, I have to get out type by key. If such key is forbidden, I will refuse to marshall it.
|
101
|
+
* Then, I will cast ruby VALUE to C++ value, according to type_id
|
102
|
+
* then I will just set apropreciated hash entry to this casted value
|
103
|
+
*/
|
104
|
+
static bool marshall_value(Exiv2::ExifData &exifData, const char* key, VALUE value) {
|
105
|
+
Exiv2::ExifKey exif_key(key);
|
106
|
+
Exiv2::TypeId type_id = Exiv2::ExifTags::tagType(exif_key.tag(), exif_key.ifdId());
|
107
|
+
switch(type_id) {
|
108
|
+
case Exiv2::invalidTypeId:
|
109
|
+
{
|
110
|
+
rb_warn("Trying to marshall invalid type id");
|
111
|
+
return Qnil;
|
112
|
+
}
|
113
|
+
|
114
|
+
case Exiv2::unsignedByte:
|
115
|
+
case Exiv2::unsignedShort:
|
116
|
+
case Exiv2::unsignedLong:
|
117
|
+
case Exiv2::signedShort:
|
118
|
+
case Exiv2::signedLong:
|
119
|
+
{
|
120
|
+
exifData[key] = NUM2INT(value);
|
121
|
+
return true;
|
122
|
+
}
|
123
|
+
|
124
|
+
case Exiv2::asciiString:
|
125
|
+
case Exiv2::string:
|
126
|
+
case Exiv2::undefined:
|
127
|
+
{
|
128
|
+
exifData[key] = std::string(STR(value));
|
129
|
+
return true;
|
130
|
+
}
|
131
|
+
|
132
|
+
case Exiv2::unsignedRational:
|
133
|
+
case Exiv2::signedRational:
|
134
|
+
{
|
135
|
+
if(rb_respond_to(value, rb_intern("numerator"))) {
|
136
|
+
int numerator = NUM2INT(rb_funcall(value, rb_intern("numerator"), 0));
|
137
|
+
int denominator = NUM2INT(rb_funcall(value, rb_intern("denominator"), 0));
|
138
|
+
exifData[key] = Exiv2::Rational(numerator, denominator);
|
139
|
+
return true;
|
140
|
+
}
|
141
|
+
exifData[key] = Exiv2::Rational(NUM2INT(value), 1);
|
142
|
+
return true;
|
143
|
+
}
|
144
|
+
|
145
|
+
case Exiv2::invalid6:
|
146
|
+
case Exiv2::date:
|
147
|
+
case Exiv2::time:
|
148
|
+
case Exiv2::comment:
|
149
|
+
case Exiv2::directory:
|
150
|
+
case Exiv2::lastTypeId:
|
151
|
+
{
|
152
|
+
exifData[key] = std::string(STR(value));
|
153
|
+
return true;
|
154
|
+
}
|
155
|
+
}
|
156
|
+
return false;
|
157
|
+
}
|
158
|
+
|
159
|
+
|
98
160
|
/*
|
99
161
|
* @exif["Exif.Photo.PixelXDimension"] = 3024
|
100
162
|
* [] — is a universal accessor
|
@@ -105,12 +167,19 @@ static VALUE exiv2_exif_set(VALUE self, VALUE key, VALUE value) {
|
|
105
167
|
Data_Get_Struct(self, rbImage, image);
|
106
168
|
|
107
169
|
VALUE strkey = rb_funcall(key, rb_intern("to_s"), 0);
|
108
|
-
|
109
|
-
|
170
|
+
bool marshalled = false;
|
171
|
+
{
|
172
|
+
Exiv2::ExifData &exifData = image->image->exifData();
|
173
|
+
|
174
|
+
marshalled = marshall_value(exifData, STR(strkey), value);
|
175
|
+
}
|
176
|
+
|
177
|
+
if(!marshalled) {
|
178
|
+
THROW("Couldn't write %s", STR(strkey));
|
179
|
+
}
|
110
180
|
|
111
|
-
exifData[STR(strkey)] = STR(strvalue);
|
112
181
|
image->dirty = true;
|
113
|
-
return
|
182
|
+
return value;
|
114
183
|
__NIL_END
|
115
184
|
}
|
116
185
|
|
data/lib/exiv2.cpp
CHANGED
@@ -31,11 +31,26 @@
|
|
31
31
|
|
32
32
|
VALUE mExiv2, cImage, cExif, cIptc, cThumbnail, eError;
|
33
33
|
|
34
|
+
void rb_exiv2_throw(const char *file, long unsigned int line, const char *fmt, ...) {
|
35
|
+
char* message;
|
36
|
+
va_list ap;
|
37
|
+
va_start(ap, fmt);
|
38
|
+
vasprintf(&message, fmt, ap);
|
39
|
+
va_end(ap);
|
40
|
+
|
41
|
+
char error_message[strlen(message) + 80];
|
42
|
+
snprintf(error_message, sizeof(error_message), "%s. File: %s, line: %lu", message, file, line);
|
43
|
+
free(message);
|
44
|
+
rb_raise(eError, error_message);
|
45
|
+
}
|
46
|
+
|
47
|
+
|
34
48
|
#ifdef __cplusplus
|
35
49
|
extern "C"
|
36
50
|
#endif
|
37
51
|
|
38
52
|
|
53
|
+
|
39
54
|
void Init_exiv2() {
|
40
55
|
mExiv2 = rb_define_module("Exiv2");
|
41
56
|
|
data/lib/exiv2.hpp
CHANGED
@@ -81,6 +81,9 @@
|
|
81
81
|
#define __NIL_END } catch(Exiv2::AnyError& e) { return Qnil; }
|
82
82
|
#define __VOID_END } catch(Exiv2::AnyError& e) {}
|
83
83
|
|
84
|
+
#define THROW(message, ...) rb_exiv2_throw(__FILE__, __LINE__, message, ##__VA_ARGS__)
|
85
|
+
void rb_exiv2_throw(const char* file, long unsigned int line, const char *fmt, ...);
|
86
|
+
|
84
87
|
#if defined(__cplusplus)
|
85
88
|
extern "C" {
|
86
89
|
#endif
|
data/lib/extconf.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require "mkmf"
|
4
|
-
CONFIG["
|
5
|
-
CONFIG[
|
4
|
+
#CONFIG["CXX"] = "g++ -g " + CONFIG['LDSHARED']
|
5
|
+
CONFIG["CPP"] = "g++ -E "
|
6
|
+
#CONFIG['LDSHARED'] = "g++ -g -dynamic -bundle -undefined suppress -flat_namespace"
|
6
7
|
|
7
8
|
|
8
9
|
|
data/test/image.rb
CHANGED
@@ -14,71 +14,99 @@ class ImageTest < Test::Unit::TestCase
|
|
14
14
|
end
|
15
15
|
begin
|
16
16
|
yield test_file_name
|
17
|
-
rescue
|
17
|
+
rescue StandardError => e
|
18
|
+
File.unlink(test_file_name)
|
19
|
+
raise e
|
18
20
|
end
|
19
21
|
File.unlink(test_file_name)
|
20
22
|
end
|
21
23
|
|
22
24
|
def test_open
|
23
|
-
open_test_file "exiv2-fujifilm-finepix-s2pro.jpg" do |
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
open_test_file "exiv2-fujifilm-finepix-s2pro.jpg" do |filename|
|
26
|
+
open(filename) do |image_file|
|
27
|
+
assert @img = Exiv2::Image.new(image_file), "Image should be opened from IO::File"
|
28
|
+
assert_equal "FinePixS2Pro", @img.exif["Exif.Image.Model"]
|
29
|
+
assert_equal nil, @img.exif["zeze"]
|
30
|
+
assert_equal 3024, @img.exif["Exif.Photo.PixelXDimension"]
|
31
|
+
end
|
28
32
|
end
|
29
33
|
|
30
|
-
open_test_file "exiv2-fujifilm-finepix-s2pro.jpg" do |
|
31
|
-
assert @img = Exiv2::Image.new(
|
34
|
+
open_test_file "exiv2-fujifilm-finepix-s2pro.jpg" do |filename|
|
35
|
+
assert @img = Exiv2::Image.new(filename), "Image should be opened from filename"
|
32
36
|
assert_equal "FinePixS2Pro", @img.exif["Exif.Image.Model"]
|
33
37
|
assert_equal nil, @img.exif["zeze"]
|
34
|
-
assert_equal
|
38
|
+
assert_equal 3024, @img.exif["Exif.Photo.PixelXDimension"]
|
35
39
|
end
|
36
40
|
end
|
37
41
|
|
38
|
-
def
|
39
|
-
open_test_file "exiv2-fujifilm-finepix-s2pro.jpg" do |
|
40
|
-
assert @img = Exiv2::Image.new(
|
42
|
+
def test_write_string
|
43
|
+
open_test_file "exiv2-fujifilm-finepix-s2pro.jpg" do |filename|
|
44
|
+
assert @img = Exiv2::Image.new(filename)
|
41
45
|
assert_equal "FinePixS2Pro", @img.exif["Exif.Image.Model"]
|
42
46
|
assert_equal "*istDs", @img.exif["Exif.Image.Model"] = "*istDs"
|
43
47
|
assert @img.save
|
44
48
|
|
45
|
-
assert @img = Exiv2::Image.new(
|
49
|
+
assert @img = Exiv2::Image.new(filename)
|
46
50
|
assert_equal "*istDs", @img.exif["Exif.Image.Model"]
|
47
51
|
end
|
48
52
|
end
|
49
53
|
|
54
|
+
def test_write_int
|
55
|
+
open_test_file "exiv2-fujifilm-finepix-s2pro.jpg" do |filename|
|
56
|
+
assert @img = Exiv2::Image.new(filename)
|
57
|
+
assert_equal 3024, @img.exif["Exif.Photo.PixelXDimension"]
|
58
|
+
assert_equal 25, @img.exif["Exif.Photo.PixelXDimension"] = 25
|
59
|
+
assert @img.save
|
60
|
+
|
61
|
+
assert @img = Exiv2::Image.new(filename)
|
62
|
+
assert_equal 25, @img.exif["Exif.Photo.PixelXDimension"]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_write_rational
|
67
|
+
open_test_file "exiv2-fujifilm-finepix-s2pro.jpg" do |filename|
|
68
|
+
assert @img = Exiv2::Image.new(filename)
|
69
|
+
assert_equal Rational.new!(72, 1), @img.exif["Exif.Image.XResolution"]
|
70
|
+
assert_equal Rational.new!(27, 11), @img.exif["Exif.Image.XResolution"] = Rational.new!(27, 11)
|
71
|
+
assert @img.save
|
72
|
+
|
73
|
+
assert @img = Exiv2::Image.new(filename)
|
74
|
+
assert_equal Rational.new!(27, 11), @img.exif["Exif.Image.XResolution"]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
|
50
80
|
def test_comment
|
51
|
-
open_test_file "exiv2-fujifilm-finepix-s2pro.jpg" do |
|
52
|
-
assert @img = Exiv2::Image.new(
|
81
|
+
open_test_file "exiv2-fujifilm-finepix-s2pro.jpg" do |filename|
|
82
|
+
assert @img = Exiv2::Image.new(filename)
|
53
83
|
assert_equal "My funny comment", @img.comment = "My funny comment"
|
54
84
|
assert @img.save
|
55
85
|
|
56
|
-
assert @img = Exiv2::Image.new(
|
86
|
+
assert @img = Exiv2::Image.new(filename)
|
57
87
|
assert_equal "My funny comment", @img.comment
|
58
88
|
end
|
59
89
|
end
|
60
90
|
|
61
91
|
def test_typehinting
|
62
|
-
open_test_file "exiv2-fujifilm-finepix-s2pro.jpg" do |
|
63
|
-
assert @img = Exiv2::Image.new(
|
92
|
+
open_test_file "exiv2-fujifilm-finepix-s2pro.jpg" do |filename|
|
93
|
+
assert @img = Exiv2::Image.new(filename)
|
64
94
|
assert @exif = @img.exif
|
65
95
|
assert_equal 1, @exif["Exif.Image.Orientation"]
|
66
96
|
assert_equal "Digital Camera FinePixS2Pro Ver1.00", @exif["Exif.Image.Software"]
|
97
|
+
assert_kind_of Numeric, @exif["Exif.Image.XResolution"]
|
67
98
|
assert_equal 72, @exif["Exif.Image.XResolution"]
|
68
|
-
assert_equal String, @exif["Exif.Image.XResolution"].class
|
69
|
-
puts @exif["Exif.Image.XResolution"].class
|
70
99
|
|
71
100
|
require 'rational'
|
72
101
|
|
73
|
-
|
74
|
-
assert_equal
|
75
|
-
puts @exif["Exif.Image.XResolution"].class
|
102
|
+
assert_kind_of Rational, @exif["Exif.Image.XResolution"]
|
103
|
+
assert_equal Rational.new!(72, 1), @exif["Exif.Image.XResolution"]
|
76
104
|
end
|
77
105
|
end
|
78
106
|
|
79
107
|
def test_each
|
80
|
-
open_test_file "exiv2-fujifilm-finepix-s2pro.jpg" do |
|
81
|
-
assert @img = Exiv2::Image.new(
|
108
|
+
open_test_file "exiv2-fujifilm-finepix-s2pro.jpg" do |filename|
|
109
|
+
assert @img = Exiv2::Image.new(filename)
|
82
110
|
i = 0
|
83
111
|
@img.exif.each do |key, value|
|
84
112
|
i = i + 1
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
|
|
3
3
|
specification_version: 1
|
4
4
|
name: ruby-exiv2
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: "0.
|
7
|
-
date: 2006-
|
6
|
+
version: "0.3"
|
7
|
+
date: 2006-11-07 00:00:00 +03:00
|
8
8
|
summary: Exiv2 (exif image tags handling) library driver
|
9
9
|
require_paths:
|
10
10
|
- lib
|