From f44e621c7dce432fb2d0ac71153a58d2820c3dc8 Mon Sep 17 00:00:00 2001 From: Peter Goldstein Date: Tue, 15 Feb 2022 13:00:03 -0800 Subject: [PATCH 1/2] Add rise and leading to the set of text state operator helpers --- lib/pdf/core/text.rb | 74 ++++++++++++++++++++++++--- spec/pdf/core/text_spec.rb | 100 +++++++++++++++++++++++++++++++++++++ 2 files changed, 166 insertions(+), 8 deletions(-) diff --git a/lib/pdf/core/text.rb b/lib/pdf/core/text.rb index d019a7f..ca14aa2 100644 --- a/lib/pdf/core/text.rb +++ b/lib/pdf/core/text.rb @@ -252,6 +252,36 @@ def horizontal_text_scaling(amount = nil, &block) end end + # Increases or decreases the vertical distance between baselines of + # adjacent lines of text. + def leading(amount = nil, &block) + if amount.nil? + return defined?(@leading) && @leading || 0 + end + + if leading == amount + yield + else + wrap_and_restore_leading(amount, &block) + end + end + + # Move the baseline up or down from its default location. + # Positive values move the baseline up, negative values + # move it down, and a zero value resets the baseline to + # its default location. + def rise(amount = nil, &block) + if amount.nil? + return defined?(@rise) && @rise || 0 + end + + if rise == amount + yield + else + wrap_and_restore_rise(amount, &block) + end + end + def add_text_content(text, x, y, options) chunks = font.encode_text(text, options) @@ -316,6 +346,10 @@ def wrap_and_restore_character_spacing(block_value) end end + def update_character_spacing_state + add_content "\n#{PDF::Core.real(character_spacing)} Tc" + end + def wrap_and_restore_word_spacing(block_value) original_value = word_spacing @word_spacing = block_value @@ -328,6 +362,10 @@ def wrap_and_restore_word_spacing(block_value) end end + def update_word_spacing_state + add_content "\n#{PDF::Core.real(word_spacing)} Tw" + end + def wrap_and_restore_horizontal_text_scaling(block_value) original_value = horizontal_text_scaling @horizontal_text_scaling = block_value @@ -340,20 +378,40 @@ def wrap_and_restore_horizontal_text_scaling(block_value) end end - def update_character_spacing_state - update_real_text_state(character_spacing, 'Tc') + def update_horizontal_text_scaling_state + add_content "\n#{PDF::Core.real(horizontal_text_scaling)} Tz" end - def update_word_spacing_state - update_real_text_state(word_spacing, 'Tw') + def wrap_and_restore_leading(block_value) + original_value = leading + @leading = block_value + update_leading_state + begin + yield + ensure + @leading = original_value + update_leading_state + end end - def update_horizontal_text_scaling_state - update_real_text_state(horizontal_text_scaling, 'Tz') + def update_leading_state + add_content "\n#{PDF::Core.real(leading)} TL" + end + + def wrap_and_restore_rise(block_value) + original_value = rise + @rise = block_value + update_rise_state + begin + yield + ensure + @rise = original_value + update_rise_state + end end - def update_real_text_state(amount, operator) - add_content "\n#{PDF::Core.real(amount)} #{operator}" + def update_rise_state + add_content "\n#{PDF::Core.real(rise)} Ts" end end end diff --git a/spec/pdf/core/text_spec.rb b/spec/pdf/core/text_spec.rb index 54f711b..ada702c 100644 --- a/spec/pdf/core/text_spec.rb +++ b/spec/pdf/core/text_spec.rb @@ -236,6 +236,106 @@ def font_size end end + describe '#leading' do + describe 'called without argument' do + let(:result) { mock.leading } + + it 'functions as accessor' do + expect(result).to eq(0) + end + end + + describe 'called with argument' do + context 'when the block does not raise an error' do + before do + mock.leading(16) do + mock.add_content('TEST') + end + end + + it 'resets leading to original value' do + expect(mock.leading).to eq(0) + end + + it 'outputs correct PDF content' do + expect(mock.text).to eq("\n16.0 TLTEST\n0.0 TL") + end + end + + context 'when the block raises an error' do + let(:error_message) { SecureRandom.hex(5) } + + # rubocop:disable RSpec/ExpectInHook + before do + expect do + mock.leading(16) do + raise StandardError, error_message + end + end.to raise_error StandardError, error_message + end + # rubocop:enable RSpec/ExpectInHook + + it 'resets leading to original value' do + expect(mock.leading).to eq(0) + end + + it 'outputs correct PDF content' do + expect(mock.text).to eq("\n16.0 TL\n0.0 TL") + end + end + end + end + + describe '#rise' do + describe 'called without argument' do + let(:result) { mock.rise } + + it 'functions as accessor' do + expect(result).to eq(0) + end + end + + describe 'called with argument' do + context 'when the block does not raise an error' do + before do + mock.rise(2.3) do + mock.add_content('TEST') + end + end + + it 'resets rise to original value' do + expect(mock.rise).to eq(0) + end + + it 'outputs correct PDF content' do + expect(mock.text).to eq("\n2.3 TsTEST\n0.0 Ts") + end + end + + context 'when the block raises an error' do + let(:error_message) { SecureRandom.hex(5) } + + # rubocop:disable RSpec/ExpectInHook + before do + expect do + mock.rise(5) do + raise StandardError, error_message + end + end.to raise_error StandardError, error_message + end + # rubocop:enable RSpec/ExpectInHook + + it 'resets rise to original value' do + expect(mock.rise).to eq(0) + end + + it 'outputs correct PDF content' do + expect(mock.text).to eq("\n5.0 Ts\n0.0 Ts") + end + end + end + end + describe '#add_text_content' do it 'handles frozen strings' do expect { mock.add_text_content 'text', 0, 0, {} } From af6a22aa8bc0fe255d87f59c478dbeca6379ddb0 Mon Sep 17 00:00:00 2001 From: Peter Goldstein Date: Tue, 15 Feb 2022 14:50:30 -0800 Subject: [PATCH 2/2] Remove leading and limit change to rise --- lib/pdf/core/text.rb | 30 ----------------------- spec/pdf/core/text_spec.rb | 50 -------------------------------------- 2 files changed, 80 deletions(-) diff --git a/lib/pdf/core/text.rb b/lib/pdf/core/text.rb index ca14aa2..38e80b9 100644 --- a/lib/pdf/core/text.rb +++ b/lib/pdf/core/text.rb @@ -252,20 +252,6 @@ def horizontal_text_scaling(amount = nil, &block) end end - # Increases or decreases the vertical distance between baselines of - # adjacent lines of text. - def leading(amount = nil, &block) - if amount.nil? - return defined?(@leading) && @leading || 0 - end - - if leading == amount - yield - else - wrap_and_restore_leading(amount, &block) - end - end - # Move the baseline up or down from its default location. # Positive values move the baseline up, negative values # move it down, and a zero value resets the baseline to @@ -382,22 +368,6 @@ def update_horizontal_text_scaling_state add_content "\n#{PDF::Core.real(horizontal_text_scaling)} Tz" end - def wrap_and_restore_leading(block_value) - original_value = leading - @leading = block_value - update_leading_state - begin - yield - ensure - @leading = original_value - update_leading_state - end - end - - def update_leading_state - add_content "\n#{PDF::Core.real(leading)} TL" - end - def wrap_and_restore_rise(block_value) original_value = rise @rise = block_value diff --git a/spec/pdf/core/text_spec.rb b/spec/pdf/core/text_spec.rb index ada702c..8a50d87 100644 --- a/spec/pdf/core/text_spec.rb +++ b/spec/pdf/core/text_spec.rb @@ -236,56 +236,6 @@ def font_size end end - describe '#leading' do - describe 'called without argument' do - let(:result) { mock.leading } - - it 'functions as accessor' do - expect(result).to eq(0) - end - end - - describe 'called with argument' do - context 'when the block does not raise an error' do - before do - mock.leading(16) do - mock.add_content('TEST') - end - end - - it 'resets leading to original value' do - expect(mock.leading).to eq(0) - end - - it 'outputs correct PDF content' do - expect(mock.text).to eq("\n16.0 TLTEST\n0.0 TL") - end - end - - context 'when the block raises an error' do - let(:error_message) { SecureRandom.hex(5) } - - # rubocop:disable RSpec/ExpectInHook - before do - expect do - mock.leading(16) do - raise StandardError, error_message - end - end.to raise_error StandardError, error_message - end - # rubocop:enable RSpec/ExpectInHook - - it 'resets leading to original value' do - expect(mock.leading).to eq(0) - end - - it 'outputs correct PDF content' do - expect(mock.text).to eq("\n16.0 TL\n0.0 TL") - end - end - end - end - describe '#rise' do describe 'called without argument' do let(:result) { mock.rise }