ruby-exiv2 0.4 → 0.5

Sign up to get free protection for your applications and to get access to all the features.
data/lib/Makefile CHANGED
@@ -4,7 +4,7 @@ SHELL = /bin/sh
4
4
  #### Start of system configuration section. ####
5
5
 
6
6
  srcdir = .
7
- topdir = /opt/local/lib/ruby/1.8/powerpc-darwin8.8.0
7
+ topdir = /opt/local/lib/ruby/1.8/i686-darwin8.8.3
8
8
  hdrdir = $(topdir)
9
9
  VPATH = $(srcdir):$(topdir):$(hdrdir)
10
10
  prefix = $(DESTDIR)/opt/local
@@ -30,7 +30,7 @@ vendorlibdir = $(vendordir)/$(ruby_version)
30
30
  sitelibdir = $(sitedir)/$(ruby_version)
31
31
  libexecdir = $(exec_prefix)/libexec
32
32
 
33
- CC = gcc
33
+ CC = g++ -c
34
34
  LIBRUBY = $(LIBRUBY_SO)
35
35
  LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
36
36
  LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME)
@@ -38,19 +38,19 @@ LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static
38
38
 
39
39
  RUBY_EXTCONF_H =
40
40
  CFLAGS = -fno-common -O -pipe -I/opt/local/include -fno-common -pipe -fno-common
41
- INCFLAGS = -I. -I. -I/opt/local/lib/ruby/1.8/powerpc-darwin8.8.0 -I.
42
- CPPFLAGS = -O -pipe -I/opt/local/include -Wall -I/usr/local/include/exiv2 -I/usr/include/exiv2
41
+ INCFLAGS = -I. -I. -I/opt/local/lib/ruby/1.8/i686-darwin8.8.3 -I.
42
+ CPPFLAGS = -DHAVE_EXIF_HPP -O -pipe -I/opt/local/include -Wall -I/usr/include/exiv2 -I/Users/max/Sites/exif/include/exiv2
43
43
  CXXFLAGS = $(CFLAGS)
44
- DLDFLAGS = -L/opt/local/lib -lstdc++
44
+ DLDFLAGS = -L/opt/local/lib -lstdc++ -L/Users/max/Sites/exif/lib
45
45
  LDSHARED = cc -dynamic -bundle -undefined suppress -flat_namespace
46
46
  AR = ar
47
47
  EXEEXT =
48
48
 
49
49
  RUBY_INSTALL_NAME = ruby
50
50
  RUBY_SO_NAME = ruby
51
- arch = powerpc-darwin8.8.0
52
- sitearch = powerpc-darwin8.8.0
53
- vendorarch = powerpc-darwin8.8.0
51
+ arch = i686-darwin8.8.3
52
+ sitearch = i686-darwin8.8.3
53
+ vendorarch = i686-darwin8.8.3
54
54
  ruby_version = 1.8
55
55
  ruby = /opt/local/bin/ruby
56
56
  RUBY = $(ruby)
@@ -76,7 +76,7 @@ extout =
76
76
  extout_prefix =
77
77
  target_prefix =
78
78
  LOCAL_LIBS =
79
- LIBS = $(LIBRUBYARG_SHARED) -lpthread -ldl -lobjc
79
+ LIBS = $(LIBRUBYARG_SHARED) -lexiv2 -lpthread -ldl -lobjc
80
80
  SRCS = exif.cpp exiv2.cpp image.cpp
81
81
  OBJS = exif.o exiv2.o image.o
82
82
  TARGET = exiv2
data/lib/exif.cpp CHANGED
@@ -1,71 +1,7 @@
1
1
  #include "exiv2.hpp"
2
2
 
3
3
 
4
- static VALUE unmarshall_value(const Exiv2::Value& value) {
5
- if(value.count() <= 0) {
6
- rb_warn("Empty value (no entries)");
7
- return Qnil;
8
- }
9
-
10
- Exiv2::TypeId type_id = value.typeId();
11
- switch(type_id) {
12
- case Exiv2::invalidTypeId:
13
- {
14
- rb_warn("Trying to demarshall invalid type id");
15
- return Qnil;
16
- }
17
-
18
- case Exiv2::unsignedByte:
19
- case Exiv2::unsignedShort:
20
- case Exiv2::unsignedLong:
21
- case Exiv2::signedShort:
22
- case Exiv2::signedLong:
23
- {
24
- return INT2NUM(value.toLong());
25
- }
26
-
27
- case Exiv2::asciiString:
28
- case Exiv2::string:
29
- case Exiv2::undefined:
30
- {
31
- VALUE str = rb_str_buf_new(value.size() - 1);
32
- value.copy((Exiv2::byte *)STR(str), Exiv2::littleEndian);
33
- LEN(str) = value.size() - 1;
34
- STR(str)[LEN(str)] = '\0';
35
- LEN(str) = strlen(STR(str));
36
- return str;
37
- }
38
-
39
- case Exiv2::unsignedRational:
40
- case Exiv2::signedRational:
41
- {
42
- Exiv2::Rational r = value.toRational();
43
- ID rational_id = rb_intern("Rational");
44
- if(rb_const_defined(rb_cObject, rational_id)) {
45
- VALUE rational = rb_const_get(rb_cObject, rational_id);
46
- return rb_funcall(rational, rb_intern("new!"), 2, INT2NUM(r.first), INT2NUM(r.second));
47
- }
48
- return INT2NUM(r.first/r.second);
49
- }
50
-
51
- case Exiv2::invalid6:
52
- case Exiv2::date:
53
- case Exiv2::time:
54
- case Exiv2::comment:
55
- case Exiv2::directory:
56
- case Exiv2::lastTypeId:
57
- {
58
- VALUE str = rb_str_buf_new(value.size() - 1);
59
- value.copy((Exiv2::byte *)STR(str), Exiv2::littleEndian);
60
- LEN(str) = value.size() - 1;
61
- char msg[200];
62
- snprintf(msg, sizeof(msg), " !!! %d", type_id);
63
- rb_funcall(str, rb_intern("<<"), 1, rb_str_new2(msg));
64
- return str;
65
- }
66
- }
67
- return Qfalse;
68
- }
4
+
69
5
 
