module Prawn::Graphics::Patterns
Constants
- Gradient
- GradientStop
Public Instance Methods
Sets the fill gradient. old arguments:
from, to, color1, color2 or from, r1, to, r2, color1, color2
new arguments:
from: [x, y] to: [x, y] r1: radius r2: radius stops: [color, color, ...] or { position => color, position => color, ... } apply_transformations: true
Examples:
# draws a horizontal axial gradient that starts at red on the left # and ends at blue on the right fill_gradient from: [0, 0], to: [100, 0], stops: ['red', 'blue'] # draws a horizontal radial gradient that starts at red, is green # 80% of the way through, and finishes blue fill_gradient from: [0, 0], r1: 0, to: [100, 0], r2: 180, stops: { 0 => 'red', 0.8 => 'green', 1 => 'blue' }
from
and to
specify the axis of where the gradient should be painted.
r1
and r2
, if specified, make a radial gradient with the starting circle of radius r1
centered at from
and ending at a circle of radius r2
centered at to
. If r1
is not specified, a axial gradient will be drawn.
stops
is an array or hash of stops. Each stop is either just a string indicating the color, in which case the stops will be evenly distributed across the gradient, or a hash where the key is a position between 0 and 1 indicating what distance through the gradient the color should change, and the value is a color string.
Option apply_transformations
, if set true, will transform the gradient's co-ordinate space so it matches the current co-ordinate space of the document. This option will be the default from Prawn
v3, and is default true if you use the new arguments format. The default for the old arguments format, false, will mean if you (for example) scale your document by 2 and put a gradient inside, you will have to manually multiply your co-ordinates by 2 so the gradient is correctly positioned.
# File lib/prawn/graphics/patterns.rb, line 67 def fill_gradient(*args, **kwargs) set_gradient(:fill, *args, **kwargs) end
Sets the stroke gradient. See fill_gradient
for a description of the arguments to this method.
# File lib/prawn/graphics/patterns.rb, line 73 def stroke_gradient(*args, **kwargs) set_gradient(:stroke, *args, **kwargs) end
Private Instance Methods
# File lib/prawn/graphics/patterns.rb, line 181 def create_gradient_pattern(gradient) if gradient.apply_transformations.nil? && current_transformation_matrix_with_translation(0, 0) != [1, 0, 0, 1, 0, 0] warn 'Gradients in Prawn 2.x and lower are not correctly positioned '\ 'when a transformation has been made to the document. ' \ "Pass 'apply_transformations: true' to correctly transform the " \ 'gradient, or see ' \ 'https://github.com/prawnpdf/prawn/wiki/Gradient-Transformations ' \ 'for more information.' end shader_stops = gradient.stops.each_cons(2).map do |first, second| ref!( FunctionType: 2, Domain: [0.0, 1.0], C0: first.color, C1: second.color, N: 1.0 ) end # If there's only two stops, we can use the single shader. # Otherwise we stitch the multiple shaders together. shader = if shader_stops.length == 1 shader_stops.first else ref!( FunctionType: 3, # stitching function Domain: [0.0, 1.0], Functions: shader_stops, Bounds: gradient.stops[1..-2].map(&:position), Encode: [0.0, 1.0] * shader_stops.length ) end x1, y1, x2, y2, transformation = gradient_coordinates(gradient) coords = if gradient.type == :axial [0, 0, x2 - x1, y2 - y1] else [0, 0, gradient.r1, x2 - x1, y2 - y1, gradient.r2] end shading = ref!( ShadingType: gradient.type == :axial ? 2 : 3, ColorSpace: color_space(gradient.stops.first.color), Coords: coords, Function: shader, Extend: [true, true] ) ref!( PatternType: 2, # shading pattern Shading: shading, Matrix: transformation ) end
# File lib/prawn/graphics/patterns.rb, line 240 def gradient_coordinates(gradient) x1, y1 = map_to_absolute(gradient.from) x2, y2 = map_to_absolute(gradient.to) transformation = if gradient.apply_transformations current_transformation_matrix_with_translation(x1, y1) else [1, 0, 0, 1, x1, y1] end [x1, y1, x2, y2, transformation] end
# File lib/prawn/graphics/patterns.rb, line 177 def gradient_registry @gradient_registry ||= {} end
# File lib/prawn/graphics/patterns.rb, line 163 def gradient_registry_key(gradient) _x1, _y1, x2, y2, transformation = gradient_coordinates(gradient) key = [ gradient.type.to_s, transformation, x2, y2, gradient.r1 || -1, gradient.r2 || -1, gradient.stops.length, gradient.stops.map { |s| [s.position, s.color] } ].flatten Digest::SHA1.hexdigest(key.pack('HC*')) end
# File lib/prawn/graphics/patterns.rb, line 109 def parse_gradient_arguments( # rubocop: disable Metrics/ParameterLists *arguments, from: nil, to: nil, r1: nil, r2: nil, stops: nil, apply_transformations: nil ) case arguments.length when 0 apply_transformations = true if apply_transformations.nil? when 4 from, to, *stops = arguments when 6 from, r1, to, r2, *stops = arguments else raise ArgumentError, "Unknown type of gradient: #{arguments.inspect}" end if stops.length < 2 raise ArgumentError, 'At least two stops must be specified' end stops = stops.map.with_index do |stop, index| case stop when Array, Hash position, color = stop else position = index / (stops.length.to_f - 1) color = stop end unless (0..1).cover?(position) raise ArgumentError, 'position must be between 0 and 1' end GradientStop.new(position, normalize_color(color)) end if stops.first.position != 0 raise ArgumentError, 'The first stop must have a position of 0' end if stops.last.position != 1 raise ArgumentError, 'The last stop must have a position of 1' end if stops.map { |stop| color_type(stop.color) }.uniq.length > 1 raise ArgumentError, 'All colors must be of the same color space' end Gradient.new( r1 ? :radial : :axial, apply_transformations, stops, from, to, r1, r2 ) end
# File lib/prawn/graphics/patterns.rb, line 79 def set_gradient(type, *grad, **kwargs) gradient = parse_gradient_arguments(*grad, **kwargs) patterns = page.resources[:Pattern] ||= {} registry_key = gradient_registry_key gradient unless patterns.key? "SP#{registry_key}" shading = gradient_registry[registry_key] unless shading shading = create_gradient_pattern(gradient) gradient_registry[registry_key] = shading end patterns["SP#{registry_key}"] = shading end operator = case type when :fill 'scn' when :stroke 'SCN' else raise ArgumentError, "unknown type '#{type}'" end set_color_space type, :Pattern renderer.add_content "/SP#{registry_key} #{operator}" end