ruby-exiv2 1.3 → 1.5
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 +1 -0
- data/Rakefile +5 -29
- data/{ext → lib}/exiv2.hpp +4 -4
- data/lib/exiv2.rb +22 -28
- data/lib/exiv2/exif.rb +19 -0
- data/lib/exiv2/image.rb +205 -0
- data/lib/exiv2/iptc.rb +19 -0
- data/lib/exiv2/metadata/clear.cpp +14 -0
- data/lib/exiv2/metadata/count.cpp +10 -0
- data/lib/exiv2/metadata/delete.cpp +23 -0
- data/lib/exiv2/metadata/each.cpp +26 -0
- data/lib/exiv2/metadata/get.cpp +21 -0
- data/lib/exiv2/metadata/is_empty.cpp +10 -0
- data/lib/exiv2/metadata/marshall.cpp +85 -0
- data/lib/exiv2/metadata/set.cpp +16 -0
- data/{ext/marshall.cpp → lib/exiv2/metadata/unmarshall.cpp} +0 -1
- data/lib/exiv2/tag.rb +110 -0
- data/lib/exiv2/throw.cpp +12 -0
- data/test/{image.rb → test_image.rb} +14 -2
- metadata +58 -48
- data/ext/exif.cpp +0 -369
- data/ext/exiv2.cpp +0 -78
- data/ext/extconf.rb +0 -75
- data/ext/image.cpp +0 -230
- data/ext/iptc.cpp +0 -253
- data/setup.rb +0 -1585
data/ext/image.cpp
DELETED
@@ -1,230 +0,0 @@
|
|
1
|
-
#include "exiv2.hpp"
|
2
|
-
|
3
|
-
static void image_real_save(rbImage* image);
|
4
|
-
|
5
|
-
static void image_delete(rbImage* image) {
|
6
|
-
__BEGIN
|
7
|
-
image_real_save(image);
|
8
|
-
delete image;
|
9
|
-
__VOID_END
|
10
|
-
}
|
11
|
-
|
12
|
-
static void image_leave(rbImage* image) {
|
13
|
-
|
14
|
-
}
|
15
|
-
|
16
|
-
/*
|
17
|
-
* Document-class: Exiv2::Image
|
18
|
-
* Image is used to access to all exif data of image
|
19
|
-
*
|
20
|
-
* @image = Exiv2::Image.new("my.jpg")
|
21
|
-
* puts @image["Iptc.Application2.DateCreated"]
|
22
|
-
* puts @image["Exif.Image.Software"]
|
23
|
-
*/
|
24
|
-
static VALUE exiv2_image_s_allocate(VALUE klass) {
|
25
|
-
__BEGIN
|
26
|
-
rbImage* image = new rbImage();
|
27
|
-
image->dirty = false;
|
28
|
-
return Data_Wrap_Struct(klass, 0, image_delete, image);
|
29
|
-
__END
|
30
|
-
}
|
31
|
-
|
32
|
-
/*
|
33
|
-
* img = Exiv2::Image.new("IMGP3025.jpg")
|
34
|
-
*/
|
35
|
-
static VALUE exiv2_image_initialize(VALUE self, VALUE file) {
|
36
|
-
__BEGIN
|
37
|
-
rbImage* image;
|
38
|
-
Data_Get_Struct(self, rbImage, image);
|
39
|
-
|
40
|
-
|
41
|
-
try {
|
42
|
-
if(rb_respond_to(file, rb_intern("read"))) {
|
43
|
-
VALUE file_content = rb_funcall(file, rb_intern("read"), 0);
|
44
|
-
rb_iv_set(self, "@file_content", file_content);
|
45
|
-
image->image = Exiv2::ImageFactory::open(CBSTR(file_content), LEN(file_content));
|
46
|
-
} else if(TYPE(file) == T_STRING) {
|
47
|
-
image->image = Exiv2::ImageFactory::open(CSTR(file));
|
48
|
-
}
|
49
|
-
image->image->readMetadata();
|
50
|
-
}
|
51
|
-
catch(const Exiv2::AnyError&) {
|
52
|
-
rb_raise(rb_eStandardError, "Cannot open file %s", STR(file));
|
53
|
-
}
|
54
|
-
return self;
|
55
|
-
__END
|
56
|
-
}
|
57
|
-
|
58
|
-
/*
|
59
|
-
*
|
60
|
-
* Load Exiv2::Image from memory string
|
61
|
-
*
|
62
|
-
* content = File.open("a.jpg").read
|
63
|
-
* img = Exiv2::Image.load_string(content)
|
64
|
-
*/
|
65
|
-
static VALUE exiv2_image_load_string(VALUE self, VALUE string) {
|
66
|
-
__BEGIN
|
67
|
-
Check_Type(string, T_STRING);
|
68
|
-
rbImage* image = new rbImage();
|
69
|
-
image->dirty = false;
|
70
|
-
VALUE img = Data_Wrap_Struct(self, 0, image_delete, image);
|
71
|
-
|
72
|
-
image->image = Exiv2::ImageFactory::open(CBSTR(string), LEN(string));
|
73
|
-
return img;
|
74
|
-
__END
|
75
|
-
}
|
76
|
-
|
77
|
-
|
78
|
-
static void image_real_save(rbImage* image) {
|
79
|
-
if(image->dirty) {
|
80
|
-
image->image->writeMetadata();
|
81
|
-
image->dirty = false;
|
82
|
-
}
|
83
|
-
}
|
84
|
-
|
85
|
-
/*
|
86
|
-
* Save image with changed data
|
87
|
-
*/
|
88
|
-
static VALUE exiv2_image_save(VALUE self) {
|
89
|
-
__BEGIN
|
90
|
-
rbImage* image;
|
91
|
-
Data_Get_Struct(self, rbImage, image);
|
92
|
-
image_real_save(image);
|
93
|
-
return self;
|
94
|
-
__END
|
95
|
-
}
|
96
|
-
|
97
|
-
/*
|
98
|
-
* Clear all metadata in image. Not only exif
|
99
|
-
*/
|
100
|
-
static VALUE exiv2_image_clear(VALUE self) {
|
101
|
-
__BEGIN
|
102
|
-
rbImage* image;
|
103
|
-
Data_Get_Struct(self, rbImage, image);
|
104
|
-
image->image->clearMetadata();
|
105
|
-
image->dirty = true;
|
106
|
-
return self;
|
107
|
-
__END
|
108
|
-
}
|
109
|
-
|
110
|
-
/*
|
111
|
-
* Get comment of image
|
112
|
-
*/
|
113
|
-
static VALUE exiv2_image_get_comment(VALUE self) {
|
114
|
-
__BEGIN
|
115
|
-
rbImage* image;
|
116
|
-
Data_Get_Struct(self, rbImage, image);
|
117
|
-
std::string comment = image->image->comment();
|
118
|
-
return rb_str_new(comment.c_str(), comment.length());
|
119
|
-
__END
|
120
|
-
}
|
121
|
-
|
122
|
-
/*
|
123
|
-
* Set comment in image
|
124
|
-
*/
|
125
|
-
static VALUE exiv2_image_set_comment(VALUE self, VALUE comment) {
|
126
|
-
__BEGIN
|
127
|
-
rbImage* image;
|
128
|
-
Data_Get_Struct(self, rbImage, image);
|
129
|
-
switch(TYPE(comment)) {
|
130
|
-
case T_STRING: {
|
131
|
-
image->image->setComment(CSTR(comment));
|
132
|
-
image->dirty = true;
|
133
|
-
break;
|
134
|
-
}
|
135
|
-
case T_NIL: {
|
136
|
-
image->image->clearComment();
|
137
|
-
image->dirty = true;
|
138
|
-
break;
|
139
|
-
}
|
140
|
-
default: {
|
141
|
-
rb_raise(rb_eStandardError, "Can only set comment to string, or clear it with nil value");
|
142
|
-
}
|
143
|
-
}
|
144
|
-
return comment;
|
145
|
-
__END
|
146
|
-
}
|
147
|
-
|
148
|
-
/*
|
149
|
-
* Access to exif data of image
|
150
|
-
*/
|
151
|
-
static VALUE exiv2_image_exif(VALUE self) {
|
152
|
-
__BEGIN
|
153
|
-
rbImage* image;
|
154
|
-
Data_Get_Struct(self, rbImage, image);
|
155
|
-
VALUE exif = Data_Wrap_Struct(cExif, 0, image_leave, image);
|
156
|
-
rb_iv_set(exif, "@image", self);
|
157
|
-
return exif;
|
158
|
-
__END
|
159
|
-
}
|
160
|
-
|
161
|
-
/*
|
162
|
-
* Access to iptc data of image
|
163
|
-
*/
|
164
|
-
static VALUE exiv2_image_iptc(VALUE self) {
|
165
|
-
__BEGIN
|
166
|
-
rbImage* image;
|
167
|
-
Data_Get_Struct(self, rbImage, image);
|
168
|
-
VALUE iptc = Data_Wrap_Struct(cIptc, 0, image_leave, image);
|
169
|
-
rb_iv_set(iptc, "@image", self);
|
170
|
-
return iptc;
|
171
|
-
__END
|
172
|
-
}
|
173
|
-
|
174
|
-
|
175
|
-
/*
|
176
|
-
* Dump thumbnail to file.
|
177
|
-
* @img.thumbnail("my_image")
|
178
|
-
*/
|
179
|
-
static VALUE exiv2_image_thumbnail(VALUE self, VALUE file_name) {
|
180
|
-
__BEGIN
|
181
|
-
Check_Type(file_name, T_STRING);
|
182
|
-
|
183
|
-
rbImage* image;
|
184
|
-
Data_Get_Struct(self, rbImage, image);
|
185
|
-
|
186
|
-
Exiv2::ExifData &exifData = image->image->exifData();
|
187
|
-
exifData.writeThumbnail(STR(file_name));
|
188
|
-
if(rb_block_given_p()) {
|
189
|
-
rb_yield(file_name);
|
190
|
-
}
|
191
|
-
return self;
|
192
|
-
__END
|
193
|
-
}
|
194
|
-
|
195
|
-
/*
|
196
|
-
* Set image thumbnail to contents of passed file
|
197
|
-
* @img.thumbnail = "my_image.jpg"
|
198
|
-
*/
|
199
|
-
static VALUE exiv2_image_thumbnail_set(VALUE self, VALUE file_name) {
|
200
|
-
__BEGIN
|
201
|
-
Check_Type(file_name, T_STRING);
|
202
|
-
|
203
|
-
rbImage* image;
|
204
|
-
Data_Get_Struct(self, rbImage, image);
|
205
|
-
|
206
|
-
Exiv2::ExifData &exifData = image->image->exifData();
|
207
|
-
exifData.setJpegThumbnail(STR(file_name));
|
208
|
-
return self;
|
209
|
-
__END
|
210
|
-
}
|
211
|
-
|
212
|
-
|
213
|
-
void Init_image() {
|
214
|
-
cImage = rb_define_class_under(mExiv2, "Image", rb_cObject);
|
215
|
-
rb_define_alloc_func(cImage, exiv2_image_s_allocate);
|
216
|
-
rb_define_method(cImage, "initialize", VALUEFUNC(exiv2_image_initialize), 1);
|
217
|
-
rb_define_singleton_method(cImage, "load_string", VALUEFUNC(exiv2_image_load_string), 1);
|
218
|
-
|
219
|
-
rb_define_method(cImage, "exif", VALUEFUNC(exiv2_image_exif), 0);
|
220
|
-
rb_define_method(cImage, "Exif", VALUEFUNC(exiv2_image_exif), 0);
|
221
|
-
rb_define_method(cImage, "iptc", VALUEFUNC(exiv2_image_iptc), 0);
|
222
|
-
|
223
|
-
rb_define_method(cImage, "thumbnail", VALUEFUNC(exiv2_image_thumbnail), 1);
|
224
|
-
rb_define_method(cImage, "thumbnail=", VALUEFUNC(exiv2_image_thumbnail_set), 1);
|
225
|
-
|
226
|
-
rb_define_method(cImage, "save", VALUEFUNC(exiv2_image_save), 0);
|
227
|
-
rb_define_method(cImage, "clear", VALUEFUNC(exiv2_image_clear), 0);
|
228
|
-
rb_define_method(cImage, "comment", VALUEFUNC(exiv2_image_get_comment), 0);
|
229
|
-
rb_define_method(cImage, "comment=", VALUEFUNC(exiv2_image_set_comment), 1);
|
230
|
-
}
|
data/ext/iptc.cpp
DELETED
@@ -1,253 +0,0 @@
|
|
1
|
-
#include "exiv2.hpp"
|
2
|
-
|
3
|
-
/*
|
4
|
-
* First, I have to get out type by key. If such key is forbidden, I will refuse to marshall it.
|
5
|
-
* Then, I will cast ruby VALUE to C++ value, according to type_id
|
6
|
-
* then I will just set apropreciated hash entry to this casted value
|
7
|
-
*/
|
8
|
-
static bool marshall_value(Exiv2::IptcData &data, const char* key, VALUE value) {
|
9
|
-
Exiv2::TypeId type_id;
|
10
|
-
try {
|
11
|
-
Exiv2::IptcKey iptcKey(key);
|
12
|
-
type_id = Exiv2::IptcDataSets::dataSetType(iptcKey.tag(), iptcKey.record());
|
13
|
-
}
|
14
|
-
catch(Exiv2::Error& e) {
|
15
|
-
rb_raise(eError, "Cannot set tag %s because it doesn't exists. Look at http://www.exiv2.org/tags.html for list of supported tags", key);
|
16
|
-
}
|
17
|
-
switch(type_id) {
|
18
|
-
case Exiv2::invalidTypeId:
|
19
|
-
{
|
20
|
-
rb_warn("Trying to marshall invalid type id");
|
21
|
-
return Qnil;
|
22
|
-
}
|
23
|
-
|
24
|
-
case Exiv2::unsignedByte:
|
25
|
-
case Exiv2::unsignedShort:
|
26
|
-
case Exiv2::unsignedLong:
|
27
|
-
case Exiv2::signedShort:
|
28
|
-
case Exiv2::signedLong:
|
29
|
-
{
|
30
|
-
data[key] = NUM2INT(value);
|
31
|
-
return true;
|
32
|
-
}
|
33
|
-
|
34
|
-
case Exiv2::asciiString:
|
35
|
-
case Exiv2::string:
|
36
|
-
case Exiv2::undefined:
|
37
|
-
{
|
38
|
-
data[key] = std::string(STR(value));
|
39
|
-
return true;
|
40
|
-
}
|
41
|
-
|
42
|
-
case Exiv2::unsignedRational:
|
43
|
-
case Exiv2::signedRational:
|
44
|
-
{
|
45
|
-
if(rb_respond_to(value, rb_intern("numerator"))) {
|
46
|
-
int numerator = NUM2INT(rb_funcall(value, rb_intern("numerator"), 0));
|
47
|
-
int denominator = NUM2INT(rb_funcall(value, rb_intern("denominator"), 0));
|
48
|
-
data[key] = numerator / denominator;
|
49
|
-
return true;
|
50
|
-
}
|
51
|
-
data[key] = int(NUM2INT(value));
|
52
|
-
return true;
|
53
|
-
}
|
54
|
-
|
55
|
-
case Exiv2::date:
|
56
|
-
{
|
57
|
-
int year = NUM2INT(rb_funcall(value, rb_intern("year"), 0));
|
58
|
-
int month = NUM2INT(rb_funcall(value, rb_intern("month"), 0));
|
59
|
-
int day = NUM2INT(rb_funcall(value, rb_intern("day"), 0));
|
60
|
-
data[key] = Exiv2::DateValue(year, month, day);
|
61
|
-
return true;
|
62
|
-
}
|
63
|
-
case Exiv2::time: {
|
64
|
-
int hour = NUM2INT(rb_funcall(value, rb_intern("hour"), 0));
|
65
|
-
int minute = NUM2INT(rb_funcall(value, rb_intern("min"), 0));
|
66
|
-
int second = NUM2INT(rb_funcall(value, rb_intern("sec"), 0));
|
67
|
-
data[key] = Exiv2::TimeValue(hour, minute, second);
|
68
|
-
return true;
|
69
|
-
}
|
70
|
-
|
71
|
-
case Exiv2::invalid6:
|
72
|
-
case Exiv2::comment:
|
73
|
-
case Exiv2::directory:
|
74
|
-
case Exiv2::lastTypeId:
|
75
|
-
{
|
76
|
-
data[key] = std::string(STR(value));
|
77
|
-
return true;
|
78
|
-
}
|
79
|
-
}
|
80
|
-
return false;
|
81
|
-
}
|
82
|
-
|
83
|
-
|
84
|
-
/*
|
85
|
-
* Access iptc tag by name
|
86
|
-
*
|
87
|
-
* <code>Exiv2::Image.new("test/data/smiley.jpg").iptc["Iptc.Application2.ObjectName"] => "GreeenDude"</code>
|
88
|
-
*/
|
89
|
-
static VALUE exiv2_iptc_get(VALUE self, VALUE key) {
|
90
|
-
__BEGIN
|
91
|
-
rbImage* image;
|
92
|
-
Data_Get_Struct(self, rbImage, image);
|
93
|
-
|
94
|
-
VALUE strkey = rb_funcall(key, rb_intern("to_s"), 0);
|
95
|
-
Exiv2::IptcData &iptcData = image->image->iptcData();
|
96
|
-
|
97
|
-
if(iptcData.empty()) {
|
98
|
-
return Qnil;
|
99
|
-
}
|
100
|
-
|
101
|
-
Exiv2::IptcKey iptcKey(STR(strkey));
|
102
|
-
Exiv2::IptcData::const_iterator pos = iptcData.findKey(iptcKey);
|
103
|
-
if (pos == iptcData.end()) {
|
104
|
-
return Qnil;
|
105
|
-
}
|
106
|
-
|
107
|
-
return unmarshall_value(pos->value());
|
108
|
-
__NIL_END
|
109
|
-
}
|
110
|
-
|
111
|
-
#if 1
|
112
|
-
/*
|
113
|
-
* @iptc["Iptc.Application2.ObjectName"] = "GreeenDude"
|
114
|
-
* [] — is a universal accessor
|
115
|
-
*/
|
116
|
-
static VALUE exiv2_iptc_set(VALUE self, VALUE key, VALUE value) {
|
117
|
-
__BEGIN
|
118
|
-
rbImage* image;
|
119
|
-
Data_Get_Struct(self, rbImage, image);
|
120
|
-
|
121
|
-
VALUE strkey = rb_funcall(key, rb_intern("to_s"), 0);
|
122
|
-
|
123
|
-
if(!marshall_value(image->image->iptcData(), STR(strkey), value)) {
|
124
|
-
THROW("Couldn't write %s", STR(strkey));
|
125
|
-
}
|
126
|
-
|
127
|
-
image->dirty = true;
|
128
|
-
return value;
|
129
|
-
__NIL_END
|
130
|
-
|
131
|
-
}
|
132
|
-
#endif
|
133
|
-
|
134
|
-
/*
|
135
|
-
* Iterates through all iptc tags in image
|
136
|
-
*/
|
137
|
-
static VALUE exiv2_iptc_each(int argc, VALUE *argv, VALUE self) {
|
138
|
-
__BEGIN
|
139
|
-
rbImage* image;
|
140
|
-
Data_Get_Struct(self, rbImage, image);
|
141
|
-
|
142
|
-
VALUE prefix;
|
143
|
-
rb_scan_args(argc, argv, "01", &prefix);
|
144
|
-
|
145
|
-
Exiv2::IptcData &iptcData = image->image->iptcData();
|
146
|
-
if(iptcData.empty()) {
|
147
|
-
return Qnil;
|
148
|
-
}
|
149
|
-
|
150
|
-
Exiv2::IptcData::const_iterator end = iptcData.end();
|
151
|
-
for(Exiv2::IptcData::const_iterator i = iptcData.begin(); i != end; ++i) {
|
152
|
-
VALUE key = rb_str_new(i->key().c_str(), i->key().length());
|
153
|
-
VALUE val = unmarshall_value(i->value());
|
154
|
-
if(prefix != Qnil && INT2FIX(0) != rb_funcall(key, rb_intern("index"), 1, prefix)) {
|
155
|
-
continue;
|
156
|
-
}
|
157
|
-
rb_yield(rb_ary_new3(2, key, val));
|
158
|
-
}
|
159
|
-
return self;
|
160
|
-
__END
|
161
|
-
}
|
162
|
-
|
163
|
-
#if 1
|
164
|
-
/*
|
165
|
-
* Delete iptc value by it's name
|
166
|
-
*/
|
167
|
-
static VALUE exiv2_iptc_delete(VALUE self, VALUE key) {
|
168
|
-
__BEGIN
|
169
|
-
rbImage* image;
|
170
|
-
Data_Get_Struct(self, rbImage, image);
|
171
|
-
|
172
|
-
VALUE strkey = rb_funcall(key, rb_intern("to_s"), 0);
|
173
|
-
Exiv2::IptcData &iptcData = image->image->iptcData();
|
174
|
-
|
175
|
-
if(iptcData.empty()) {
|
176
|
-
return Qnil;
|
177
|
-
}
|
178
|
-
|
179
|
-
Exiv2::IptcKey iptcKey(STR(strkey));
|
180
|
-
Exiv2::IptcData::iterator pos = iptcData.findKey(iptcKey);
|
181
|
-
if (pos == iptcData.end()) {
|
182
|
-
return Qnil;
|
183
|
-
}
|
184
|
-
|
185
|
-
std::string v = pos->toString();
|
186
|
-
iptcData.erase(pos);
|
187
|
-
return rb_str_new(v.c_str(), v.length());
|
188
|
-
__NIL_END
|
189
|
-
}
|
190
|
-
#endif
|
191
|
-
|
192
|
-
/*
|
193
|
-
* Clear all iptc data in image
|
194
|
-
*/
|
195
|
-
static VALUE exiv2_iptc_clear(VALUE self) {
|
196
|
-
__BEGIN
|
197
|
-
rbImage* image;
|
198
|
-
Data_Get_Struct(self, rbImage, image);
|
199
|
-
|
200
|
-
Exiv2::IptcData &iptcData = image->image->iptcData();
|
201
|
-
|
202
|
-
if(iptcData.empty()) {
|
203
|
-
return Qnil;
|
204
|
-
}
|
205
|
-
iptcData.clear();
|
206
|
-
return self;
|
207
|
-
__END
|
208
|
-
}
|
209
|
-
|
210
|
-
/*
|
211
|
-
* Count of iptc tags in image
|
212
|
-
*/
|
213
|
-
static VALUE exiv2_iptc_count(VALUE self) {
|
214
|
-
__BEGIN
|
215
|
-
rbImage* image;
|
216
|
-
Data_Get_Struct(self, rbImage, image);
|
217
|
-
|
218
|
-
Exiv2::IptcData &iptcData = image->image->iptcData();
|
219
|
-
|
220
|
-
return INT2FIX(iptcData.count());
|
221
|
-
__END
|
222
|
-
}
|
223
|
-
|
224
|
-
/*
|
225
|
-
* Predicate method. Is iptc empty?
|
226
|
-
*/
|
227
|
-
static VALUE exiv2_iptc_empty(VALUE self) {
|
228
|
-
__BEGIN
|
229
|
-
rbImage* image;
|
230
|
-
Data_Get_Struct(self, rbImage, image);
|
231
|
-
|
232
|
-
Exiv2::IptcData &iptcData = image->image->iptcData();
|
233
|
-
|
234
|
-
return iptcData.empty() ? Qtrue : Qfalse;
|
235
|
-
__NIL_END
|
236
|
-
}
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
void Init_iptc() {
|
243
|
-
cIptc = rb_define_class_under(mExiv2, "Iptc", rb_cObject);
|
244
|
-
rb_define_method(cIptc, "each", VALUEFUNC(exiv2_iptc_each), -1);
|
245
|
-
rb_define_method(cIptc, "[]", VALUEFUNC(exiv2_iptc_get), 1);
|
246
|
-
#if 1
|
247
|
-
rb_define_method(cIptc, "[]=", VALUEFUNC(exiv2_iptc_set), 2);
|
248
|
-
rb_define_method(cIptc, "delete", VALUEFUNC(exiv2_iptc_delete), 1);
|
249
|
-
#endif
|
250
|
-
rb_define_method(cIptc, "clear", VALUEFUNC(exiv2_iptc_clear), 0);
|
251
|
-
rb_define_method(cIptc, "count", VALUEFUNC(exiv2_iptc_count), 0);
|
252
|
-
rb_define_method(cIptc, "empty?", VALUEFUNC(exiv2_iptc_empty), 0);
|
253
|
-
}
|