lib/squib/graphics/image.rb in squib-0.14.2 vs lib/squib/graphics/image.rb in squib-0.14.3.pre1
- old
+ new
@@ -1,108 +1,129 @@
-module Squib
-
- # Cache all pngs we've already loaded
- #
- # :nodoc:
- # @api private
- def cache_load_image(file)
- @img_cache ||= {}
- @img_cache[file] || @img_cache[file] = Cairo::ImageSurface.from_png(file)
- end
- module_function :cache_load_image
-
- class Card
-
- # :nodoc:
- # @api private
- def png(file, box, paint, trans)
- Squib.logger.debug {"RENDERING PNG: \n file: #{file}\n box: #{box}\n paint: #{paint}\n trans: #{trans}"}
- return if file.nil? or file.eql? ''
- png = Squib.cache_load_image(file)
- use_cairo do |cc|
- cc.translate(box.x, box.y)
- box.width = png.width.to_f if box.width == :native
- box.height = png.height.to_f if box.height == :native
- box.width = png.width.to_f * box.height.to_f / png.height.to_f if box.width == :scale
- box.height = png.height.to_f * box.width.to_f / png.width.to_f if box.height == :scale
-
- scale_width = box.width.to_f / png.width.to_f
- scale_height = box.height.to_f / png.height.to_f
- warn_png_scale(file, scale_width, scale_height)
- cc.scale(scale_width, scale_height)
-
- cc.rotate(trans.angle)
- cc.flip(trans.flip_vertical, trans.flip_horizontal, box.width / 2, box.height / 2)
- cc.translate(-box.x, -box.y)
-
- trans.crop_width = png.width.to_f if trans.crop_width == :native
- trans.crop_height = png.height.to_f if trans.crop_height == :native
- cc.rounded_rectangle(box.x, box.y, trans.crop_width, trans.crop_height, trans.crop_corner_x_radius, trans.crop_corner_y_radius)
- cc.clip
- cc.translate(-trans.crop_x, -trans.crop_y)
-
-
- cc.set_source(png, box.x, box.y)
- cc.operator = paint.blend unless paint.blend == :none
- if paint.mask.empty?
- cc.paint(paint.alpha)
- else
- cc.set_source_squibcolor(paint.mask)
- cc.mask(png, box.x, box.y)
- end
- end
- end
-
- # :nodoc:
- # @api private
- def warn_png_scale(file, scale_width, scale_height)
- if @deck.conf.warn_png_scale? && (scale_width > 1.0 || scale_height > 1.0)
- Squib.logger.warn "PNG is being upscaled - antialiasing could result: #{file}"
- end
- end
-
- # :nodoc:
- # @api private
- def svg(file, svg_args, box, paint, trans)
- Squib.logger.debug {"Rendering: #{file}, id: #{id} @#{x},#{y} #{width}x#{height}, alpha: #{alpha}, blend: #{blend}, angle: #{angle}, mask: #{mask}"}
- Squib.logger.warn 'Both an SVG file and SVG data were specified' unless file.to_s.empty? || svg_args.data.to_s.empty?
- return if (file.nil? or file.eql? '') and svg_args.data.nil? # nothing specified TODO Move this out to arg validator
- svg_args.data = File.read(file) if svg_args.data.to_s.empty?
- begin
- svg = Rsvg::Handle.new_from_data(svg_args.data)
- rescue Rsvg::Error::Failed
- Squib.logger.error "Invalid SVG data. Is '#{file}' a valid svg file?"
- return
- end
- box.width = svg.width if box.width == :native
- box.height = svg.height if box.height == :native
- box.width = svg.width.to_f * box.height.to_f / svg.height.to_f if box.width == :scale
- box.height = svg.height.to_f * box.width.to_f / svg.width.to_f if box.height == :scale
- scale_width = box.width.to_f / svg.width.to_f
- scale_height = box.height.to_f / svg.height.to_f
- use_cairo do |cc|
- cc.translate(box.x, box.y)
- cc.flip(trans.flip_vertical, trans.flip_horizontal, box.width / 2, box.height / 2)
- cc.rotate(trans.angle)
- cc.scale(scale_width, scale_height)
-
- trans.crop_width = box.width if trans.crop_width == :native
- trans.crop_height = box.height if trans.crop_height == :native
- cc.rounded_rectangle(0, 0, trans.crop_width / scale_width, trans.crop_height / scale_height, trans.crop_corner_x_radius, trans.crop_corner_y_radius)
- cc.clip
- cc.translate(-trans.crop_x, -trans.crop_y)
-
- cc.operator = paint.blend unless paint.blend == :none
- if paint.mask.to_s.empty?
- cc.render_rsvg_handle(svg, id: svg_args.id)
- else
- tmp = Cairo::ImageSurface.new(box.width / scale_width, box.height / scale_height)
- tmp_cc = Cairo::Context.new(tmp)
- tmp_cc.render_rsvg_handle(svg, id: svg_args.id)
- cc.set_source_squibcolor(paint.mask)
- cc.mask(tmp, 0, 0)
- end
- end
- end
-
- end
-end
+module Squib
+
+ # Cache all pngs we've already loaded
+ #
+ # :nodoc:
+ # @api private
+ def cache_load_image(file)
+ @img_cache ||= {}
+ @img_cache[file] ||= open_png file
+ end
+ module_function :cache_load_image
+
+ # Open a PNG file, checking magic bytes if it's a real PNG
+ # Magic bytes taken from:
+ # https://en.wikipedia.org/wiki/List_of_file_signatures
+ # :nodoc:
+ # @api private
+ PNG_MAGIC = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]
+ def open_png(file)
+ if PNG_MAGIC == File.read(file, 8).bytes
+ return Cairo::ImageSurface.from_png(file)
+ else
+ raise ArgumentError.new("ERROR: #{file} is not a PNG file")
+ end
+ end
+ module_function :open_png
+
+ class Card
+
+ # :nodoc:
+ # @api private
+ def png(file, box, paint, trans)
+ Squib.logger.debug {"RENDERING PNG: \n file: #{file}\n box: #{box}\n paint: #{paint}\n trans: #{trans}"}
+ return if file.nil? or file.eql? ''
+ png = Squib.cache_load_image(file)
+ use_cairo do |cc|
+ cc.translate(box.x, box.y)
+ box.width = png.width.to_f if box.width == :native
+ box.height = png.height.to_f if box.height == :native
+ box.width = png.width.to_f * box.height.to_f / png.height.to_f if box.width == :scale
+ box.height = png.height.to_f * box.width.to_f / png.width.to_f if box.height == :scale
+
+ scale_width = box.width.to_f / png.width.to_f
+ scale_height = box.height.to_f / png.height.to_f
+ warn_png_scale(file, scale_width, scale_height)
+ cc.scale(scale_width, scale_height)
+
+ cc.rotate(trans.angle)
+ cc.flip(trans.flip_vertical, trans.flip_horizontal, box.width / 2, box.height / 2)
+ cc.translate(-box.x, -box.y)
+
+ trans.crop_width = png.width.to_f if trans.crop_width == :native
+ trans.crop_height = png.height.to_f if trans.crop_height == :native
+ cc.rounded_rectangle(box.x, box.y, trans.crop_width, trans.crop_height, trans.crop_corner_x_radius, trans.crop_corner_y_radius)
+ cc.clip
+ cc.translate(-trans.crop_x, -trans.crop_y)
+
+
+ cc.set_source(png, box.x, box.y)
+ cc.operator = paint.blend unless paint.blend == :none
+ if paint.mask.empty?
+ cc.paint(paint.alpha)
+ else
+ cc.set_source_squibcolor(paint.mask)
+ cc.mask(png, box.x, box.y)
+ end
+ end
+ end
+
+ # :nodoc:
+ # @api private
+ def warn_png_scale(file, scale_width, scale_height)
+ if @deck.conf.warn_png_scale? && (scale_width > 1.0 || scale_height > 1.0)
+ Squib.logger.warn "PNG is being upscaled - antialiasing could result: #{file}"
+ end
+ end
+
+ # :nodoc:
+ # @api private
+ def svg(file, svg_args, box, paint, trans)
+ Squib.logger.debug {"Rendering: #{file}, id: #{id} @#{x},#{y} #{width}x#{height}, alpha: #{alpha}, blend: #{blend}, angle: #{angle}, mask: #{mask}"}
+ Squib.logger.warn 'Both an SVG file and SVG data were specified' unless file.to_s.empty? || svg_args.data.to_s.empty?
+ return if (file.nil? or file.eql? '') and svg_args.data.nil? # nothing specified TODO Move this out to arg validator
+ if(box.width == 0 || box.height == 0)
+ if @deck.conf.warn_zero_size_image?
+ Squib.logger.warn "svg: zero-sized width or height detected for #{file}. SVG not drawn."
+ end
+ return
+ end
+ svg_args.data = File.read(file) if svg_args.data.to_s.empty?
+ begin
+ svg = Rsvg::Handle.new_from_data(svg_args.data)
+ rescue Rsvg::Error::Failed
+ Squib.logger.error "Invalid SVG data. Is '#{file}' a valid svg file?"
+ return
+ end
+ box.width = svg.width if box.width == :native
+ box.height = svg.height if box.height == :native
+ box.width = svg.width.to_f * box.height.to_f / svg.height.to_f if box.width == :scale
+ box.height = svg.height.to_f * box.width.to_f / svg.width.to_f if box.height == :scale
+ scale_width = box.width.to_f / svg.width.to_f
+ scale_height = box.height.to_f / svg.height.to_f
+ use_cairo do |cc|
+ cc.translate(box.x, box.y)
+ cc.flip(trans.flip_vertical, trans.flip_horizontal, box.width / 2, box.height / 2)
+ cc.rotate(trans.angle)
+ cc.scale(scale_width, scale_height)
+
+ trans.crop_width = box.width if trans.crop_width == :native
+ trans.crop_height = box.height if trans.crop_height == :native
+ cc.rounded_rectangle(0, 0, trans.crop_width / scale_width, trans.crop_height / scale_height, trans.crop_corner_x_radius, trans.crop_corner_y_radius)
+ cc.clip
+ cc.translate(-trans.crop_x, -trans.crop_y)
+
+ cc.operator = paint.blend unless paint.blend == :none
+ if paint.mask.to_s.empty?
+ cc.render_rsvg_handle(svg, id: svg_args.id)
+ else
+ tmp = Cairo::ImageSurface.new(box.width / scale_width, box.height / scale_height)
+ tmp_cc = Cairo::Context.new(tmp)
+ tmp_cc.render_rsvg_handle(svg, id: svg_args.id)
+ cc.set_source_squibcolor(paint.mask)
+ cc.mask(tmp, 0, 0)
+ end
+ end
+ end
+
+ end
+end