Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial commit of glyphr

  • Loading branch information...
commit 4d0fbbfe8fcaf3bddca0dd29127a79ad76a470e5 0 parents
@pepe pepe authored
5 .document
@@ -0,0 +1,5 @@
+lib/**/*.rb
+bin/*
+-
+features/**/*.feature
+LICENSE.txt
1  .rspec
@@ -0,0 +1 @@
+--color
1  .rvmrc
@@ -0,0 +1 @@
+rvm --create 1.9.2@glyphr
13 Gemfile
@@ -0,0 +1,13 @@
+source "http://rubygems.org"
+
+gem 'oily_png'
+gem 'ft2-ruby'
+
+# Add dependencies to develop your gem here.
+# Include everything needed to run rake, tests, features, etc.
+group :development do
+ gem "rspec", "~> 2.3.0"
+ gem "bundler", "~> 1.0.0"
+ gem "jeweler", "~> 1.5.2"
+ gem "rcov", ">= 0"
+end
34 Gemfile.lock
@@ -0,0 +1,34 @@
+GEM
+ remote: http://rubygems.org/
+ specs:
+ chunky_png (1.1.0)
+ diff-lcs (1.1.2)
+ ft2-ruby (0.1.3)
+ git (1.2.5)
+ jeweler (1.5.2)
+ bundler (~> 1.0.0)
+ git (>= 1.2.5)
+ rake
+ oily_png (1.0.0)
+ chunky_png (~> 1.0)
+ rake (0.8.7)
+ rcov (0.9.9)
+ rspec (2.3.0)
+ rspec-core (~> 2.3.0)
+ rspec-expectations (~> 2.3.0)
+ rspec-mocks (~> 2.3.0)
+ rspec-core (2.3.1)
+ rspec-expectations (2.3.0)
+ diff-lcs (~> 1.1.2)
+ rspec-mocks (2.3.0)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ bundler (~> 1.0.0)
+ ft2-ruby
+ jeweler (~> 1.5.2)
+ oily_png
+ rcov
+ rspec (~> 2.3.0)
20 LICENSE.txt
@@ -0,0 +1,20 @@
+Copyright (c) 2011 Josef Pospíšil
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 README.rdoc
@@ -0,0 +1,26 @@
+= glyphr
+
+Simple library for accessing font file through freetype (and ft2-ruby)
+library.
+
+Planned functions:
+
+* Rendering to PNG (implemented)
+* All typeface informations
+* Charmaps specimen rendering
+
+== Contributing to glyphr
+
+* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
+* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
+* Fork the project
+* Start a feature/bugfix branch
+* Commit and push until you are happy with your contribution
+* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
+* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
+
+== Copyright
+
+Copyright (c) 2011 Josef Pospíšil. See LICENSE.txt for
+further details.
+
55 Rakefile
@@ -0,0 +1,55 @@
+#encoding: utf-8
+require 'rubygems'
+require 'bundler'
+begin
+ Bundler.setup(:default, :development)
+rescue Bundler::BundlerError => e
+ $stderr.puts e.message
+ $stderr.puts "Run `bundle install` to install missing gems"
+ exit e.status_code
+end
+require 'rake'
+
+require 'jeweler'
+Jeweler::Tasks.new do |gem|
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
+ gem.name = "glyphr"
+ gem.homepage = "http://github.com/pepe/glyphr"
+ gem.license = "MIT"
+ gem.summary = %Q{Library for font manipulation in ruby}
+ gem.description = %Q{Library for rendering png images from otf font files, and general manipulation and info gathering from font file. Only rendering part is done and only on basic level.}
+ gem.email = "josef.pospisil@laststar.eu"
+ gem.authors = ["Josef Pospíšil"]
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
+ gem.add_runtime_dependency 'ft2-ruby', '~> 0.1.3'
+ gem.add_runtime_dependency 'oily_png', '~> 1.0.0'
+ gem.add_development_dependency 'rspec', '~> 2.5.0'
+ gem.add_development_dependency 'bundler', '~> 1.0.0'
+ gem.add_development_dependency 'jeweler', '~> 1.0.0'
+ gem.add_development_dependency 'rcov', '>= 0'
+end
+Jeweler::RubygemsDotOrgTasks.new
+
+require 'rspec/core'
+require 'rspec/core/rake_task'
+RSpec::Core::RakeTask.new(:spec) do |spec|
+ spec.pattern = FileList['spec/**/*_spec.rb']
+end
+
+RSpec::Core::RakeTask.new(:rcov) do |spec|
+ spec.pattern = 'spec/**/*_spec.rb'
+ spec.rcov = true
+end
+
+task :default => :spec
+
+require 'rake/rdoctask'
+Rake::RDocTask.new do |rdoc|
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
+
+ rdoc.rdoc_dir = 'rdoc'
+ rdoc.title = "text_renderer #{version}"
+ rdoc.rdoc_files.include('README*')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+end
1  VERSION
@@ -0,0 +1 @@
+0.0.0
92 lib/glyphr.rb
@@ -0,0 +1,92 @@
+require 'oily_png'
+require 'ft2'
+
+module Glyphr
+ class Renderer
+ attr_accessor :font, :size, :image_size
+ attr_reader :face, :image, :hinting
+
+ POINT_FRACTION = 26.6
+ RESOLUTION = 72
+ LEFT_MARGIN = 10
+
+ def initialize(font = nil, size = 36)
+ @font = font
+ @size = size
+ if font
+ setup_ft
+ end
+ end
+
+ def render(*composition)
+ return false if not image_size or not composition
+ reset_image
+ x = LEFT_MARGIN
+ if composition.size == 1 && composition.first.is_a?(String)
+ composition = glyphs_array_from(composition.first)
+ end
+
+ composition.each do |glyph_code|
+ face.load_glyph(glyph_code, FT2::Load::NO_HINTING)
+ glyph = face.glyph.render(FT2::RenderMode::NORMAL)
+ if x + glyph.h_advance < image_width
+ if glyph.bitmap.width > 0
+ image_compose x, glyph
+ end
+ x = x + glyph.h_advance
+ else
+ break
+ end
+ end
+
+ readjust_image(image_width, image_height)
+ return true
+ end
+
+ def reset_image
+ @image = ChunkyPNG::Image.new(image_width, image_height, ChunkyPNG::Color::WHITE)
+ end
+
+ def image
+ return @image
+ end
+
+ def image_height
+ @image_height ||= image_size.split('x').last.to_i
+ end
+
+ def image_width
+ @image_width ||= image_size.split('x').first.to_i
+ end
+
+ #TODO move to its own class for font info
+ def glyphs_array_from(text)
+ arr = []
+ text.each_codepoint do |c|
+ arr << face.char_index(c)
+ end
+ return arr
+ end
+
+ private
+ # sets up all attributes of freetype
+ def setup_ft
+ unless face
+ @face = FT2::Face.load(@font)
+ face.select_charmap(FT2::Encoding::UNICODE)
+ face.set_char_size size * POINT_FRACTION * (RESOLUTION/POINT_FRACTION), size * POINT_FRACTION * (RESOLUTION/POINT_FRACTION), RESOLUTION, RESOLUTION
+ end
+ end
+
+ def image_compose(x, glyph)
+ @image = @image.compose(ChunkyPNG::Image.new(glyph.bitmap.width, glyph.bitmap.rows, glyph.bitmap.buffer.bytes.to_a),
+ x + glyph.bitmap_left,
+ size - glyph.bitmap_top)
+ end
+
+ # it readjust image in size and colors
+ def readjust_image(width, height)
+ @image.crop(0, 0, width, height)
+ end
+ end
+end
BIN  spec/fixtures/Metalista.otf
Binary file not shown
BIN  spec/fixtures/output.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
111 spec/glyphr_spec.rb
@@ -0,0 +1,111 @@
+require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
+require File.expand_path(File.dirname(__FILE__) + '/../lib/glyphr')
+
+describe Glyphr::Renderer do
+ it 'can be initiated' do
+ Glyphr::Renderer.new.should_not be_nil
+ end
+ it 'can be initiated with font and size' do
+ Glyphr::Renderer.new(font_file, 36).should_not be_nil
+ end
+
+ context 'Initialized' do
+ let (:renderer) {Glyphr::Renderer.new(font_file, 36)}
+ it 'returns font' do
+ renderer.font.should == font_file
+ end
+ it 'returns size' do
+ renderer.size.should == 36
+ end
+ end
+ context 'Rendering' do
+ let (:renderer) {Glyphr::Renderer.new(font_file, 36)}
+ it 'accepts image size' do
+ renderer.image_size = '10x10'
+ renderer.image_size.should == '10x10'
+ end
+ it 'returns image width' do
+ renderer.image_size = '10x20'
+ renderer.image_width.should == 10
+ end
+ it 'returns image height' do
+ renderer.image_size = '10x20'
+ renderer.image_height.should == 20
+ end
+ it 'render method accepts text' do
+ renderer.render('Hello world')
+ end
+ it 'returns false for render when image size not set' do
+ renderer.render('Hello world').should be_false
+ end
+ it 'returns true for render when image size set' do
+ renderer.image_size = '10x10'
+ renderer.render('Hello world').should be_true
+ end
+ it 'returns nil for image when not rendered' do
+ renderer.image.should be_nil
+ end
+ end
+ context 'After rendering' do
+ let (:renderer) {Glyphr::Renderer.new(font_file, 36)}
+ before do
+ renderer.image_size = '10x10'
+ renderer.render('Hello world')
+ end
+
+ it 'returns image when rendered' do
+ renderer.image.should_not be_nil
+ end
+ it 'returns Chunky PNG image with after render' do
+ renderer.image.should be_kind_of ChunkyPNG::Canvas
+ end
+ it 'can reset image' do
+ renderer.reset_image
+ end
+ end
+ context 'With freetype' do
+ let (:renderer) {Glyphr::Renderer.new(font_file, 36)}
+
+ it 'has freetype face for font' do
+ renderer.face.should be_kind_of FT2::Face
+ end
+ it 'return glyphs count' do
+ renderer.face.glyphs.should == 367
+ end
+ end
+ context 'Comparing output' do
+ let(:renderer) {renderer = Glyphr::Renderer.new("spec/fixtures/metalista.otf", 72)}
+ before do
+ renderer.image_size = '340x80'
+ renderer.render('hello world')
+ end
+ it 'should render same image as in fixture' do
+ renderer.image.save('output.png')
+ FileUtils.compare_file('output.png', 'spec/fixtures/output.png').should be_true
+ end
+
+ after do
+ FileUtils.rm('output.png')
+ end
+ end
+ context 'Rendering array of glyphs' do
+ let(:renderer) {renderer = Glyphr::Renderer.new("spec/fixtures/metalista.otf", 72)}
+ before do
+ renderer.image_size = '340x80'
+ renderer.render(11, 133, 140, 140, 143, 3, 26, 143, 146, 140, 132)
+ end
+ it 'should render same image as in fixture' do
+ renderer.image.save('output.png')
+ FileUtils.compare_file('output.png', 'spec/fixtures/output.png').should be_true
+ end
+ it 'should render just one glyph' do
+ renderer.render(11).should be_true
+ end
+ end
+ context 'Converting text to glyphs array' do
+ let(:renderer) {renderer = Glyphr::Renderer.new("spec/fixtures/metalista.otf", 72)}
+ it 'converts string to glyphs array' do
+ renderer.glyphs_array_from('Hello World').should == [11, 133, 140, 140, 143, 3, 26, 143, 146, 140, 132]
+ end
+ end
+end
19 spec/spec_helper.rb
@@ -0,0 +1,19 @@
+$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
+$LOAD_PATH.unshift(File.dirname(__FILE__))
+require 'rspec'
+require 'fileutils'
+
+require 'glyphr'
+
+# Requires supporting files with custom matchers and macros, etc,
+# in ./support/ and its subdirectories.
+Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
+
+RSpec.configure do |config|
+
+end
+
+def font_file
+ @font_file ||= File.join(File.dirname(__FILE__), '/fixtures/Metalista.otf')
+end
+
110 spec/text_renderer_spec.rb
@@ -0,0 +1,110 @@
+require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
+
+describe Glyphr::Renderer do
+ it 'can be initiated' do
+ Glyphr::Renderer.new.should_not be_nil
+ end
+ it 'can be initiated with font and size' do
+ Glyphr::Renderer.new(font_file, 36).should_not be_nil
+ end
+
+ context 'Initialized' do
+ let (:renderer) {Glyphr::Renderer.new(font_file, 36)}
+ it 'returns font' do
+ renderer.font.should == font_file
+ end
+ it 'returns size' do
+ renderer.size.should == 36
+ end
+ end
+ context 'Rendering' do
+ let (:renderer) {Glyphr::Renderer.new(font_file, 36)}
+ it 'accepts image size' do
+ renderer.image_size = '10x10'
+ renderer.image_size.should == '10x10'
+ end
+ it 'returns image width' do
+ renderer.image_size = '10x20'
+ renderer.image_width.should == 10
+ end
+ it 'returns image height' do
+ renderer.image_size = '10x20'
+ renderer.image_height.should == 20
+ end
+ it 'render method accepts text' do
+ renderer.render('Hello world')
+ end
+ it 'returns false for render when image size not set' do
+ renderer.render('Hello world').should be_false
+ end
+ it 'returns true for render when image size set' do
+ renderer.image_size = '10x10'
+ renderer.render('Hello world').should be_true
+ end
+ it 'returns nil for image when not rendered' do
+ renderer.image.should be_nil
+ end
+ end
+ context 'After rendering' do
+ let (:renderer) {Glyphr::Renderer.new(font_file, 36)}
+ before do
+ renderer.image_size = '10x10'
+ renderer.render('Hello world')
+ end
+
+ it 'returns image when rendered' do
+ renderer.image.should_not be_nil
+ end
+ it 'returns Chunky PNG image with after render' do
+ renderer.image.should be_kind_of ChunkyPNG::Canvas
+ end
+ it 'can reset image' do
+ renderer.reset_image
+ end
+ end
+ context 'With freetype' do
+ let (:renderer) {Glyphr::Renderer.new(font_file, 36)}
+
+ it 'has freetype face for font' do
+ renderer.face.should be_kind_of FT2::Face
+ end
+ it 'return glyphs count' do
+ renderer.face.glyphs.should == 367
+ end
+ end
+ context 'Comparing output' do
+ let(:renderer) {renderer = Glyphr::Renderer.new("spec/fixtures/metalista.otf", 72)}
+ before do
+ renderer.image_size = '340x80'
+ renderer.render('hello world')
+ end
+ it 'should render same image as in fixture' do
+ renderer.image.save('output.png')
+ FileUtils.compare_file('output.png', 'spec/fixtures/output.png').should be_true
+ end
+
+ after do
+ FileUtils.rm('output.png')
+ end
+ end
+ context 'Rendering array of glyphs' do
+ let(:renderer) {renderer = Glyphr::Renderer.new("spec/fixtures/metalista.otf", 72)}
+ before do
+ renderer.image_size = '340x80'
+ renderer.render(11, 133, 140, 140, 143, 3, 26, 143, 146, 140, 132)
+ end
+ it 'should render same image as in fixture' do
+ renderer.image.save('output.png')
+ FileUtils.compare_file('output.png', 'spec/fixtures/output.png').should be_true
+ end
+ it 'should render just one glyph' do
+ renderer.render(11).should be_true
+ end
+ end
+ context 'Converting text to glyphs array' do
+ let(:renderer) {renderer = Glyphr::Renderer.new("spec/fixtures/metalista.otf", 72)}
+ it 'converts string to glyphs array' do
+ renderer.glyphs_array_from('Hello World').should == [11, 133, 140, 140, 143, 3, 26, 143, 146, 140, 132]
+ end
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.