ruby-exiv2 1.3 → 1.5

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -2,6 +2,7 @@ Library for handling exif image tags.
2
2
 
3
3
  Basic usage:
4
4
 
5
+ > gem install RubyInline
5
6
  > gem install ruby-exiv2
6
7
  > irb -r rubygems
7
8
 
data/Rakefile CHANGED
@@ -6,17 +6,11 @@ require 'rake/packagetask'
6
6
  require 'rake/contrib/rubyforgepublisher'
7
7
 
8
8
  PKG_NAME = "ruby-exiv2"
9
- PKG_VERSION = "1.3"
9
+ PKG_VERSION = "1.5"
10
10
  PKG_AUTHOR = "Max Lapshin"
11
11
  PKG_EMAIL = "max@maxidoors.ru"
12
- PKG_HOMEPAGE = "http://maxidoors.ru/"
12
+ PKG_HOMEPAGE = "http://github.com/maxlapshin/exiv2"
13
13
  PKG_SUMMARY = "Exiv2 (exif image tags handling) library driver"
14
- PKG_SVN = "http://svn.maxidoors.ru/ruby-exiv2"
15
- PKG_RDOC_OPTS = ['--main=README',
16
- '--line-numbers',
17
- '--webcvs='+PKG_SVN,
18
- '--charset=utf-8',
19
- '--promiscuous']
20
14
 
21
15
 
22
16
  spec = Gem::Specification.new do |s|
@@ -29,19 +23,16 @@ spec = Gem::Specification.new do |s|
29
23
  s.summary = PKG_SUMMARY
30
24
  s.require_path = "lib"
31
25
  s.rubyforge_project = PKG_NAME
32
- s.files = %w(README Rakefile setup.rb init.rb) +
26
+ s.files = %w(README Rakefile init.rb) +
33
27
  Dir.glob("{test}/**/*") +
34
- Dir.glob("ext/**/*.{h,cpp,rb,hpp}") +
35
- Dir.glob("lib/**/*.rb")
28
+ Dir.glob("lib/**/*.{rb,cpp,hpp}")
36
29
  s.test_files = FileList["{test}/**/*.rb"].to_a
37
30
  s.has_rdoc = true
38
31
  s.extra_rdoc_files = ["README"]
39
- s.rdoc_options = PKG_RDOC_OPTS
40
- s.extensions << 'ext/extconf.rb'
41
32
  end
42
33
 
43
34
  Rake::GemPackageTask.new(spec) do |pkg|
44
- pkg.need_tar = true
35
+ pkg.need_tar = false
45
36
  end
46
37
 
47
38
  task :default => [ :test ]
@@ -77,7 +68,6 @@ Rake::RDocTask.new("doc") do |rdoc|
77
68
  rdoc.rdoc_files.include('README')
78
69
  # rdoc.rdoc_files.include('CHANGELOG')
79
70
  # rdoc.rdoc_files.include('TODO')
80
- rdoc.options = PKG_RDOC_OPTS
81
71
  rdoc.rdoc_files.include "ruby-exiv2.cpp"
82
72
  end
83
73
 
@@ -109,18 +99,4 @@ task :push_docs do
109
99
  ].each { |p| p.upload }
110
100
  end
111
101
 
112
- desc "Build binary driver"
113
- task :build do
114
- puts `cd lib; [ -e Makefile ] || ruby extconf.rb; make`
115
- end
116
-
117
- desc "Rebuild binary driver"
118
- task :rebuild do
119
- puts `cd lib; ruby extconf.rb; make clean all`
120
- end
121
102
 
