-
Notifications
You must be signed in to change notification settings - Fork 690
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #910 from iamjohnford/patch-1
Add Blend Modes
- Loading branch information
Showing
8 changed files
with
193 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
# encoding: utf-8 | ||
# | ||
# blend_mode.rb : Implements blend modes | ||
# | ||
# Contributed by John Ford. October, 2015 | ||
# | ||
# This is free software. Please see the LICENSE and COPYING files for details. | ||
# | ||
|
||
module Prawn | ||
module Graphics | ||
# The Prawn::BlendMode module is used to change the way | ||
# two layers are blended together. | ||
# | ||
# Passing an array of blend modes is allowed. PDF viewers should | ||
# blend layers based on the first recognized blend mode. | ||
# | ||
# Valid blend modes in v1.4 of the PDF spec include :Normal, :Multiply, :Screen, | ||
# :Overlay, :Darken, :Lighten, :ColorDodge, :ColorBurn, :HardLight, :SoftLight, | ||
# :Difference, :Exclusion, :Hue, :Saturation, :Color, and :Luminosity. | ||
# | ||
# Example: | ||
# pdf.fill_color('0000ff') | ||
# pdf.fill_rectangle([x, y+25], 50, 50) | ||
# pdf.blend_mode(:Multiply) do | ||
# pdf.fill_color('ff0000') | ||
# pdf.fill_circle([x, y], 25) | ||
# end | ||
# | ||
module BlendMode | ||
# @group Stable API | ||
|
||
def blend_mode(blend_mode = :Normal) | ||
renderer.min_version(1.4) | ||
|
||
save_graphics_state if block_given? | ||
renderer.add_content "/#{blend_mode_dictionary_name(blend_mode)} gs" | ||
if block_given? | ||
yield | ||
restore_graphics_state | ||
end | ||
end | ||
|
||
private | ||
|
||
def blend_mode_dictionary_registry | ||
@blend_mode_dictionary_registry ||= {} | ||
end | ||
|
||
def blend_mode_dictionary_name(blend_mode) | ||
key = Array(blend_mode).join('') | ||
dictionary_name = "BM#{key}" | ||
|
||
dictionary = blend_mode_dictionary_registry[dictionary_name] ||= ref!( | ||
:Type => :ExtGState, | ||
:BM => blend_mode | ||
) | ||
|
||
page.ext_gstates.merge!(dictionary_name => dictionary) | ||
dictionary_name | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
# encoding: utf-8 | ||
# | ||
# Blend modes can be used to change the way two layers (images, graphics, | ||
# text, etc.) are blended together. The <code>blend_mode</code> method | ||
# accepts a single blend mode or an array of blend modes. PDF viewers should | ||
# blend the layers based on the first recognized blend mode. | ||
# | ||
# Valid blend modes in v1.4 of the PDF spec include :Normal, :Multiply, :Screen, | ||
# :Overlay, :Darken, :Lighten, :ColorDodge, :ColorBurn, :HardLight, :SoftLight, | ||
# :Difference, :Exclusion, :Hue, :Saturation, :Color, and :Luminosity. | ||
# | ||
require File.expand_path(File.join(File.dirname(__FILE__), | ||
%w[.. example_helper])) | ||
|
||
filename = File.basename(__FILE__).gsub('.rb', '.pdf') | ||
Prawn::ManualBuilder::Example.generate(filename) do | ||
start_new_page | ||
|
||
# https://commons.wikimedia.org/wiki/File:Blend_modes_2.-bottom-layer.jpg#/media/File:Blend_modes_2.-bottom-layer.jpg | ||
bottom_layer = "#{Prawn::DATADIR}/images/blend_modes_bottom_layer.jpg" | ||
|
||
# https://commons.wikimedia.org/wiki/File:Blend_modes_1.-top-layer.jpg#/media/File:Blend_modes_1.-top-layer.jpg | ||
top_layer = "#{Prawn::DATADIR}/images/blend_modes_top_layer.jpg" | ||
|
||
blend_modes = [:Normal, :Multiply, :Screen, :Overlay, :Darken, :Lighten, :ColorDodge, :ColorBurn, :HardLight, :SoftLight, :Difference, :Exclusion, :Hue, :Saturation, :Color, :Luminosity] | ||
blend_modes.each_with_index do |blend_mode, index| | ||
x = index % 4 * 135 | ||
y = cursor - (index / 4 * 200) | ||
|
||
image bottom_layer, :at => [x, y], :fit => [125, 125] | ||
blend_mode(blend_mode) do | ||
image top_layer, :at => [x, y], :fit => [125, 125] | ||
end | ||
|
||
y -= 130 | ||
|
||
fill_color '009ddc' | ||
fill_rectangle [x, y], 75, 25 | ||
blend_mode(blend_mode) do | ||
fill_color 'fdb827' | ||
fill_rectangle [x + 50, y], 75, 25 | ||
end | ||
|
||
y -= 30 | ||
|
||
fill_color '000000' | ||
text_box blend_mode.to_s, :at => [x, y] | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
# encoding: utf-8 | ||
|
||
require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper") | ||
|
||
module BlendModeHelper | ||
def make_blend_mode(blend_mode) | ||
@pdf.blend_mode(blend_mode) do | ||
yield if block_given? | ||
end | ||
end | ||
end | ||
|
||
describe "Document with with blend_mode" do | ||
include BlendModeHelper | ||
|
||
it "the PDF version should be at least 1.4" do | ||
create_pdf | ||
make_blend_mode(:Multiply) | ||
str = @pdf.render | ||
expect(str[0, 8]).to eq("%PDF-1.4") | ||
end | ||
|
||
it "a new extended graphics state should be created for " \ | ||
"each unique blend mode setting" do | ||
create_pdf | ||
make_blend_mode(:Multiply) do | ||
make_blend_mode(:Screen) | ||
end | ||
extgstates = PDF::Inspector::ExtGState.analyze(@pdf.render).extgstates | ||
expect(extgstates.length).to eq(2) | ||
end | ||
|
||
it "a new extended graphics state should not be created for " \ | ||
"each duplicate blend mode setting" do | ||
create_pdf | ||
make_blend_mode(:Multiply) do | ||
make_blend_mode(:Multiply) | ||
end | ||
extgstates = PDF::Inspector::ExtGState.analyze(@pdf.render).extgstates | ||
expect(extgstates.length).to eq(1) | ||
end | ||
|
||
it "setting the blend mode with only one parameter sets a single blend mode value" do | ||
create_pdf | ||
make_blend_mode(:Multiply) | ||
extgstate = PDF::Inspector::ExtGState.analyze(@pdf.render).extgstates.first | ||
expect(extgstate[:blend_mode]).to eq(:Multiply) | ||
end | ||
|
||
it "setting the blend mode with multiple parameters sets an array of blend modes" do | ||
create_pdf | ||
make_blend_mode([:Multiply, :Screen, :Overlay]) | ||
extgstate = PDF::Inspector::ExtGState.analyze(@pdf.render).extgstates.first | ||
expect(extgstate[:blend_mode]).to eq([:Multiply, :Screen, :Overlay]) | ||
end | ||
|
||
describe "with more than one page" do | ||
include BlendModeHelper | ||
|
||
it "the extended graphic state resource should be added to both pages" do | ||
create_pdf | ||
make_blend_mode(:Multiply) | ||
@pdf.start_new_page | ||
make_blend_mode(:Multiply) | ||
extgstates = PDF::Inspector::ExtGState.analyze(@pdf.render).extgstates | ||
extgstate = extgstates[0] | ||
expect(extgstates.length).to eq(2) | ||
expect(extgstate[:blend_mode]).to eq(:Multiply) | ||
end | ||
end | ||
end |