70
6
  /*
71
7
  * Access exif tag by name
@@ -91,76 +27,9 @@ static VALUE exiv2_exif_get(VALUE self, VALUE key) {
91
27
  }
92
28
 
93
29
  return unmarshall_value(pos->value());
94
- //std::string v = pos->toString();
95
- //return rb_str_new(v.c_str(), v.length());
96
30
  __NIL_END
97
31
  }
98
32
 
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::TypeId type_id;
106
- try {
107
- Exiv2::ExifKey exif_key(key);
108
- type_id = Exiv2::ExifTags::tagType(exif_key.tag(), exif_key.ifdId());
109
- }
110
- catch(Exiv2::Error& e) {
111
- 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);
112
- }
113
- switch(type_id) {
114
- case Exiv2::invalidTypeId:
115
- {
116
- rb_warn("Trying to marshall invalid type id");
117
- return Qnil;
118
- }
119
-
120
- case Exiv2::unsignedByte:
121
- case Exiv2::unsignedShort:
122
- case Exiv2::unsignedLong:
123
- case Exiv2::signedShort:
124
- case Exiv2::signedLong:
125
- {
126
- exifData[key] = NUM2INT(value);
127
- return true;
128
- }
129
-
130
- case Exiv2::asciiString:
131
- case Exiv2::string:
132
- case Exiv2::undefined:
133
- {
134
- exifData[key] = std::string(STR(value));
135
- return true;
136
- }
137
-
138
- case Exiv2::unsignedRational:
139
- case Exiv2::signedRational:
140
- {
141
- if(rb_respond_to(value, rb_intern("numerator"))) {
142
- int numerator = NUM2INT(rb_funcall(value, rb_intern("numerator"), 0));
143
- int denominator = NUM2INT(rb_funcall(value, rb_intern("denominator"), 0));
144
- exifData[key] = Exiv2::Rational(numerator, denominator);
145
- return true;
146
- }
147
- exifData[key] = Exiv2::Rational(NUM2INT(value), 1);
148
- return true;
149
- }
150
-
151
- case Exiv2::invalid6:
152
- case Exiv2::date:
153
- case Exiv2::time:
154
- case Exiv2::comment:
155
- case Exiv2::directory:
156
- case Exiv2::lastTypeId:
157
- {
158
- exifData[key] = std::string(STR(value));
159
- return true;
160
- }
161
- }
162
- return false;
163
- }
164
33
 
165
34
 
166
35
  /*
@@ -197,7 +66,7 @@ static VALUE exiv2_exif_each(int argc, VALUE *argv, VALUE self) {
197
66
 
198
67
  Exiv2::ExifData &exifData = image->image->exifData();
199
68
  if(exifData.empty()) {
200
- return self;
69
+ return Qnil;
201
70
  }
202
71
 
203
72
  Exiv2::ExifData::const_iterator end = exifData.end();
@@ -288,36 +157,96 @@ static VALUE exiv2_exif_empty(VALUE self) {
288
157
  }
289
158
 
290
159
 
291
- /*
160
+
292
161
  static void tag_leave(Exiv2::TagInfo* info) {
293
162
 
294
163
  }
295
164
 
296
- static VALUE create_exiv2_tag(VALUE exif, Exiv2::TagInfo* info) {
297
- VALUE tag_info = Data_Wrap_Struct(cTag, 0, tag_leave, info);
298
- rb_iv_set(tag_info, "@exif", exif);
299
- return tag_info;
165
+ static VALUE create_exiv2_tag(Exiv2::TagInfo* info) {
166
+ return Data_Wrap_Struct(cTag, 0, tag_leave, info);
300
167
  }
301
- static VALUE exiv2_exif_tags_each(VALUE self) {
302
- for (int i=0; Exiv2::ifdTagInfo[i].tag_ != 0xffff; ++i) {
303
- rb_yield(create_exiv2_tag(self, Exiv2::ifdTagInfo + i));
304
- }
305
- for (int i=0; Exiv2::exifTagInfo[i].tag_ != 0xffff; ++i) {
306
- rb_yield(create_exiv2_tag(self, Exiv2::exifTagInfo + i));
307
- }
308
- for (int i=0; Exiv2::iopTagInfo[i].tag_ != 0xffff; ++i) {
309
- rb_yield(create_exiv2_tag(self, Exiv2::iopTagInfo + i));
310
- }
311
- for (int i=0; Exiv2::gpsTagInfo[i].tag_ != 0xffff; ++i) {
312
- rb_yield(create_exiv2_tag(self, Exiv2::gpsTagInfo + i));
168
+
169
+ static int iterate_tag_collection(const Exiv2::TagInfo* collection, bool to_yield = true) {
170
+ Exiv2::TagInfo* _collection = const_cast<Exiv2::TagInfo *>(collection);
171
+ int i;
172
+ for (i=0; _collection[i].tag_ != 0xffff; ++i) {
173
+ if(to_yield) {
174
+ rb_yield(create_exiv2_tag(_collection + i));
175
+ }
313
176
  }
177
+ return i;
178
+ }
179
+
180
+ #ifdef HAVE_IFDTAGLIST
181
+ static VALUE exiv2_tags_each(VALUE self) {
182
+ __BEGIN
183
+ iterate_tag_collection(Exiv2::ExifTags::ifdTagList());
184
+ iterate_tag_collection(Exiv2::ExifTags::exifTagList());
185
+ iterate_tag_collection(Exiv2::ExifTags::iopTagList());
186
+ iterate_tag_collection(Exiv2::ExifTags::gpsTagList());
314
187
  return self;
188
+ __END
189
+ }
190
+
191
+
192
+
193
+ static VALUE exiv2_tags_count(VALUE self) {
194
+ __BEGIN
195
+ return INT2NUM(
196
+ iterate_tag_collection(Exiv2::ExifTags::ifdTagList(), false) +
197
+ iterate_tag_collection(Exiv2::ExifTags::exifTagList(), false) +
198
+ iterate_tag_collection(Exiv2::ExifTags::iopTagList(), false) +
199
+ iterate_tag_collection(Exiv2::ExifTags::gpsTagList(), false)
200
+ );
201
+ __END
202
+ }
203
+ #endif /* HAVE_IFDTAGLIST */
204
+
205
+ static VALUE exiv2_tag_name(VALUE self) {
206
+ __BEGIN
207
+ Exiv2::TagInfo* tag;
208
+ Data_Get_Struct(self, Exiv2::TagInfo, tag);
209
+
210
+ return tag->name_ ? rb_str_new2(tag->name_) : Qnil;
211
+ __END
212
+ }
213
+
214
+ static VALUE exiv2_tag_title(VALUE self) {
215
+ __BEGIN
216
+ Exiv2::TagInfo* tag;
217
+ Data_Get_Struct(self, Exiv2::TagInfo, tag);
218
+
219
+ return tag->title_ ? rb_str_new2(tag->title_) : Qnil;
220
+ __END
221
+ }
222
+
223
+ static VALUE exiv2_tag_desc(VALUE self) {
224
+ __BEGIN
225
+ Exiv2::TagInfo* tag;
226
+ Data_Get_Struct(self, Exiv2::TagInfo, tag);
227
+
228
+ return tag->desc_ ? rb_str_new2(tag->desc_) : Qnil;
229
+ __END
230
+ }
231
+
232
+ static VALUE exiv2_tag_section(VALUE self) {
233
+ __BEGIN
234
+ Exiv2::TagInfo* tag;
235
+ Data_Get_Struct(self, Exiv2::TagInfo, tag);
236
+
237
+ return rb_str_new2(Exiv2::ExifTags::sectionName(tag->sectionId_));
238
+ __END
315
239
  }
