master
1class Image
2 attr_reader :path
3
4 def initialize(path, exif = ExifParser.new)
5 @path = path
6 @exif = exif
7 ensure_in_whitelist!(@path)
8 end
9
10 def filename
11 @filename ||= sanitize(@path)
12 end
13
14 def content_type
15 @content_type ||= ::MIME::Types.type_for(filename).first.to_s
16 end
17
18 def geolocation
19 @exif.parse_geolocation_from(@path)
20 end
21
22 def sha256
23 @sha256 ||= Digest::SHA256.file(@path).to_s
24 end
25
26 def resize_to_fit(width:, height:)
27 manipulate! do |image|
28 image.resize "#{width}x#{height}"
29 image = yield(image) if block_given?
30 image
31 end
32 end
33
34 def resize_to_fill(width:, height:, gravity: 'Center')
35 manipulate! do |image|
36 columns, rows = image[:dimensions]
37 image.combine_options do |cmd|
38 if width != columns || height != rows
39 scale_x = width/columns.to_f
40 scale_y = height/rows.to_f
41 if scale_x >= scale_y
42 columns = (scale_x * (columns + 0.5)).round
43 rows = (scale_x * (rows + 0.5)).round
44 cmd.resize "#{columns}"
45 else
46 columns = (scale_y * (columns + 0.5)).round
47 rows = (scale_y * (rows + 0.5)).round
48 cmd.resize "x#{rows}"
49 end
50 end
51 cmd.gravity gravity
52 cmd.background "rgba(255,255,255,0.0)"
53 cmd.extent "#{width}x#{height}" if columns != width || rows != height
54 end
55 image = yield(image) if block_given?
56 image
57 end
58 end
59
60 def watermark(message)
61 manipulate! do |image|
62 image.combine_options do |c|
63 c.gravity 'Southeast'
64 c.draw "text 10,10 \"#{message} on CakeSide.com\""
65 c.font 'helvetica'
66 c.fill("#FFFFFF")
67 c.pointsize 28
68 end
69 image
70 end
71 end
72
73 private
74
75 def manipulate!
76 image = ::MiniMagick::Image.open(path)
77 image = yield(image)
78 image.write(path)
79 image.run_command("identify", path)
80 rescue StandardError => error
81 Rails.logger.error("#{error.message} #{error.backtrace.join(', ')}")
82 ensure
83 image.try(:destroy!)
84 end
85
86 def sanitize(name)
87 name = name.gsub("\\", "/")
88 name = File.basename(name)
89 name = name.gsub(sanitize_regexp,"_")
90 name = "_#{name}" if name =~ /\A\.+\z/
91 name = "unnamed" if name.size == 0
92 return name.mb_chars.to_s
93 end
94
95 def sanitize_regexp
96 /[^a-zA-Z0-9\.\-\+_]/
97 end
98
99 def ensure_in_whitelist!(path)
100 unless %w(.jpg .jpeg .gif .png .bmp .tif).include?(File.extname(path).downcase)
101 raise StandardError.new("This file is not in the whitelist. #{path}")
102 end
103 end
104end