2009-06-02 00:08:57 +02:00
|
|
|
require "image_science"
|
|
|
|
require 'mini_exiftool'
|
|
|
|
|
2009-05-22 14:13:46 +02:00
|
|
|
class Photo < ActiveRecord::Base
|
|
|
|
belongs_to :album
|
2009-05-22 22:38:52 +02:00
|
|
|
has_many :photo_tags, :dependent => :destroy
|
|
|
|
has_many :tags, :through => :photo_tags
|
2009-05-22 21:04:41 +02:00
|
|
|
|
|
|
|
validates_uniqueness_of :path, :message => "Photo already exsists on disc"
|
2009-05-25 21:39:43 +02:00
|
|
|
validates_presence_of :title
|
2009-05-22 22:38:52 +02:00
|
|
|
|
2009-06-12 01:04:57 +02:00
|
|
|
before_validation :set_title
|
2009-06-16 21:43:03 +02:00
|
|
|
before_save :ensure_file
|
2009-06-03 01:33:39 +02:00
|
|
|
before_create :exif_read
|
|
|
|
after_create :create_thumbnails
|
2009-06-16 21:43:03 +02:00
|
|
|
#before_update :exif_write # should only write if tags are changed as images can be large and thus ExifTool will take a while to write to the file
|
2009-05-22 22:38:52 +02:00
|
|
|
before_destroy :destroy_file
|
2009-06-02 00:08:57 +02:00
|
|
|
|
2009-05-25 21:39:43 +02:00
|
|
|
attr_accessor :tag_list
|
2009-06-09 00:50:25 +02:00
|
|
|
#attr_protected :path
|
2009-06-02 00:08:57 +02:00
|
|
|
|
2009-06-09 00:30:22 +02:00
|
|
|
named_scope :untouched, :conditions => "Photos.description IS NULL AND Photos.Id NOT IN ( SELECT Photo_ID FROM Photo_Tags)", :include => :album
|
2009-06-11 13:05:09 +02:00
|
|
|
named_scope :previous, lambda { |p,a| { :conditions => ["id < :id AND Album_Id = :album ", { :id => p, :album => a } ], :limit => 1, :order => "Id DESC"} }
|
|
|
|
named_scope :next, lambda { |p,a| { :conditions => ["id > :id AND Album_Id = :album ", { :id => p, :album => a } ], :limit => 1, :order => "Id ASC"} }
|
|
|
|
|
|
|
|
def to_param
|
2009-06-16 21:43:03 +02:00
|
|
|
self.id.to_s + '-' + self.title.parameterize
|
2009-06-12 01:04:57 +02:00
|
|
|
end
|
|
|
|
|
2009-06-02 00:08:57 +02:00
|
|
|
def path_original_public
|
|
|
|
return APP_CONFIG[:photos_path_public] + self.path
|
|
|
|
end
|
|
|
|
|
|
|
|
def path_modified_public(size)
|
2009-06-03 01:33:39 +02:00
|
|
|
return APP_CONFIG[:thumbs_path_public] + self.album.path + "/" + self.id.to_s + "_" + size + self.extension
|
2009-06-02 00:08:57 +02:00
|
|
|
end
|
2009-06-03 02:15:23 +02:00
|
|
|
|
|
|
|
def tag(title)
|
|
|
|
return if self.tags.collect{|tag|tag.title}.include?( title )
|
|
|
|
self.photo_tags.create(:tag => Tag.find_or_create_by_title( :title => title) )
|
|
|
|
self.reload
|
|
|
|
end
|
|
|
|
|
|
|
|
def untag(title)
|
|
|
|
return if !self.tags.collect{|tag|tag.title}.include?( title )
|
|
|
|
# perhaps not the best way but it finds the correct PhotoTag and deletes it
|
|
|
|
self.photo_tags.select{|photo_tag|
|
|
|
|
photo_tag.tag.title == title
|
|
|
|
}.each {|photo_tag|photo_tag.destroy}
|
|
|
|
self.reload
|
|
|
|
end
|
2009-06-02 00:08:57 +02:00
|
|
|
|
2009-05-25 21:39:43 +02:00
|
|
|
def tag_list
|
2009-07-06 15:41:19 +02:00
|
|
|
return self.tags.find(:all, :order => 'title').map{ |t| t.title }.sort.join(" ")
|
2009-05-25 21:39:43 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
def tag_list=(tags)
|
|
|
|
ts = Array.new
|
|
|
|
tags.split(" ").each do |tag|
|
2009-06-03 21:30:09 +02:00
|
|
|
ts.push( Tag.find_or_create_by_title( :title => tag.downcase) )
|
2009-05-25 21:39:43 +02:00
|
|
|
end
|
|
|
|
self.tags = ts
|
|
|
|
end
|
|
|
|
|
2009-06-02 00:08:57 +02:00
|
|
|
|
2009-06-03 01:33:39 +02:00
|
|
|
def exif_info
|
|
|
|
photo = MiniExiftool.new(self.path_original)
|
|
|
|
photo.tags.sort.each do |tag|
|
|
|
|
puts tag.ljust(28) + photo[tag].to_s
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# Map file extensions to mime types.
|
|
|
|
# Thanks to bug in Flash 8 the content type is always set to application/octet-stream.
|
|
|
|
# From: http://blog.airbladesoftware.com/2007/8/8/uploading-files-with-swfupload
|
|
|
|
def swf_uploaded_data=(data)
|
|
|
|
data.content_type = MIME::Types.type_for(data.original_filename)
|
|
|
|
self.title = data.original_filename
|
|
|
|
self.path = self.album.path + "/" + data.original_filename
|
2009-06-15 01:33:13 +02:00
|
|
|
File.open(APP_CONFIG[:photos_path] + self.path, 'wb') { |f| f.write(data.read) }
|
2009-06-03 01:33:39 +02:00
|
|
|
end
|
|
|
|
|
2009-06-12 01:04:57 +02:00
|
|
|
|
|
|
|
def create_thumbnails
|
2009-06-16 21:43:03 +02:00
|
|
|
ImageScience.with_image(self.path_original) do |img|
|
2009-06-12 01:04:57 +02:00
|
|
|
img.cropped_thumbnail(200) do |thumb|
|
|
|
|
thumb.save APP_CONFIG[:thumbs_path] + self.album.path + "/" + self.id.to_s + "_collection" + self.extension
|
|
|
|
end
|
|
|
|
img.cropped_thumbnail(100) do |thumb|
|
|
|
|
thumb.save APP_CONFIG[:thumbs_path] + self.album.path + "/" + self.id.to_s + "_album" + self.extension
|
|
|
|
end
|
|
|
|
img.thumbnail(210) do |thumb|
|
|
|
|
thumb.save APP_CONFIG[:thumbs_path] + self.album.path + "/" + self.id.to_s + "_preview" + self.extension
|
|
|
|
end
|
2009-06-30 21:24:06 +02:00
|
|
|
img.thumbnail(800) do |thumb|
|
2009-06-12 01:04:57 +02:00
|
|
|
thumb.save APP_CONFIG[:thumbs_path] + self.album.path + "/" + self.id.to_s + "_single" + self.extension
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2009-06-03 01:33:39 +02:00
|
|
|
protected
|
2009-06-16 21:43:03 +02:00
|
|
|
|
2009-06-03 02:15:23 +02:00
|
|
|
def extension
|
|
|
|
return File.extname(self.path_original)
|
|
|
|
end
|
|
|
|
|
2009-06-03 01:33:39 +02:00
|
|
|
def path_original
|
|
|
|
return APP_CONFIG[:photos_path] + self.path
|
|
|
|
end
|
|
|
|
|
|
|
|
def path_modified(size)
|
|
|
|
return APP_CONFIG[:thumbs_path] + self.album.path + "/" + self.id.to_s + "_" + size + self.extension
|
|
|
|
end
|
2009-06-02 00:08:57 +02:00
|
|
|
|
2009-06-12 01:04:57 +02:00
|
|
|
private
|
2009-06-03 01:33:39 +02:00
|
|
|
|
2009-06-16 21:43:03 +02:00
|
|
|
def set_title
|
|
|
|
self.title = File.basename( self.path ).gsub( self.extension, "" ) unless self.title
|
|
|
|
end
|
|
|
|
|
|
|
|
def ensure_file
|
|
|
|
self.destroy if !File.exists?( APP_CONFIG[:photos_path] + self.path )
|
|
|
|
end
|
|
|
|
|
2009-06-03 01:33:39 +02:00
|
|
|
def exif_read
|
2009-06-02 00:08:57 +02:00
|
|
|
photo = MiniExiftool.new(self.path_original)
|
2009-06-03 01:33:39 +02:00
|
|
|
self.longitude = photo.GPSLongitude if self.longitude.nil?
|
|
|
|
self.latitude = photo.GPSLatitude if self.latitude.nil?
|
|
|
|
self.title = photo.DocumentName if self.title.nil?
|
2009-06-30 21:24:06 +02:00
|
|
|
self.description = photo.ImageDescription if self.description.nil? || photo.ImageDescription != 'Exif_JPEG_PICTURE'
|
2009-06-15 23:36:47 +02:00
|
|
|
self.tag_list = (self.tags.empty? ? "" : self.album.tag_list) + " " + (photo.Keywords.nil? ? "" : photo.Keywords.to_a.map { |tag| tag.gsub(" ", "_") }.join(" "))
|
2009-06-02 00:08:57 +02:00
|
|
|
end
|
|
|
|
|
2009-06-03 01:33:39 +02:00
|
|
|
def exif_write
|
2009-06-02 00:08:57 +02:00
|
|
|
photo = MiniExiftool.new(self.path_original)
|
|
|
|
photo.GPSLongitude = self.longitude
|
|
|
|
photo.GPSLatitude = self.latitude
|
|
|
|
photo.DocumentName = self.title
|
|
|
|
photo.ImageDescription = self.description
|
2009-06-03 01:33:39 +02:00
|
|
|
photo.Keywords = self.tags
|
2009-06-02 00:08:57 +02:00
|
|
|
photo.save
|
|
|
|
end
|
2009-06-03 21:30:09 +02:00
|
|
|
|
2009-05-22 22:38:52 +02:00
|
|
|
def destroy_file
|
2009-06-02 00:08:57 +02:00
|
|
|
#puts "DELETE THUMBS OF " + APP_CONFIG[:photos_path] + self.path
|
2009-06-16 21:43:03 +02:00
|
|
|
File.delete( self.path_original ) if File.exists?( self.path_original )
|
|
|
|
File.delete( self.path_modified("_collection") ) if File.exists?( self.path_modified("_collection") )
|
|
|
|
File.delete( self.path_modified("_album") ) if File.exists?( self.path_modified("_album") )
|
|
|
|
File.delete( self.path_modified("_single") ) if File.exists?( self.path_modified("_single") )
|
|
|
|
File.delete( self.path_modified("_preview") ) if File.exists?( self.path_modified("_preview") )
|
2009-05-22 22:38:52 +02:00
|
|
|
end
|
2009-05-22 14:13:46 +02:00
|
|
|
end
|