Permalink
Browse files

initial version

  • Loading branch information...
0 parents commit f0cfb774279d4dec49cbf3e2d9da4c626ddef03b @madrobby committed Sep 26, 2009
Showing with 251 additions and 0 deletions.
  1. +1 −0 .gitignore
  2. +15 −0 README
  3. +16 −0 Rakefile
  4. +70 −0 bin/textorize.rb
  5. +5 −0 lib/textorize.rb
  6. +58 −0 lib/textorize/renderer.rb
  7. +38 −0 lib/textorize/runner.rb
  8. +16 −0 lib/textorize/saver.rb
  9. +18 −0 test/test_runner.rb
  10. +14 −0 textorize.gemspec
@@ -0,0 +1 @@
+.DS_Store
15 README
@@ -0,0 +1,15 @@
+textorize produces beautifully sub-pixel-antialiased text graphics on OS X. Output format is always PNG.
+
+Usage: ./textorize.rb [options] string
+ -f, --font=[FONT] Font name
+ -s, --size=[SIZE] Font size in point
+ -l, --lineheight=[HEIGHT] Line height in point
+ -k, --kerning=[STEPS] Tighten or loosen kerning by the given amount
+ -w, --width=[WIDTH] Wrapping width in pixels
+ -o, --output=[FILENAME] Specify filename for saving
+ -b, --obliqueness=[ANGLE] Slant angle
+ -t, --stencil=[COLOR] Render background with color and stencil text
+ -r, --reverse Reverse stencil (color on transparent background)
+ -c, --color=[COLOR] Render text in specific color
+ --background=[COLOR] Render background in specific color
+ -h, --help Display this message and exit
@@ -0,0 +1,16 @@
+require "rubygems"
+require "rake/testtask"
+require "rake/gempackagetask"
+
+task :default => :test
+
+Rake::TestTask.new do |t|
+ t.libs << "test"
+ t.test_files = FileList["test/test_*.rb"]
+ t.verbose = true
+end
+
+Rake::GemPackageTask.new(eval(IO.read(File.join(File.dirname(__FILE__), "textorize.gemspec")))) do |pkg|
+ pkg.need_zip = true
+ pkg.need_tar = true
+end
@@ -0,0 +1,70 @@
+#!/usr/bin/env ruby
+require "optparse"
+require "../lib/textorize/renderer"
+require "../lib/textorize/saver"
+require "../lib/textorize/runner"
+
+options = {}
+opts = OptionParser.new do |opts|
+ opts.banner = "Usage: #$0 [options] string"
+
+ opts.on('-f', '--font=[FONT]', String, 'Font name') do |v|
+ options[:font] = v
+ end
+
+ opts.on('-s', '--size=[SIZE]', Float, 'Font size in point') do |v|
+ options[:size] = v
+ end
+
+ opts.on('-l', '--lineheight=[HEIGHT]', Float, 'Line height in point') do |v|
+ options[:lineheight] = v
+ end
+
+ opts.on('-k', '--kerning=[STEPS]', Integer, 'Tighten or loosen kerning by the given amount') do |v|
+ options[:kerning] = v
+ end
+
+ opts.on('-w', '--width=[WIDTH]', Integer, 'Wrapping width in pixels') do |v|
+ options[:width] = v
+ end
+
+ opts.on('-o', '--output=[FILENAME]', String, 'Specify filename for saving') do |v|
+ options[:output] = v
+ end
+
+ opts.on('-b', '--obliqueness=[ANGLE]', Float, 'Slant angle') do |v|
+ options[:obliqueness] = v
+ end
+
+ opts.on('-t', '--stencil=[COLOR]', String, 'Render background with color and stencil text') do |v|
+ options[:stencil] = v
+ end
+
+ opts.on('-r', '--reverse', 'Reverse stencil (color on transparent background)') do
+ options[:reverse_stencil] = true
+ end
+
+ opts.on('-c', '--color=[COLOR]', String, 'Render text in specific color') do |v|
+ options[:color] = v
+ end
+
+ opts.on('-b', '--background=[COLOR]', String, 'Render background in specific color') do |v|
+ options[:background] = v
+ end
+
+ opts.on_tail('-h', '--help', 'Display this message and exit') do
+ puts opts
+ exit
+ end
+end.parse!
+
+options[:font] ||= 'Arial'
+options[:size] ||= 28.0
+options[:kerning] ||= 0
+options[:lineheight] ||= options[:size]
+options[:output] ||= 'output.png'
+options[:strings] = ARGV.first || 'Hello World'
+options[:width] ||= 250
+options[:obliqueness] ||= 0
+
+renderer = Textorize::Runner.new(options[:strings], options[:output], options)
@@ -0,0 +1,5 @@
+$:.unshift File.dirname(__FILE__)
+
+require "textorize/runner"
+require "textorize/renderer"
+require "textorize/saver"
@@ -0,0 +1,58 @@
+require 'osx/cocoa'
+
+module Textorize
+ class Renderer
+ include OSX
+
+ def initialize(window, string, options)
+ @text_view = NSTextView.alloc.initWithFrame([0,0,1000,100])
+
+ set_attribs options
+ window.setContentView @text_view
+ @text_view.setString string
+ @text_view.sizeToFit
+
+ window.display
+ window.orderFrontRegardless
+ end
+
+ def bitmap
+ @text_view.lockFocus
+ bitmap = NSBitmapImageRep.alloc.initWithFocusedViewRect(@text_view.bounds)
+ @text_view.unlockFocus
+ bitmap
+ end
+
+ private
+
+ def set_attribs(options)
+ @text_view.setHorizontallyResizable(true)
+ @text_view.useAllLigatures(nil)
+
+ color = (options[:color] || '0,0,0').split(',')
+ fgcolor = NSColor.colorWithDeviceRed_green_blue_alpha(color[0], color[1], color[2], 1)
+ bgcolor = (options[:background] || '1,1,1').split(',')
+ @text_view.setBackgroundColor(
+ NSColor.colorWithDeviceRed_green_blue_alpha(bgcolor[0], bgcolor[1], bgcolor[2], 1)
+ )
+ @text_view.setTextColor(fgcolor)
+
+ puts @text_view.inspect
+
+ para = NSMutableParagraphStyle.alloc.init
+ para.setLineSpacing(options[:lineheight])
+
+ attribs = NSMutableDictionary.alloc.init
+ attribs.setObject_forKey(NSFont.fontWithName_size(options[:font], options[:size]), NSFontAttributeName)
+ attribs.setObject_forKey(options[:kerning], NSKernAttributeName)
+ attribs.setObject_forKey(para, NSParagraphStyleAttributeName)
+ attribs.setObject_forKey(0, NSBaselineOffsetAttributeName)
+ attribs.setObject_forKey(options[:obliqueness], NSObliquenessAttributeName)
+
+ @text_view.setTypingAttributes(attribs)
+ @text_view.lowerBaseline(nil)
+ end
+
+ end
+
+end
@@ -0,0 +1,38 @@
+require 'osx/cocoa'
+
+module Textorize
+ class Runner
+
+ def initialize(string, output, options)
+ app = OSX::NSApplication.sharedApplication
+
+ delegate = RunnerApplication.alloc.init
+ delegate.options = options
+ delegate.string = string
+ delegate.output = output
+
+ app.setDelegate delegate
+ app.run
+ end
+
+ end
+
+ class RunnerApplication < OSX::NSObject
+ include OSX
+ attr_accessor :options
+ attr_accessor :string
+ attr_accessor :output
+
+ def initialize
+ @window = NSWindow.alloc.initWithContentRect_styleMask_backing_defer([150, 1500, 1000, 500], NSBorderlessWindowMask, 2, 0)
+ end
+
+ def applicationDidFinishLaunching(notification)
+ renderer = Renderer.new(@window, @string, @options)
+ Saver.new(renderer).write_to_file(@output)
+ NSApplication.sharedApplication.terminate(nil)
+ end
+
+ end
+
+end
@@ -0,0 +1,16 @@
+module Textorize
+ class Saver
+ include OSX
+ attr_reader :png
+
+ def initialize(renderer)
+ bitmap = renderer.bitmap
+ @png = bitmap.representationUsingType_properties(NSPNGFileType, nil)
+ end
+
+ def write_to_file(file)
+ @png.writeToFile_atomically(file, true)
+ end
+
+ end
+end
@@ -0,0 +1,18 @@
+require File.join(File.dirname(__FILE__), *%w".. lib textorize")
+require "test/unit"
+
+class RunnerTest < Test::Unit::TestCase
+
+ def test_runner
+ options = {}
+ options[:font] ||= 'Arial'
+ options[:size] ||= 28.0
+ options[:kerning] ||= 0
+ options[:lineheight] ||= options[:size]
+ options[:width] ||= 250
+ options[:obliqueness] ||= 0
+
+ Textorize::Runner.new 'Hallo!', 'output.png', options
+ end
+
+end
@@ -0,0 +1,14 @@
+Gem::Specification.new do |s|
+ s.name = "textorize"
+ s.version = "0.0.1"
+ s.date = "2009-05-15"
+ s.summary = "OS X sub-pixel-antialiased PNG string renderer."
+ s.email = "thomas@fesch.at"
+ s.homepage = "http://github.com/madrobby/textorize"
+ s.description = "Textorize is a OS X utility to render sub-pixel-antialised strings into PNG files."
+ s.has_rdoc = false
+ s.authors = ["Thomas Fuchs"]
+ s.files = Dir["Rakefile", "bin/**/*", "lib/**/*", "test/**/*"]
+ s.test_files = Dir["test/test_*.rb"] unless $SAFE > 0
+ s.executables = ["textorize"]
+end

0 comments on commit f0cfb77

Please sign in to comment.