From e63c0b1326149cf95339d29f4fab2315d52b14dd Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Sat, 20 Sep 2014 15:36:04 -0400 Subject: [PATCH 1/4] Parse bitmap data from sbix tables --- lib/ttfunk.rb | 7 +++++- lib/ttfunk/table/sbix.rb | 53 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 lib/ttfunk/table/sbix.rb diff --git a/lib/ttfunk.rb b/lib/ttfunk.rb index 27177179..1a4f5e48 100644 --- a/lib/ttfunk.rb +++ b/lib/ttfunk.rb @@ -106,7 +106,11 @@ def glyph_locations def glyph_outlines @glyph_outlines ||= TTFunk::Table::Glyf.new(self) end - end + + def sbix + @sbix ||= TTFunk::Table::Sbix.new(self) + end + end end require_relative "ttfunk/table/cmap" @@ -120,3 +124,4 @@ def glyph_outlines require_relative "ttfunk/table/name" require_relative "ttfunk/table/os2" require_relative "ttfunk/table/post" +require_relative "ttfunk/table/sbix" diff --git a/lib/ttfunk/table/sbix.rb b/lib/ttfunk/table/sbix.rb new file mode 100644 index 00000000..827d00d6 --- /dev/null +++ b/lib/ttfunk/table/sbix.rb @@ -0,0 +1,53 @@ +require_relative '../table' + +module TTFunk + class Table + class Sbix < Table + attr_reader :version + attr_reader :flags + attr_reader :num_strikes + attr_reader :strikes + + BitmapData = Struct.new(:x, :x, :type, :data, :ppem, :resolution) + + def bitmap_data_for(glyph_id, strike_index) + return unless strike = strikes[strike_index] + + glyph_offset = strike[:glyph_data_offset][glyph_id] + next_glyph_offset = strike[:glyph_data_offset][glyph_id + 1] + + if glyph_offset && next_glyph_offset + bytes = next_glyph_offset - glyph_offset + if bytes > 0 + parse_from(offset + strike[:offset] + glyph_offset) do + x, y, type = read(8, "s2A4") + data = StringIO.new(io.read(bytes - 8)) + BitmapData.new(x, y, type, data, strike[:ppem], strike[:resolution]) + end + end + end + end + + def all_bitmap_data_for(glyph_id) + strikes.each_index.map do |strike_index| + bitmap_data_for(glyph_id, strike_index) + end.compact + end + + private + + def parse! + @version, @flags, @num_strikes = read(8, "n2N") + strike_offsets = num_strikes.times.map { read(4, "N").first } + + @strikes = strike_offsets.map do |strike_offset| + parse_from(offset + strike_offset) do + ppem, resolution = read(4, "n2") + data_offsets = (file.maximum_profile.num_glyphs + 1).times.map { read(4, "N").first } + { ppem: ppem, resolution: resolution, offset: strike_offset, glyph_data_offset: data_offsets } + end + end + end + end + end +end From 8f32bef9fcf33649bff6d420e763208c0fb58747 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Sat, 20 Sep 2014 16:10:46 -0400 Subject: [PATCH 2/4] Remove assignment from condition --- lib/ttfunk/table/sbix.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/ttfunk/table/sbix.rb b/lib/ttfunk/table/sbix.rb index 827d00d6..c28ba3de 100644 --- a/lib/ttfunk/table/sbix.rb +++ b/lib/ttfunk/table/sbix.rb @@ -11,7 +11,8 @@ class Sbix < Table BitmapData = Struct.new(:x, :x, :type, :data, :ppem, :resolution) def bitmap_data_for(glyph_id, strike_index) - return unless strike = strikes[strike_index] + strike = strikes[strike_index] + return if strike.nil? glyph_offset = strike[:glyph_data_offset][glyph_id] next_glyph_offset = strike[:glyph_data_offset][glyph_id + 1] From 9ef73c9d912935b43de43ced2f3d6ade6b40c77a Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Sat, 20 Sep 2014 17:11:55 -0400 Subject: [PATCH 3/4] Fix duplicated member name --- lib/ttfunk/table/sbix.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ttfunk/table/sbix.rb b/lib/ttfunk/table/sbix.rb index c28ba3de..c5f16ff3 100644 --- a/lib/ttfunk/table/sbix.rb +++ b/lib/ttfunk/table/sbix.rb @@ -8,7 +8,7 @@ class Sbix < Table attr_reader :num_strikes attr_reader :strikes - BitmapData = Struct.new(:x, :x, :type, :data, :ppem, :resolution) + BitmapData = Struct.new(:x, :y, :type, :data, :ppem, :resolution) def bitmap_data_for(glyph_id, strike_index) strike = strikes[strike_index] From a55ba919f26b67a4e910f5f01c334762789637a8 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Sat, 20 Sep 2014 17:12:49 -0400 Subject: [PATCH 4/4] Add tests for sbix table --- spec/fonts/ColorTestSbix.ttf | Bin 0 -> 31668 bytes spec/integration/file_spec.rb | 30 ++++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100755 spec/fonts/ColorTestSbix.ttf diff --git a/spec/fonts/ColorTestSbix.ttf b/spec/fonts/ColorTestSbix.ttf new file mode 100755 index 0000000000000000000000000000000000000000..75f9cba2d46e4aa8783d0defbeda9e13cab7d89e GIT binary patch literal 31668 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 TB>t1AwTiGk+ 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 literal 0 HcmV?d00001 diff --git a/spec/integration/file_spec.rb b/spec/integration/file_spec.rb index 1a2bded7..cf850ebe 100644 --- a/spec/integration/file_spec.rb +++ b/spec/integration/file_spec.rb @@ -115,3 +115,33 @@ it "should extract the correct value" end end + +describe TTFunk::File, "#sbix" do + + context "with ColorTestSbix" do + # Thank you http://typophile.com/node/103268 for ColorTestSbix.ttf + let!(:file) { TTFunk::File.open(test_font("ColorTestSbix"))} + + it "should should extract headers" do + expect(file.sbix.version).to eq(1) + expect(file.sbix.flags).to eq(1) + expect(file.sbix.num_strikes).to eq(1) + end + + it "should extract bitmap data given a glyph id and strike index" do + bitmap = file.sbix.bitmap_data_for(4, 0) + expect(bitmap.x).to eq(0) + expect(bitmap.y).to eq(0) + expect(bitmap.type).to eq("png") + expect(bitmap.data.read).to match(/IHDR.*ImageReady.*IEND/m) + expect(bitmap.ppem).to eq(150) + expect(bitmap.resolution).to eq(72) + end + + it "should extract an array of all bitmap data given a glyph id" do + all_bitmaps = file.sbix.all_bitmap_data_for(4) + expect(all_bitmaps.size).to eq(1) + expect(all_bitmaps[0].ppem).to eq(150) + end + end +end