122
- desc "Mark files in SVN"
123
- task :release => [:clobber, :package] do
124
- svn_aware_revision = 'r_' + PKG_VERSION.gsub(/-|\./, '_')
125
- puts `svn copy #{PKG_SVN}/trunk #{PKG_SVN}/tags/#{svn_aware_revision} -m "release #{svn_aware_revision}"`
126
- end
@@ -89,7 +89,7 @@ void rb_exiv2_throw(const char* file, long unsigned int line, const char *fmt, .
89
89
  #if defined(__cplusplus)
90
90
  extern "C" {
91
91
  #endif
92
- void Init_exiv2(void);
92
+ //void Init_exiv2(void);
93
93
  extern VALUE mExiv2, cImage, cExif, cTag, cIptc, eError;
94
94
 
95
95
  #if defined(__cplusplus)
@@ -105,9 +105,9 @@ struct rbImage {
105
105
  VALUE unmarshall_value(const Exiv2::Value& value);
106
106
 
107
107
 
108
- void Init_image();
109
- void Init_exif();
110
- void Init_iptc();
108
+ //void Init_image();
109
+ //void Init_exif();
110
+ //void Init_iptc();
111
111
 
112
112
 
113
113
  #endif /* EXIV2_HPP_ */
@@ -1,38 +1,32 @@
1
- begin
2
- require File.dirname(__FILE__)+'/exiv2_bin'
3
- rescue LoadError
4
- require File.dirname(__FILE__)+'/../ext/exiv2_bin'
5
- end
6
1
  require 'enumerator'
7
2
  require 'rubygems'
3
+ require 'inline'
8
4
  require 'active_support'
5
+ require 'erb'
9
6
 
10
7
  module Exiv2
11
- #
12
- class Image
13
-
14
- # method [] is used to read exif or iptc data
15
- def [](key)
16
- return exif[key] if key[0...4] == "Exif"
17
- return iptc[key] if key[0...4] == "Iptc"
18
- end
19
-
20
- # method []= is used to set exif or iptc data
21
- def []=(key, value)
22
- return exif[key] = value if key[0...4] == "Exif"
23
- return iptc[key] = value if key[0...4] == "Iptc"
24
- raise Exiv2::Error, "Unknown key for writing: #{key.inspect}"
25
- end
26
-
27
- # clues together Iptc.Application2.DateCreated and Iptc.Application2.TimeCreated if possible
28
- def created_at
29
- date = iptc["Iptc.Application2.DateCreated"]
30
- time = iptc["Iptc.Application2.TimeCreated"]
31
- return date unless time
32
- Time.utc(date.year, date.month, date.day, time.hour, time.min, time.sec)
33
- end
8
+ def self.prepare_builder(builder)
9
+ Config::CONFIG["CPP"] = "g++ -E "
10
+ Config::CONFIG["CC"] = "g++ "
11
+ Config::CONFIG["LDSHARED"].gsub!(/^cc /,"g++ ")
12
+ builder.include "<exiv2.hpp>"
13
+ builder.add_compile_flags "-x c++ -I#{File.dirname(__FILE__)} -I/usr/local/include/exiv2", '-lstdc++ -lexiv2'
14
+ builder.include_ruby_last
34
15
  end
35
16
 
17
+ def self.load(&block)
18
+ ERB.new(File.read(File.dirname(__FILE__)+"/exiv2/" + block.call)).result(block.binding)
19
+ end
20
+ end
21
+
22
+ require 'exiv2/image'
23
+ require 'exiv2/exif'
24
+ require 'exiv2/iptc'
25
+ require 'exiv2/tag'
26
+
27
+ module Exiv2
28
+ class Error < StandardError; end
29
+
36
30
  class SubTagAccess
37
31
  def initialize(class_name, sub_tag, parent)
38
32
  @class_name = class_name.split("::").last
@@ -0,0 +1,19 @@
1
+ module Exiv2
2
+ class Exif
3
+ inline do |builder|
4
+ kind = "Exif"
5
+ Exiv2::prepare_builder(builder)
6
+ builder.prefix(Exiv2::load {"metadata/marshall.cpp"})
7
+ builder.prefix(Exiv2::load {"metadata/unmarshall.cpp"})
8
+ builder.prefix(Exiv2::load {"throw.cpp"})
9
+
10
+ builder.c(Exiv2::load {"metadata/get.cpp"}, {:method_name => "[]"})
11
+ builder.c(Exiv2::load {"metadata/set.cpp"}, {:method_name => "[]="})
12
+ builder.c_raw(Exiv2::load {"metadata/each.cpp"}, {:method_name => "each"})
13
+ builder.c(Exiv2::load {"metadata/delete.cpp"}, {:method_name => "delete"})
14
+ builder.c(Exiv2::load {"metadata/clear.cpp"}, {:method_name => "clear"})
15
+ builder.c(Exiv2::load {"metadata/count.cpp"}, {:method_name => "count"})
16
+ builder.c(Exiv2::load {"metadata/is_empty.cpp"}, {:method_name => "empty?"})
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,205 @@
1
+ module Exiv2
2
+ class Image
3
+ # method [] is used to read exif or iptc data
4
+ def [](key)
5
+ return exif[key] if key[0...4] == "Exif"
6
+ return iptc[key] if key[0...4] == "Iptc"
7
+ end
8
+
9
+ # method []= is used to set exif or iptc data
10
+ def []=(key, value)
11
+ return exif[key] = value if key[0...4] == "Exif"
12
+ return iptc[key] = value if key[0...4] == "Iptc"
13
+ raise Exiv2::Error, "Unknown key for writing: #{key.inspect}"
14
+ end
15
+
16
+ # clues together Iptc.Application2.DateCreated and Iptc.Application2.TimeCreated if possible
17
+ def created_at
18
+ date = iptc["Iptc.Application2.DateCreated"]
19
+ time = iptc["Iptc.Application2.TimeCreated"]
20
+ return date unless time
21
+ Time.utc(date.year, date.month, date.day, time.hour, time.min, time.sec)
22
+ end
23
+
24
+
25
+
26
+
27
+
28
+ inline do |builder|
29
+ Exiv2.prepare_builder(builder)
30
+ builder.prefix <<-PREFIX
31
+ VALUE mExiv2, cImage, cExif, cTag, cIptc, cThumbnail, eError;
32
+
33
+
34
+ static void image_real_save(rbImage* image) {
35
+ if(image->dirty) {
36
+ image->image->writeMetadata();
37
+ image->dirty = false;
38
+ }
39
+ }
40
+
41
+ static void image_leave(rbImage* image) {
42
+ }
43
+
44
+ static void image_delete(rbImage* image) {
45
+ __BEGIN
46
+ image_real_save(image);
47
+ delete image;
48
+ __VOID_END
49
+ }
50
+ PREFIX
51
+
52
+ builder.c_singleton <<-EOF, :method_name => "new"
53
+ static VALUE exiv2_image_alloc_and_initialize(VALUE file) {
54
+ __BEGIN
55
+ rbImage* image = new rbImage();
56
+ VALUE rb_image = Data_Wrap_Struct(self, 0, image_delete, image);
57
+ image->dirty = false;
58
+
59
+
60
+ try {
61
+ if(!strcmp(rb_class2name(rb_class_of(file)), "StringIO")) {
62
+ rb_iv_set(rb_image, "@content", file);
63
+ VALUE string = rb_funcall(file, rb_intern("string"), 0);
64
+ image->image = Exiv2::ImageFactory::open(CBSTR(string), LEN(string));
65
+ } else if(rb_respond_to(file, rb_intern("read"))) {
66
+ VALUE file_content = rb_funcall(file, rb_intern("read"), 0);
67
+ rb_iv_set(rb_image, "@file_content", file_content);
68
+ image->image = Exiv2::ImageFactory::open(CBSTR(file_content), LEN(file_content));
69
+ } else if(TYPE(file) == T_STRING) {
70
+ image->image = Exiv2::ImageFactory::open(CSTR(file));
71
+ }
72
+ image->image->readMetadata();
73
+ }
74
+ catch(const Exiv2::AnyError&) {
75
+ rb_raise(eError, "Cannot open file %s", STR(file));
76
+ }
77
+ return rb_image;
78
+ __END
79
+ }
80
+ EOF
81
+
82
+ builder.c_singleton <<-EOF, :method_name => "load_string"
83
+ static VALUE exiv2_image_load_string(VALUE string) {
84
+ __BEGIN
85
+ Check_Type(string, T_STRING);
86
+ rbImage* image = new rbImage();
87
+ image->dirty = false;
88
+ VALUE img = Data_Wrap_Struct(self, 0, image_delete, image);
89
+
90
+ image->image = Exiv2::ImageFactory::open(CBSTR(string), LEN(string));
91
+ return img;
92
+ __END
93
+ }
94
+ EOF
95
+
96
+ builder.c <<-EOF, :method_name => "save"
97
+ static VALUE exiv2_image_save() {
98
+ __BEGIN
99
+ rbImage* image;
100
+ Data_Get_Struct(self, rbImage, image);
101
+ image_real_save(image);
102
+ return self;
103
+ __END
104
+ }
105
+ EOF
106
+
107
+ builder.c <<-EOF, :method_name => "clear"
108
+ static VALUE exiv2_image_clear() {
109
+ __BEGIN
110
+ rbImage* image;
111
+ Data_Get_Struct(self, rbImage, image);
112
+ image->image->clearMetadata();
113
+ image->dirty = true;
114
+ return self;
115
+ __END
116
+ }
117
+ EOF
118
+
119
+ %w(exif iptc).each do |kind|
120
+ builder.add_to_init "rb_define_method(c, \"#{kind.classify}\", (VALUE(*)(ANYARGS))exiv2_image_#{kind}, 0);"
121
+ builder.c <<-EOF, :method_name => kind
122
+ static VALUE exiv2_image_#{kind}() {
123
+ __BEGIN
124
+ rbImage* image;
125
+ VALUE klass = rb_path2class("Exiv2::#{kind.classify}");
126
+ Data_Get_Struct(self, rbImage, image);
127
+ VALUE reader = Data_Wrap_Struct(klass, 0, image_leave, image);
128
+ rb_iv_set(reader, "@image", self);
129
+ return reader;
130
+ __END
131
+ }
132
+ EOF
133
+ end
134
+
135
+ builder.c <<-EOF, :method_name => "comment"
136
+ static VALUE exiv2_image_get_comment() {
137
+ __BEGIN
138
+ rbImage* image;
139
+ Data_Get_Struct(self, rbImage, image);
140
+ std::string comment = image->image->comment();
141
+ return rb_str_new(comment.c_str(), comment.length());
142
+ __END
143
+ }
144
+ EOF
145
+
146
+ builder.c <<-EOF, :method_name => "comment="
147
+ static VALUE exiv2_image_set_comment(VALUE comment) {
148
+ __BEGIN
149
+ rbImage* image;
150
+ Data_Get_Struct(self, rbImage, image);
151
+ switch(TYPE(comment)) {
152
+ case T_STRING: {
153
+ image->image->setComment(CSTR(comment));
154
+ image->dirty = true;
155
+ break;
156
+ }
157
+ case T_NIL: {
158
+ image->image->clearComment();
159
+ image->dirty = true;
160
+ break;
161
+ }
162
+ default: {
163
+ rb_raise(rb_eStandardError, "Can only set comment to string, or clear it with nil value");
164
+ }
165
+ }
166
+ return comment;
167
+ __END
168
+ }
169
+ EOF
170
+
171
+ builder.c <<-EOF, :method_name => "thumbnail"
172
+ static VALUE exiv2_image_thumbnail(VALUE file_name) {
173
+ __BEGIN
174
+ Check_Type(file_name, T_STRING);
175
+
176
+ rbImage* image;
177
+ Data_Get_Struct(self, rbImage, image);
178
+
179
+ Exiv2::ExifData &exifData = image->image->exifData();
180
+ // exifData.writeThumbnail(STR(file_name));
181
+ if(rb_block_given_p()) {
182
+ rb_yield(file_name);
183
+ }
184
+ return self;
185
+ __END
186
+ }
187
+ EOF
188
+
189
+ builder.c <<-EOF, :method_name => "thumbnail="
190
+ static VALUE exiv2_image_thumbnail_set(VALUE file_name) {
191
+ __BEGIN
192
+ Check_Type(file_name, T_STRING);
193
+
194
+ rbImage* image;
195
+ Data_Get_Struct(self, rbImage, image);
196
+
197
+ Exiv2::ExifData &exifData = image->image->exifData();
198
+ // exifData.setJpegThumbnail(STR(file_name));
199
+ return self;
200
+ __END
201
+ }
202
+ EOF
203
+ end
204
+ end
205
+ end
@@ -0,0 +1,19 @@
1
+ module Exiv2
2
+ class Iptc
3
+ inline do |builder|
4
+ kind = "Iptc"
5
+ Exiv2::prepare_builder(builder)
6
+ builder.prefix(Exiv2::load {"metadata/marshall.cpp"})
7
+ builder.prefix(Exiv2::load {"metadata/unmarshall.cpp"})
8
+ builder.prefix(Exiv2::load {"throw.cpp"})
9
+
10
+ builder.c(Exiv2::load {"metadata/get.cpp"}, {:method_name => "[]"})
11
+ builder.c(Exiv2::load {"metadata/set.cpp"}, {:method_name => "[]="})
12
+ builder.c_raw(Exiv2::load {"metadata/each.cpp"}, {:method_name => "each"})
13
+ builder.c(Exiv2::load {"metadata/delete.cpp"}, {:method_name => "delete"})
14
+ builder.c(Exiv2::load {"metadata/clear.cpp"}, {:method_name => "clear"})
15
+ builder.c(Exiv2::load {"metadata/count.cpp"}, {:method_name => "count"})
16
+ builder.c(Exiv2::load {"metadata/is_empty.cpp"}, {:method_name => "empty?"})
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,14 @@
1
+ static VALUE exiv2_metadata_clear() {
2
+ __BEGIN
3
+ rbImage* image;
4
+ Data_Get_Struct(self, rbImage, image);
5
+
6
+ Exiv2::<%= kind %>Data &data = image->image-><%= kind.downcase %>Data();
7
+
8
+ if(data.empty()) {
9
+ return Qnil;
10
+ }
11
+ data.clear();
12
+ return self;
13
+ __END
14
+ }
@@ -0,0 +1,10 @@
1
+ static VALUE exiv2_metadata_count() {
2
+ __BEGIN
3
+ rbImage* image;
4
+ Data_Get_Struct(self, rbImage, image);
5
+
6
+ Exiv2::<%= kind %>Data &data = image->image-><%= kind.downcase %>Data();
7
+
8
+ return INT2FIX(data.count());
9
+ __END
10
+ }
@@ -0,0 +1,23 @@
1
+ static VALUE exiv2_metadata_delete(VALUE rb_key) {
2
+ __BEGIN
3
+ rbImage* image;
4
+ Data_Get_Struct(self, rbImage, image);
5
+
6
+ VALUE strkey = rb_funcall(rb_key, rb_intern("to_s"), 0);
7
+ Exiv2::<%= kind %>Data &data = image->image-><%= kind.downcase %>Data();
8
+
9
+ if(data.empty()) {
10
+ return Qnil;
11
+ }
12
+
13
+ Exiv2::<%= kind %>Key key(STR(strkey));
14
+ Exiv2::<%= kind %>Data::iterator pos = data.findKey(key);
15
+ if (pos == data.end()) {
16
+ return Qnil;
17
+ }
18
+
19
+ std::string v = pos->toString();
20
+ data.erase(pos);
21
+ return rb_str_new(v.c_str(), v.length());
22
+ __NIL_END
23
+ }