316
240
 
317
- static VALUE exiv2_iptc_tags_each(VALUE self) {
241
+ static VALUE exiv2_tag_ifd(VALUE self) {
242
+ __BEGIN
243
+ Exiv2::TagInfo* tag;
244
+ Data_Get_Struct(self, Exiv2::TagInfo, tag);
318
245
 
246
+ return rb_str_new2(Exiv2::ExifTags::ifdName(tag->ifdId_));
247
+ __END
319
248
  }
320
- */
249
+
321
250
 
322
251
  void Init_exif() {
323
252
  cExif = rb_define_class_under(mExiv2, "Exif", rb_cObject);
@@ -328,8 +257,17 @@ void Init_exif() {
328
257
  rb_define_method(cExif, "clear", VALUEFUNC(exiv2_exif_clear), 0);
329
258
  rb_define_method(cExif, "count", VALUEFUNC(exiv2_exif_count), 0);
330
259
  rb_define_method(cExif, "empty?", VALUEFUNC(exiv2_exif_empty), 0);
331
- // rb_define_singleton_method(cExif, "exif_tags_each", VALUEFUNC(exiv2_exif_tags_each), 0);
332
260
  // rb_define_singleton_method(cExif, "iptc_tags_each", VALUEFUNC(exiv2_iptc_tags_each), 0);
333
261
 
334
262
  cTag = rb_define_class_under(mExiv2, "Tag", rb_cObject);
263
+ #ifdef HAVE_IFDTAGLIST
264
+ rb_define_singleton_method(cTag, "each", VALUEFUNC(exiv2_tags_each), 0);
265
+ rb_define_singleton_method(cTag, "count", VALUEFUNC(exiv2_tags_count), 0);
266
+ #endif /* HAVE_IFDTAGLIST */
267
+
268
+ rb_define_method(cTag, "ifd", VALUEFUNC(exiv2_tag_ifd), 0);
269
+ rb_define_method(cTag, "section", VALUEFUNC(exiv2_tag_section), 0);
270
+ rb_define_method(cTag, "name", VALUEFUNC(exiv2_tag_name), 0);
271
+ rb_define_method(cTag, "title", VALUEFUNC(exiv2_tag_title), 0);
272
+ rb_define_method(cTag, "desc", VALUEFUNC(exiv2_tag_desc), 0);
335
273
  }
data/lib/exiv2.cpp CHANGED
@@ -58,6 +58,7 @@ void Init_exiv2() {
58
58
 
59
59
  Init_image();
60
60
  Init_exif();
61
+ Init_iptc();
61
62
  //cThumbnail = rb_define_class_under(mExiv2, "Thumbnail", rb_cObject);
62
63
  //rb_define_method(cThumbnail, "extension", VALUEFUNC(exiv2_thumb_ext), 0);
63
64
  //rb_define_method(cThumbnail, "format", VALUEFUNC(exiv2_thumb_format), 0);
data/lib/exiv2.hpp CHANGED
@@ -33,6 +33,7 @@
33
33
  // included header files
34
34
  #include <image.hpp>
35
35
  #include <exif.hpp>
36
+ #include <iptc.hpp>
36
37
 
37
38
 
38
39
  #include <string>
@@ -101,9 +102,12 @@ struct rbImage {
101
102
  Exiv2::Image::AutoPtr image;
102
103
  };
103
104
 
105
+ bool marshall_value(Exiv2::ExifData &exifData, const char* key, VALUE value);
106
+ VALUE unmarshall_value(const Exiv2::Value& value);
104
107
 
105
108
  void Init_image();
106
109
  void Init_exif();
110
+ void Init_iptc();
107
111
 
108
112
 
109
113
  #endif /* EXIV2_HPP_ */
data/lib/extconf.rb CHANGED
@@ -1,15 +1,40 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require "mkmf"
4
- #CONFIG["CXX"] = "g++ -g " + CONFIG['LDSHARED']
5
4
  CONFIG["CPP"] = "g++ -E "
6
- #CONFIG['LDSHARED'] = "g++ -g -dynamic -bundle -undefined suppress -flat_namespace"
5
+ CONFIG["CC"] = "g++ -c "
7
6
 
8
7
 
9
-
10
- $CPPFLAGS << " -Wall -I/usr/local/include/exiv2 -I/usr/include/exiv2 "
11
- $LDFLAGS << " -lstdc++ "
8
+ #
9
+ # -I/usr/local/include/exiv2
10
+ $CPPFLAGS << " -Wall -I/usr/include/exiv2 -I/Users/max/Sites/exif/include/exiv2 "
11
+ $LDFLAGS << " -lstdc++ -L/Users/max/Sites/exif/lib "
12
12
  have_header "exif.hpp"
13
13
  have_library "exiv2", "_ZN5Exiv29MetadatumD0Ev"
14
+
15
+
16
+ ifd_tag_list = "Exiv2::ExifTags::ifdTagList"
17
+ def ifd_tag_list.upcase
18
+ "IFDTAGLIST"
19
+ end
20
+ have_func ifd_tag_list do <<-SRC
21
+ #include <image.hpp>
22
+ #include <exif.hpp>
23
+
24
+
25
+ #include <string>
26
+ #include <vector>
27
+ #include <iostream>
28
+ #include <fstream>
29
+ #include <iomanip>
30
+ #include <cstring>
31
+ #include <cassert>
32
+
33
+ #include <stdarg.h>
34
+ int main(void) {
35
+ Exiv2::ExifTags::ifdTagList();
36
+ }
37
+ SRC
38
+ end
14
39
  create_makefile 'exiv2'
15
40
 
data/lib/image.cpp CHANGED
@@ -48,6 +48,24 @@ static VALUE exiv2_image_initialize(VALUE self, VALUE file) {
48
48
  __END
49
49
  }
50
50
 
51
+ /*
52
+ *
53
+ * Load Exiv2::Image from memory string
54
+ * content = File.open("a.jpg").read
55
+ * img = Exiv2::Image.load_string(content)
56
+ */
57
+ static VALUE exiv2_image_load_string(VALUE self, VALUE string) {
58
+ __BEGIN
59
+ Check_Type(string, T_STRING);
60
+ rbImage* image = new rbImage();
61
+ image->dirty = false;
62
+ VALUE img = Data_Wrap_Struct(self, 0, image_delete, image);
63
+
64
+ image->image = Exiv2::ImageFactory::open(CBSTR(string), LEN(string));
65
+ return img;
66
+ __END
67
+ }
68
+
51
69
 
52
70
  static void image_real_save(rbImage* image) {
53
71
  if(image->dirty) {
@@ -127,11 +145,24 @@ static VALUE exiv2_image_exif(VALUE self) {
127
145
  rbImage* image;
128
146
  Data_Get_Struct(self, rbImage, image);
129
147
  VALUE exif = Data_Wrap_Struct(cExif, 0, image_leave, image);
130
- rb_iv_set(self, "image", self);
148
+ rb_iv_set(exif, "@image", self);
131
149
  return exif;
132
150
  __END
133
151
  }
134
152
 
153
+ /*
154
+ * Access to iptc data of image
155
+ */
156
+ static VALUE exiv2_image_iptc(VALUE self) {
157
+ __BEGIN
158
+ rbImage* image;
159
+ Data_Get_Struct(self, rbImage, image);
160
+ VALUE iptc = Data_Wrap_Struct(cIptc, 0, image_leave, image);
161
+ rb_iv_set(iptc, "@image", self);
162
+ return iptc;
163
+ __END
164
+ }
165
+
135
166
 
136
167
  /*
137
168
  * Dump thumbnail to file.
@@ -175,7 +206,10 @@ void Init_image() {
175
206
  cImage = rb_define_class_under(mExiv2, "Image", rb_cObject);
176
207
  rb_define_alloc_func(cImage, exiv2_image_s_allocate);
177
208
  rb_define_method(cImage, "initialize", VALUEFUNC(exiv2_image_initialize), 1);
209
+ rb_define_singleton_method(cImage, "load_string", VALUEFUNC(exiv2_image_load_string), 1);
210
+
178
211
  rb_define_method(cImage, "exif", VALUEFUNC(exiv2_image_exif), 0);
212
+ rb_define_method(cImage, "iptc", VALUEFUNC(exiv2_image_iptc), 0);
179
213
 
180
214
  rb_define_method(cImage, "thumbnail", VALUEFUNC(exiv2_image_thumbnail), 1);
181
215
  rb_define_method(cImage, "thumbnail=", VALUEFUNC(exiv2_image_thumbnail_set), 1);
data/lib/iptc.cpp ADDED
@@ -0,0 +1,175 @@
1
+ #include "exiv2.hpp"
2
+
3
+
4
+
5
+ /*
6
+ * Access iptc tag by name
7
+ *
8
+ * <code>Exiv2::Image.new("test/data/smiley.jpg").iptc["Iptc.Application2.ObjectName"] => "GreeenDude"</code>
9
+ */
10
+ static VALUE exiv2_iptc_get(VALUE self, VALUE key) {
11
+ __BEGIN
12
+ rbImage* image;
13
+ Data_Get_Struct(self, rbImage, image);
14
+
15
+ VALUE strkey = rb_funcall(key, rb_intern("to_s"), 0);
16
+ Exiv2::IptcData &iptcData = image->image->iptcData();
17
+
18
+ if(iptcData.empty()) {
19
+ return Qnil;
20
+ }
21
+
22
+ Exiv2::IptcKey iptcKey(STR(strkey));
23
+ Exiv2::IptcData::const_iterator pos = iptcData.findKey(iptcKey);
24
+ if (pos == iptcData.end()) {
25
+ return Qnil;
26
+ }
27
+
28
+ return unmarshall_value(pos->value());
29
+ __NIL_END
30
+ }
31
+
32
+ #if 0
33
+ /*
34
+ * @iptc["Iptc.Application2.ObjectName"] = "GreeenDude"
35
+ * [] — is a universal accessor
36
+ */
37
+ static VALUE exiv2_iptc_set(VALUE self, VALUE key, VALUE value) {
38
+ __BEGIN
39
+ rbImage* image;
40
+ Data_Get_Struct(self, rbImage, image);
41
+
42
+ VALUE strkey = rb_funcall(key, rb_intern("to_s"), 0);
43
+ Exiv2::IptcData &iptcData = image->image->iptcData();
44
+
45
+ if(!marshall_value(iptcData, STR(strkey), value)) {
46
+ THROW("Couldn't write %s", STR(strkey));
47
+ }
48
+
49
+ image->dirty = true;
50
+ return value;
51
+ __NIL_END
52
+ }
53
+ #endif
54
+
55
+ /*
56
+ * Iterates through all iptc tags in image
57
+ */
58
+ static VALUE exiv2_iptc_each(int argc, VALUE *argv, VALUE self) {
59
+ __BEGIN
60
+ rbImage* image;
61
+ Data_Get_Struct(self, rbImage, image);
62
+
63
+ VALUE prefix;
64
+ rb_scan_args(argc, argv, "01", &prefix);
65
+
66
+ Exiv2::IptcData &iptcData = image->image->iptcData();
67
+ if(iptcData.empty()) {
68
+ return Qnil;
69
+ }
70
+
71
+ Exiv2::IptcData::const_iterator end = iptcData.end();
72
+ for(Exiv2::IptcData::const_iterator i = iptcData.begin(); i != end; ++i) {
73
+ VALUE key = rb_str_new(i->key().c_str(), i->key().length());
74
+ VALUE val = unmarshall_value(i->value());
75
+ //VALUE val = rb_str_new(i->toString().c_str(), i->toString().length());
76
+ if(prefix != Qnil && INT2FIX(0) != rb_funcall(key, rb_intern("index"), 1, prefix)) {
77
+ continue;
78
+ }
79
+ rb_yield(rb_ary_new3(2, key, val));
80
+ }
81
+ return self;
82
+ __END
83
+ }
84
+
85
+ #if 0
86
+ /*
87
+ * Delete iptc value by it's name
88
+ */
89
+ static VALUE exiv2_iptc_delete(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::iterator pos = iptcData.findKey(iptcKey);
103
+ if (pos == iptcData.end()) {
104
+ return Qnil;
105
+ }
106
+
107
+ std::string v = pos->toString();
108
+ iptcData.erase(pos);
109
+ return rb_str_new(v.c_str(), v.length());
110
+ __NIL_END
111
+ }
112
+ #endif
113
+
114
+ /*
115
+ * Clear all iptc data in image
116
+ */
117
+ static VALUE exiv2_iptc_clear(VALUE self) {
118
+ __BEGIN
119
+ rbImage* image;
120
+ Data_Get_Struct(self, rbImage, image);
121
+
122
+ Exiv2::IptcData &iptcData = image->image->iptcData();
123
+
124
+ if(iptcData.empty()) {
125
+ return Qnil;
126
+ }
127
+ iptcData.clear();
128
+ return self;
129
+ __END
130
+ }
131
+
132
+ /*
133
+ * Count of iptc tags in image
134
+ */
135
+ static VALUE exiv2_iptc_count(VALUE self) {
136
+ __BEGIN
137
+ rbImage* image;
138
+ Data_Get_Struct(self, rbImage, image);
139
+
140
+ Exiv2::IptcData &iptcData = image->image->iptcData();
141
+
142
+ return INT2FIX(iptcData.count());
143
+ __END
144
+ }
145
+
146
+ /*
147
+ * Predicate method. Is iptc empty?
148
+ */
149
+ static VALUE exiv2_iptc_empty(VALUE self) {
150
+ __BEGIN
151
+ rbImage* image;
152
+ Data_Get_Struct(self, rbImage, image);
153
+
154
+ Exiv2::IptcData &iptcData = image->image->iptcData();
155
+
156
+ return iptcData.empty() ? Qtrue : Qfalse;
157
+ __NIL_END
158
+ }
159
+
160
+
161
+
162
+
163
+
164
+ void Init_iptc() {
165
+ cIptc = rb_define_class_under(mExiv2, "Iptc", rb_cObject);
166
+ rb_define_method(cIptc, "each", VALUEFUNC(exiv2_iptc_each), -1);
167
+ rb_define_method(cIptc, "[]", VALUEFUNC(exiv2_iptc_get), 1);
168
+ #if 0
169
+ rb_define_method(cIptc, "[]=", VALUEFUNC(exiv2_iptc_set), 2);
170
+ rb_define_method(cIptc, "delete", VALUEFUNC(exiv2_iptc_delete), 1);
171
+ #endif
172
+ rb_define_method(cIptc, "clear", VALUEFUNC(exiv2_iptc_clear), 0);
173
+ rb_define_method(cIptc, "count", VALUEFUNC(exiv2_iptc_count), 0);
174
+ rb_define_method(cIptc, "empty?", VALUEFUNC(exiv2_iptc_empty), 0);
175
+ }
data/lib/marshall.cpp ADDED
@@ -0,0 +1,170 @@
1
+ #include "exiv2.hpp"
2
+
3
+
4
+ typedef VALUE (unmarshaller)(const Exiv2::Value& value, long pos = 0);
5
+
6
+ static VALUE unmarshall_long_value(const Exiv2::Value& value, long pos = 0) {
7
+ return INT2NUM(value.toLong(pos));
8
+ }
9
+
10
+
11
+ static VALUE unmarshall_rational_value(const Exiv2::Value& value, long pos = 0) {
12
+ Exiv2::Rational r = value.toRational(pos);
13
+ ID rational_id = rb_intern("Rational");
14
+ if(rb_const_defined(rb_cObject, rational_id)) {
15
+ VALUE rational = rb_const_get(rb_cObject, rational_id);
16
+ return rb_funcall(rational, rb_intern("new!"), 2, INT2NUM(r.first), INT2NUM(r.second));
17
+ }
18
+ return INT2NUM(r.first/r.second);
19
+
20
+ }
21
+
22
+
23
+ static VALUE unmarshall_multiple_values(const Exiv2::Value& value, unmarshaller f) {
24
+ if(value.count() <= 0) {
25
+ rb_warn("Empty value (no entries)");
26
+ return Qnil;
27
+ }
28
+
29
+
30
+ if(value.count() == 1) {
31
+ return f(value);
32
+ }
33
+
34
+ VALUE retval = rb_ary_new2(value.count());
35
+ for(int i = 0; i < value.count(); i++) {
36
+ rb_ary_store(retval, i, f(value, i));
37
+ }
38
+ return retval;
39
+
40
+ }
41
+
42
+
43
+
44
+
45
+ VALUE unmarshall_value(const Exiv2::Value& value) {
46
+ Exiv2::TypeId type_id = value.typeId();
47
+
48
+
49
+ switch(type_id) {
50
+ case Exiv2::invalidTypeId:
51
+ {
52
+ rb_warn("Trying to demarshall invalid type id");
53
+ return Qnil;
54
+ }
55
+
56
+ case Exiv2::unsignedByte:
57
+ case Exiv2::unsignedShort:
58
+ case Exiv2::unsignedLong:
59
+ case Exiv2::signedShort:
60
+ case Exiv2::signedLong:
61
+ {
62
+ return unmarshall_multiple_values(value, unmarshall_long_value);
63
+ }
64
+
65
+ case Exiv2::asciiString:
66
+ case Exiv2::string:
67
+ case Exiv2::undefined:
68
+ {
69
+ std::string str_value = value.toString();
70
+ return rb_str_new(str_value.c_str(), str_value.length());
71
+ }
72
+
73
+ case Exiv2::unsignedRational:
74
+ case Exiv2::signedRational:
75
+ {
76
+ return unmarshall_multiple_values(value, unmarshall_rational_value);
77
+
78
+ Exiv2::Rational r = value.toRational();
79
+ ID rational_id = rb_intern("Rational");
80
+ if(rb_const_defined(rb_cObject, rational_id)) {
81
+ VALUE rational = rb_const_get(rb_cObject, rational_id);
82
+ return rb_funcall(rational, rb_intern("new!"), 2, INT2NUM(r.first), INT2NUM(r.second));
83
+ }
84
+ return INT2NUM(r.first/r.second);
85
+ }
86
+
87
+ case Exiv2::invalid6:
88
+ case Exiv2::date:
89
+ case Exiv2::time:
90
+ case Exiv2::comment:
91
+ case Exiv2::directory:
92
+ case Exiv2::lastTypeId:
93
+ {
94
+ VALUE str = rb_str_buf_new(value.size() - 1);
95
+ value.copy((Exiv2::byte *)STR(str), Exiv2::littleEndian);
96
+ LEN(str) = value.size() - 1;
97
+ char msg[200];
98
+ snprintf(msg, sizeof(msg), " !!! %d", type_id);
99
+ rb_funcall(str, rb_intern("<<"), 1, rb_str_new2(msg));
100
+ return str;
101
+ }
102
+ }
103
+ return Qfalse;
104
+ }
105
+
106
+ /*
107
+ * First, I have to get out type by key. If such key is forbidden, I will refuse to marshall it.
108
+ * Then, I will cast ruby VALUE to C++ value, according to type_id
109
+ * then I will just set apropreciated hash entry to this casted value
110
+ */
111
+ bool marshall_value(Exiv2::ExifData &exifData, const char* key, VALUE value) {
112
+ Exiv2::TypeId type_id;
113
+ try {
114
+ Exiv2::ExifKey exif_key(key);
115
+ type_id = Exiv2::ExifTags::tagType(exif_key.tag(), exif_key.ifdId());
116
+ }
117
+ catch(Exiv2::Error& e) {
118
+ 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);
119
+ }
120
+ switch(type_id) {
121
+ case Exiv2::invalidTypeId:
122
+ {
123
+ rb_warn("Trying to marshall invalid type id");
124
+ return Qnil;
125
+ }
126
+
127
+ case Exiv2::unsignedByte:
128
+ case Exiv2::unsignedShort:
129
+ case Exiv2::unsignedLong:
130
+ case Exiv2::signedShort:
131
+ case Exiv2::signedLong:
132
+ {
133
+ exifData[key] = NUM2INT(value);
134
+ return true;
135
+ }
136
+
137
+ case Exiv2::asciiString:
138
+ case Exiv2::string:
139
+ case Exiv2::undefined:
140
+ {
141
+ exifData[key] = std::string(STR(value));
142
+ return true;
143
+ }
144
+
145
+ case Exiv2::unsignedRational:
146
+ case Exiv2::signedRational:
147
+ {
148
+ if(rb_respond_to(value, rb_intern("numerator"))) {
149
+ int numerator = NUM2INT(rb_funcall(value, rb_intern("numerator"), 0));
150
+ int denominator = NUM2INT(rb_funcall(value, rb_intern("denominator"), 0));
151
+ exifData[key] = Exiv2::Rational(numerator, denominator);
152
+ return true;
153
+ }
154
+ exifData[key] = Exiv2::Rational(NUM2INT(value), 1);
155
+ return true;
156
+ }
157
+
158
+ case Exiv2::invalid6:
159
+ case Exiv2::date:
160
+ case Exiv2::time:
161
+ case Exiv2::comment:
162
+ case Exiv2::directory:
163
+ case Exiv2::lastTypeId:
164
+ {
165
+ exifData[key] = std::string(STR(value));
166
+ return true;
167
+ }
168
+ }
169
+ return false;
170
+ }
Binary file
Binary file
data/test/image.rb CHANGED
@@ -129,10 +129,55 @@ class ImageTest < Test::Unit::TestCase
129
129
  end
130
130
  end
131
131
 
132
+ def test_read_undefined
133
+ open_test_file "exiv2-fujifilm-finepix-s2pro.jpg" do |filename|
134
+ assert @img = Exiv2::Image.new(filename)
135
+ assert_equal "48 49 48 48 ", @img.exif["Exif.Iop.InteroperabilityVersion"]
136
+ end
137
+ end
138
+
139
+ def test_read_ascii
140
+ open_test_file "exiv2-fujifilm-finepix-s2pro.jpg" do |filename|
141
+ assert @img = Exiv2::Image.new(filename)
142
+ assert_equal "R98", @img.exif["Exif.Iop.InteroperabilityIndex"]
143
+ end
144
+ end
145
+
132
146
  def __test_thumbnail
133
147
  open_test_file "exiv2-fujifilm-finepix-s2pro.jpg" do |filename|
134
148
  assert @img = Exiv2::Image.new(filename)
135
149
 
136
150
  end
137
151
  end
152
+
153
+ def test_read_multiple_rationals
154
+ open_test_file "gps-test.jpg" do |filename|
155
+ assert @img = Exiv2::Image.new(filename)
156
+ require 'rational'
157
+ assert_equal [Rational.new!(41, 1), Rational.new!(53, 1), Rational.new!(4091, 100)], @img.exif["Exif.GPSInfo.GPSLatitude"]
158
+ assert_equal [Rational.new!(12, 1), Rational.new!(28, 1), Rational.new!(5996, 100)], @img.exif["Exif.GPSInfo.GPSLongitude"]
159
+ end
160
+ end
161
+
162
+ def test_tag_access
163
+ return unless Exiv2::Tag.respond_to?(:count)
164
+ assert_equal 139, Exiv2::Tag.count
165
+ exif_tag = nil
166
+ Exiv2::Tag.each do |tag|
167
+ exif_tag = tag
168
+ break
169
+ end
170
+ assert_equal "IFD0", exif_tag.ifd
171
+ assert_equal "ImageStructure", exif_tag.section
172
+ assert_equal "NewSubfileType", exif_tag.name
173
+ assert_equal "New Subfile Type", exif_tag.title
174
+ assert_equal "A general indication of the kind of data contained in this subfile.", exif_tag.desc
175
+ end
176
+
177
+ def test_iptc_get
178
+ open_test_file "smiley1.jpg" do |filename|
179
+ assert @img = Exiv2::Image.new(filename)
180
+ assert_equal "Seattle", @img.iptc["Iptc.Application2.City"]
181
+ end
182
+ end
138
183
  end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: ruby-exiv2
5
5
  version: !ruby/object:Gem::Version
6
- version: "0.4"
7
- date: 2006-11-09 00:00:00 +03:00
6
+ version: "0.5"
7
+ date: 2006-11-20 00:00:00 +03:00
8
8
  summary: Exiv2 (exif image tags handling) library driver
9
9
  require_paths:
10
10
  - lib
@@ -12,7 +12,7 @@ email: max@maxidoors.ru
12
12
  homepage: http://maxidoors.ru/
13
13
  rubyforge_project: ruby-exiv2
14
14
  description:
15
- autorequire: intersys
15
+ autorequire:
16
16
  default_executable:
17
17
  bindir: bin
18
18
  has_rdoc: true
@@ -32,12 +32,16 @@ files:
32
32
  - test/data
33
33
  - test/image.rb
34
34
  - test/data/exiv2-fujifilm-finepix-s2pro.jpg
35
+ - test/data/gps-test.jpg
36
+ - test/data/smiley1.jpg
35
37
  - lib/exif.cpp
36
38
  - lib/exiv2.cpp
37
39
  - lib/exiv2.hpp
38
40
  - lib/extconf.rb
39
41
  - lib/image.cpp
42
+ - lib/iptc.cpp
40
43
  - lib/Makefile
44
+ - lib/marshall.cpp
41
45
  - README
42
46
  test_files: []
43
47