OSDN Git Service

pass test:resource picture create
[pettanr/pettanr.git] / app / models / resource_picture.rb
1 class ResourcePicture < ActiveRecord::Base
2   belongs_to :artist
3   belongs_to :license
4   belongs_to :picture
5   has_many :panel_pictures
6   belongs_to :original_picture
7   
8   validates :ext, :presence => true, :length => {:maximum => 4}, :inclusion => {:in => ['png', 'jpeg', 'gif']}\r
9   validates :width, :presence => true, :numericality => true, :natural_number => true
10   validates :height, :presence => true, :numericality => true, :natural_number => true
11   validates :filesize, :presence => true, :numericality => {:greater_than => 0, :less_than_or_equal_to => 2000000}, :natural_number => true
12   validates :artist_id, :presence => true, :numericality => true, :existence => true
13   validates :license_id, :presence => true, :numericality => true, :existence => true
14   validates :original_picture_id, :presence => true, :numericality => true, :existence => true
15   validates :artist_name, :presence => true
16   validates :picture_id, :presence => true, :numericality => true, :existence => true
17   
18   before_destroy :destroy_with_file
19   
20   def destroy_with_file
21     PictureIO.resource_picture_io.delete self.filename
22     PictureIO.resource_picture_io.class.subdirs.each do |d|
23       next if d.empty?
24       PictureIO.resource_picture_io.delete(self.filename, d) if PictureIO.resource_picture_io.exist?(self.filename, d)
25     end
26   end
27   
28   def self.resize(data, dw, dh)
29     Magick::Image.from_blob(data).shift.resize(dw, dh)
30   end
31   
32   #サイズの調整(limw,limhに必ず収まるように合わせる)
33   def self.fix_size_both(limw, limh, w, h)
34     wr = if w > limw
35       limw*100/w
36     else
37       100
38     end
39     hr = if h > limh
40       limh*100/h
41     else
42       100
43     end
44     res = if wr < hr
45       #幅の方が圧縮率が高い
46       [w*wr/100, h*wr/100]
47     else
48       #高さの方が圧縮率が高い
49       [w*hr/100, h*hr/100]
50     end
51     res
52   end
53   
54   def dext
55     self.ext.downcase
56   end
57   
58   def filename
59     "#{self.id}.#{self.dext}"
60   end
61   
62   def mime_type
63     "image/#{self.dext}"
64   end
65   
66   def url subdir = nil
67     '/resource_pictures/' + (subdir.to_s.empty? ? '' : subdir.to_s + '/' ) + filename
68   end
69   
70   def thumbnail(rimg)
71     tw, th = ResourcePicture.fix_size_both(64, 64, rimg.columns, rimg.rows)
72     ResourcePicture.resize(rimg.to_blob, tw, th).to_blob
73   end
74   
75   def copy_data(op)
76     attr = {:width => op.width, :height => op.height, :ext => op.ext, :filesize => op.filesize, 
77       :original_picture_id => op.id, :artist_id => op.artist_id
78     }
79     self.attributes = attr
80   end
81   
82   def data_to_mgk picture_data
83     begin
84       mgk = Magick::Image.from_blob(picture_data).shift
85     rescue 
86       self.errors.add :base, 'magick failed'
87       return false
88     end
89     mgk
90   end
91   
92   def op_mgk
93     d = self.original_picture.restore
94     return false unless d
95     self.data_to_mgk d
96   end
97   
98   def new_picture mgk
99     pc = Picture.new
100     pc.copy_data self
101     pc.store mgk
102     pc
103   end
104   
105   
106   def to_gif?
107     self.dext == 'png' and self.flag_gif_convert >= 0
108   end
109   
110   def self.png_to_gif(data)
111     res = nil
112     begin
113       mgk = Magick::Image.from_blob(data).shift
114       mgk.format = 'gif'
115       res = mgk
116     rescue
117       res = false
118     end
119     res
120   end
121   
122   def store
123     res = false
124     self.copy_data self.original_picture
125     mgk = self.op_mgk
126     return false unless mgk
127     OriginalPicture.transaction do
128       pc = self.new_picture mgk
129       if res = pc.valid?
130         self.picture_id = pc.id
131         if res = self.save
132           res = self.store_picture_with_gif(mgk)
133         end
134       else
135         self.errors.add :base, 'picture does not create'
136       end
137       raise ActiveRecord::Rollback unless res
138     end
139     res
140   end
141   
142   def store_picture_with_gif(mgk)
143     if res = self.store_picture(mgk)
144       if self.to_gif?
145         if gifmgk = ResourcePicture.png_to_gif(mgk.to_blob)
146           res = self.store_picture(gifmgk)
147         else
148           self.errors.add :base, 'picture data can not conv to gif'
149           res = false
150         end
151       end
152     else
153       self.errors.add :base, 'resource picture io does not work'
154     end
155     res
156   end
157   
158   def store_picture(mgk)
159     res = false
160     tdata = self.flag_thumbnail >= 0 ? thumbnail(mgk) : mgk.to_blob
161     fdata = mgk.to_blob
162     return false unless PictureIO.resource_picture_io.put(tdata, "#{self.id}.#{mgk.format}")
163     PictureIO.resource_picture_io.put(fdata, "#{self.id}.#{mgk.format}", 'full')
164   end
165   
166   def restore(subdir = nil)
167     PictureIO.resource_picture_io.get self.filename, subdir
168   end
169   
170   def self.default_page_size
171     25
172   end
173   
174   def self.max_page_size
175     100
176   end
177   
178   def self.page prm = nil
179     page = prm.to_i
180     page = 1 if page < 1
181     page
182   end
183   
184   def self.page_size prm = self.default_page_size
185     page_size = prm.to_i
186     page_size = self.max_page_size if page_size > self.max_page_size
187     page_size = self.default_page_size if page_size < 1
188     page_size
189   end
190   
191   def self.offset cnt, prm = nil
192     offset = prm.to_i
193     offset = cnt - 1 if offset >= cnt
194     offset = cnt - offset.abs if offset < 0
195     offset = 0 if offset < 0
196     offset
197   end
198   
199   def self.list opt = {}, page = 1, page_size = self.default_page_size
200     opt.merge!(self.list_opt) unless opt[:include]
201     opt.merge!({:order => 'updated_at desc', :limit => page_size, :offset => (page -1) * page_size})
202     ResourcePicture.find(:all, opt)
203   end
204   
205   def self.list_opt
206     {:include => [:license, :artist]}
207   end
208   
209   def self.list_json_opt
210     {:include => [:license, :artist]}
211   end
212   
213   def self.show rid, opt = {}
214     r = ResourcePicture.find(rid, :include => self.show_include_opt(opt))
215 #    raise ActiveRecord::Forbidden unless c.visible?(au)
216     r
217   end
218   
219   def self.show_include_opt opt = {}
220     res = [:license, :artist]
221     res.push(opt[:include]) if opt[:include]
222     res
223   end
224   
225   def self.show_json_include_opt
226     {:include => [:license, :artist]}
227   end
228   
229   def self.visible_count
230     ResourcePicture.count
231   end
232   
233   def flags
234     begin
235       @flags = JSON.parse(self.settings) unless @flags
236     rescue 
237     end
238     @flags
239   end
240   
241   def flags=(s)
242     @flags = s
243   end
244   
245   def flag_open
246     @flag_open = flags["open"] unless @flag_open
247     @flag_open
248   end
249   
250   def flag_commercial
251     @flag_commercial = flags["commercial"] unless @flag_commercial
252     @flag_commercial
253   end
254   
255   def flag_official
256     @flag_official = flags["official"] unless @flag_official
257     @flag_official
258   end
259   
260   def flag_attribution
261     @flag_attribution = flags["attribution"] unless @flag_attribution
262     @flag_attribution
263   end
264   
265   def flag_derive
266     @flag_derive = flags["derive"] unless @flag_derive
267     @flag_derive
268   end
269   
270   def flag_thumbnail
271     @flag_thumbnail = flags["thumbnail"] unless @flag_thumbnail
272     @flag_thumbnail
273   end
274   
275   def flag_gif_convert
276     @flag_gif_convert = flags["gif_convert"] unless @flag_gif_convert
277     @flag_gif_convert
278   end
279   
280   def flag_reverse
281     @flag_reverse = flags["reverse"] unless @flag_reverse
282     @flag_reverse
283   end
284   
285   def flag_resize
286     @flag_resize = flags["resize"] unless @flag_resize
287     @flag_resize
288   end
289   
290   def flag_sync_vh
291     @flag_sync_vh = flags["sync_vh"] unless @flag_sync_vh
292     @flag_sync_vh
293   end
294   
295   def flag_overlap
296     @flag_overlap = flags["overlap"] unless @flag_overlap
297     @flag_overlap
298   end
299   
300 end