ruby-exiv2 0.4 → 0.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/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