new parameter -s textonly
[swftools.git] / spec / spec_helper.rb
1 require 'spec'
2 require 'rubygems'
3 require 'RMagick'
4
5 class WrongColor < Exception
6   def initialize(pixel)
7     @pixel = pixel
8   end
9   def to_s
10     "Wrong color at #{@pixel}"
11   end
12 end
13 class AreaError < Exception
14   def initialize(area,problem)
15     @area,@problem = area,problem
16   end
17   def to_s
18     "Area at #{@area} #{@problem}"
19   end
20 end
21 class PixelError < Exception
22   def initialize(p1, relation,p2)
23     @p1,@p2,@relation = p1,p2,relation
24   end
25   def to_s
26     "Pixel #{@p1} #{@relation} #{@p2}"
27   end
28 end
29 class ConversionFailed < Exception
30   def initialize(output,file)
31     @output = output
32     @file = file
33     @exists = File.exists?(file)
34   end
35   def to_s
36     puts "-"*26+" Conversion failed "+"-"*27
37     (puts @output) if @output
38     puts "file #{@file} doesn't exist" if not @exists
39     puts "-"*72
40   end
41 end
42
43 class Area
44   def initialize(x1,y1,x2,y2,file)
45     @x1,@y1,@x2,@y2,@file = x1,y1,x2,y2,file
46   end
47   def should_be_plain_colored
48     @rgb = @file.get_area(@x1,@y1,@x2,@y2) unless @rgb
49     @rgb.min == @rgb.max or raise AreaError.new(self,"is not plain colored")
50   end
51   def should_not_be_plain_colored
52     @rgb = @file.get_area(@x1,@y1,@x2,@y2) unless @rgb
53     @rgb.min != @rgb.max or raise AreaError.new(self,"is plain colored")
54   end
55   def should_contain_text(text)
56     text2 = @file.get_text(@x1,@y1,@x2,@y2) 
57     text2 == text or raise AreaError.new(self, "doesn't contain text \"#{text}\" (found: \"#{text2}\")")
58   end
59   def should_contain_link(url)
60     links = @file.get_links(@x1,@y1,@x2,@y2) 
61     (links & [url]).empty? and raise AreaError.new(self, "doesn't contain url \"#{url}\"")
62   end
63   def to_s
64     "(#{@x1},#{@y1},#{@x2},#{@y2})"
65   end
66 end
67
68 def rgb_to_int(rgb)
69   # ImageMagick rgb triples are 16 bit
70   (rgb.reverse+[0]).map {|c| c>>8}.pack("CCCC").unpack("i")[0]
71 end
72
73 class Pixel
74   attr :rgb
75   def initialize(x,y,rgb)
76     @x,@y,@rgb = x,y,rgb
77   end
78   def should_be_of_color(color2)
79     color1 = rgb_to_int(@rgb)
80     color1 == color2 or raise WrongColor.new(self)
81   end
82   def should_be_brighter_than(pixel)
83     gray1 = @rgb.inject(0) {|sum,e| sum+e}
84     gray2 = pixel.rgb.inject(0) {|sum,e| sum+e}
85     gray1 > gray2 or raise PixelError.new(self,"is not brighter than",pixel)
86   end
87   def should_be_darker_than(pixel)
88     gray1 = @rgb.inject(0) {|sum,e| sum+e}
89     gray2 = pixel.rgb.inject(0) {|sum,e| sum+e}
90     gray1 < gray2 or raise PixelError.new(self,"is not less bright than",pixel)
91   end
92   def should_be_the_same_as(pixel)
93     @rgb == pixel.rgb or raise PixelError.new(self,"is not the same as",pixel)
94   end
95   def to_s
96     "(#{@x},#{@y})"
97   end
98 end
99
100 $tempfiles = []
101 Kernel.at_exit do
102   $tempfiles.each do |file|
103     `rm -f #{file}`
104   end
105 end
106
107 class DocFile
108   def initialize(filename, page)
109     @filename = filename
110     @page = page
111   end
112   def convert()
113     return if @swfname
114     @swfname = @filename.gsub(/.pdf$/i,"")+".swf"
115     $tempfiles += [@swfname]
116     `pdfinfo #{@filename}` =~ /Page size:\s*([0-9]+) x ([0-9]+) pts/
117     width,height = $1,$2
118     dpi = (72.0 * 612 / width.to_i).to_i
119     output = `pdf2swf -f --flatten -s zoom=#{dpi} -p #{@page} #{@filename} -o #{@swfname} 2>&1`
120     #output = `pdf2swf -s zoom=#{dpi} --flatten -p #{@page} #{@filename} -o #{@swfname} 2>&1`
121     raise ConversionFailed.new(output,@swfname) unless File.exists?(@swfname)
122   end
123   def render()
124     return if @img
125     convert()
126     @pngname = @filename.gsub(/.pdf$/i,"")+".png"
127     begin
128       output = `swfrender #{@swfname} -o #{@pngname} 2>&1`
129       raise ConversionFailed.new(output,@pngname) unless File.exists?(@pngname)
130       @img = Magick::Image.read(@pngname).first
131     ensure
132       `rm -f #{@pngname}`
133     end
134   end
135   def get_text(x1,y1,x2,y2)
136     self.convert()
137     #puts "swfstrings -x #{x1} -y #{y1} -W #{x2-x1} -H #{y2-y1} #{@swfname}"
138     #puts `swfstrings -x #{x1} -y #{y1} -W #{x2-x1} -H #{y2-y1} #{@swfname}`
139     `swfstrings -x #{x1} -y #{y1} -W #{x2-x1} -H #{y2-y1} #{@swfname}`.chomp
140   end
141   def get_links(x1,y1,x2,y2)
142     self.convert()
143         t = `swfdump -a #{@swfname}`
144         links = t.scan(/GetUrl2? URL:"([^"]*)"/).inject([]) do |a,u| a + u end
145         t.scan(/name "url:([^"]*)"/).inject(links) do |a,u| a + u end
146   end
147   def get_area(x1,y1,x2,y2)
148     self.render()
149     data = @img.export_pixels(x1, y1, x2-x1, y2-y1, "RGB")
150     Array.new(data.size/3) { |i| data.slice(i*3,3) }
151   end
152   def area_at(x1,y1,x2,y2)
153     return Area.new(x1,y1,x2,y2,self)
154   end
155   def width()
156     self.render()
157     return @img.columns
158   end
159   def height()
160     self.render()
161     return @img.rows
162   end
163   def pixel_at(x,y)
164     self.render()
165     data = @img.export_pixels(x, y, 1, 1, "RGB")
166     return Pixel.new(x,y,data)
167   end
168 end
169
170 module  Spec::Example::ExampleGroupMethods 
171   alias :convert_file :example
172 end
173
174 class FileExampleGroup < Spec::Example::ExampleGroup
175   def area_at(x1,y1,x2,y2)
176     @file.area_at(x1,y1,x2,y2)
177   end
178   def width
179     @file.width
180   end
181   def height
182     @file.height
183   end
184   def pixel_at(x,y)
185     @file.pixel_at(x,y)
186   end  
187 end
188
189 Spec::Example::ExampleGroupFactory.default(FileExampleGroup)
190
191 Spec::Runner.configure do |config|
192   config.before do
193     input_file = File.join(File.dirname(__FILE__), description)
194     raise "Cannot find input file #{input_file}" unless File.exists?(input_file)
195     @file = DocFile.new(input_file, 1)
196   end
197 end