/* notable change in character size: character was clipped
TODO: how to deal with diagonal cuts?
*/
+ msg("<trace> Character %d was clipped: (%f,%f,%f,%f) -> (%f,%f,%f,%f)",
+ glyphnr,
+ bbox.xmin,bbox.ymin,bbox.xmax,bbox.ymax,
+ bbox2.xmin,bbox2.ymin,bbox2.xmax,bbox2.ymax);
polyops_fill(dev, glyph, color);
} else {
if(i->out) i->out->drawchar(i->out, font, glyphnr, color, matrix);
class AreaNotPlain(AreaCheck):
pass
-checktypes = [PixelColorCheck,PixelBrighterThan,PixelDarkerThan,PixelEqualTo,AreaPlain,AreaNotPlain]
+class AreaText(AreaCheck):
+ def __init__(self, x,y, x2, y2, text=""):
+ AreaCheck.__init__(self,x,y,x2,y2)
+ self.text = text
+
+checktypes = [PixelColorCheck,PixelBrighterThan,PixelDarkerThan,PixelEqualTo,AreaPlain,AreaNotPlain,AreaText]
global TESTMODE
r_pixelequalto = re.compile(r"^pixel_at\(([0-9]+),([0-9]+)\).should_be_the_same_as pixel_at\(([0-9]+),([0-9]+)\)")
r_areaplain = re.compile(r"^area_at\(([0-9]+),([0-9]+),([0-9]+),([0-9]+)\).should_be_plain_colored")
r_areanotplain = re.compile(r"^area_at\(([0-9]+),([0-9]+),([0-9]+),([0-9]+)\).should_not_be_plain_colored")
+ r_areatext = re.compile(r"^area_at\(([0-9]+),([0-9]+),([0-9]+),([0-9]+)\).should_contain_text '(.*)'")
r_width = re.compile(r"^width.should be ([0-9]+)")
r_height = re.compile(r"^height.should be ([0-9]+)")
r_describe = re.compile(r"^describe \"pdf conversion\"")
if m: model.append(AreaPlain(int(m.group(1)),int(m.group(2)),int(m.group(3)),int(m.group(4))));continue
m = r_areanotplain.match(line)
if m: model.append(AreaNotPlain(int(m.group(1)),int(m.group(2)),int(m.group(3)),int(m.group(4))));continue
+ m = r_areatext.match(line)
+ if m: model.append(AreaText(int(m.group(1)),int(m.group(2)),int(m.group(3)),int(m.group(4)),m.group(5)));continue
if r_width.match(line) or r_height.match(line):
continue # compatibility
if r_describe.match(line) or r_end.match(line) or r_header.match(line):
fi.write(" area_at(%d,%d,%d,%d).should_be_plain_colored\n" % (check.x,check.y,check.x2,check.y2))
elif c == AreaNotPlain:
fi.write(" area_at(%d,%d,%d,%d).should_not_be_plain_colored\n" % (check.x,check.y,check.x2,check.y2))
+ elif c == AreaText:
+ fi.write(" area_at(%d,%d,%d,%d).should_contain_text '%s'\n" % (check.x,check.y,check.x2,check.y2,check.text))
fi.write(" end\n")
fi.write("end\n")
fi.close()
def delete(self, event):
self.model.delete(self.id2check[event.Id])
+ def text(self, event):
+ check = self.id2check[event.GetEventObject().Id]
+ check.text = event.GetString()
+
def append(self, check):
self.vbox = wx.BoxSizer(wx.VERTICAL)
self.vbox.Add(wx.StaticLine(self, -1, size=(500,-1)), 0, wx.ALL, 5)
hbox.Add(desc, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
if isinstance(check,AreaCheck):
- choices = ["is plain","is not plain"]
+ choices = ["is plain","is not plain","contains text"]
lb = wx.Choice(self, -1, (100, 50), choices = choices)
- if isinstance(check,AreaPlain):
+ hbox.Add(lb, 0, wx.ALIGN_LEFT|wx.ALL, 5)
+ if isinstance(check, AreaPlain):
setdefault(lb,0)
- else:
+ elif isinstance(check, AreaNotPlain):
setdefault(lb,1)
- hbox.Add(lb, 0, wx.ALIGN_LEFT|wx.ALL, 5)
+ else:
+ setdefault(lb,2)
+ tb = wx.TextCtrl(self, -1, check.text, size=(100, 25))
+ self.id2check[tb.Id] = check
+ self.Bind(wx.EVT_TEXT, self.text, tb)
+
+ hbox.Add(tb, 0, wx.ALIGN_LEFT|wx.ALL, 5)
elif isinstance(check,TwoPixelCheck):
choices = ["is the same as","is brighter than","is darker than"]
lb = wx.Choice(self, -1, (100, 50), choices = choices)
end
class Area
- def initialize(x1,y1,x2,y2,data)
- @x1,@y1,@x2,@y2 = x1,y1,x2,y2
- @rgb = Array.new(data.size/3) do |i| data.slice(i*3,3) end
+ def initialize(x1,y1,x2,y2,file)
+ @x1,@y1,@x2,@y2,@file = x1,y1,x2,y2,file
end
def should_be_plain_colored
+ @rgb = @file.get_area(@x1,@y1,@x2,@y2) unless @rgb
@rgb.minmax == [@rgb[0],@rgb[0]] or raise AreaError.new(self,"is not plain colored")
end
def should_not_be_plain_colored
+ @rgb = @file.get_area(@x1,@y1,@x2,@y2) unless @rgb
@rgb.minmax != [@rgb[0],@rgb[0]] or raise AreaError.new(self,"is plain colored")
end
+ def should_contain_text(text)
+ @file.get_text(@x1,@y1,@x2,@y2) == text or raise AreaError.new(self, "doesn't contain text #{text}")
+ end
def to_s
"(#{@x1},#{@y1},#{@x2},#{@y2})"
end
@filename = filename
@page = page
end
- def load()
+ def convert()
+ return if @swfname
@swfname = @filename.gsub(/.pdf$/i,"")+".swf"
+ `pdfinfo #{@filename}` =~ /Page size:\s*([0-9]+) x ([0-9]+) pts/
+ width,height = $1,$2
+ dpi = (72.0 * 612 / width.to_i).to_i
+ output = `pdf2swf --flatten -s zoom=#{dpi} -p #{@page} #{@filename} -o #{@swfname} 2>&1`
+ #output = `pdf2swf -s zoom=#{dpi} --flatten -p #{@page} #{@filename} -o #{@swfname} 2>&1`
+ raise ConversionFailed.new(output,@swfname) unless File.exists?(@swfname)
+ end
+ def render()
+ return if @img
+ convert()
@pngname = @filename.gsub(/.pdf$/i,"")+".png"
begin
- `pdfinfo #{@filename}` =~ /Page size:\s*([0-9]+) x ([0-9]+) pts/
- width,height = $1,$2
- dpi = (72.0 * 612 / width.to_i).to_i
- output = `pdf2swf -s zoom=#{dpi} --flatten -p #{@page} #{@filename} -o #{@swfname} 2>&1`
- raise ConversionFailed.new(output,@swfname) unless File.exists?(@swfname)
output = `swfrender --legacy #{@swfname} -o #{@pngname} 2>&1`
raise ConversionFailed.new(output,@pngname) unless File.exists?(@pngname)
@img = Magick::Image.read(@pngname).first
`rm -f #{@pngname}`
end
end
- def area_at(x1,y1,x2,y2)
- self.load()
+ def get_text(x1,y1,x2,y2)
+ self.convert()
+ puts "swfstrings -x #{x1} -y #{y1} -W #{x2-x1} -H #{y2-y1} #{@swfname}"
+ puts `swfstrings -x #{x1} -y #{y1} -W #{x2-x1} -H #{y2-y1} #{@swfname}`
+ `swfstrings -x #{x1} -y #{y1} -W #{x2-x1} -H #{y2-y1} #{@swfname}`
+ end
+ def get_area(x1,y1,x2,y2)
+ self.render()
data = @img.export_pixels(x1, y1, x2-x1, y2-y1, "RGB")
- return Area.new(x1,y1,x2,y2,data)
+ Array.new(data.size/3) do |i| data.slice(i*3,3) end
+ end
+ def area_at(x1,y1,x2,y2)
+ return Area.new(x1,y1,x2,y2,self)
end
def width()
- self.load()
+ self.render()
return @img.columns
end
def height()
- self.load()
+ self.render()
return @img.rows
end
def pixel_at(x,y)
- self.load()
+ self.render()
data = @img.export_pixels(x, y, 1, 1, "RGB")
return Pixel.new(x,y,data)
end
--- /dev/null
+from sys import *
+from pdflib_py import *
+import md5
+p = PDF_new()
+PDF_open_file(p, "textarea.pdf")
+
+PDF_set_parameter(p, "usercoordinates", "true")
+
+PDF_set_info(p, "Creator", "smalltext.py")
+PDF_begin_page(p, 612, 3000)
+font = PDF_load_font(p, "Courier", "host", "")
+
+PDF_setfont(p, font, 12.0)
+i = 0
+# the idea is to overflow the placetext matrix once, so that
+# we have at least two different ty values
+for y in range(3000 / 9):
+ PDF_set_text_pos(p, 0, y*9);
+ text = "".join([md5.md5(str(i+j*732849)).hexdigest() for j in range(3)])
+ print text
+ PDF_show(p, text)
+ i = i + 1
+
+PDF_end_page(p)
+PDF_close(p)
+PDF_delete(p);
--- /dev/null
+require File.dirname(__FILE__) + '/spec_helper'
+
+describe "pdf conversion" do
+ convert_file "textarea.pdf" do
+ area_at(460,94,610,106).should_contain_text '97924ff65f9dfc75450ba'
+ area_at(467,373,525,384).should_contain_text '29cf24e47'
+ area_at(474,592,543,601).should_contain_text '0afa27099a'
+ area_at(59,798,131,808).should_contain_text '4c28e489b4'
+ end
+end
printf("\n");
}
-void handleText(TAG*tag)
+void handleText(TAG*tag, char*prefix)
{
printf("\n");
- swf_ParseDefineText(tag,textcallback, 0);
+ if(placements) {
+ swf_SetTagPos(tag, 0);
+ swf_GetU16(tag);
+ swf_GetRect(tag, 0);
+ swf_ResetReadBits(tag);
+ MATRIX m;
+ swf_GetMatrix(tag, &m);
+ printf("%s| Matrix\n",prefix);
+ printf("%s| %5.3f %5.3f %6.2f\n", prefix, m.sx/65536.0, m.r1/65536.0, m.tx/20.0);
+ printf("%s| %5.3f %5.3f %6.2f\n", prefix, m.r0/65536.0, m.sy/65536.0, m.ty/20.0);
+ swf_SetTagPos(tag, 0);
+ }
+ if(showtext) {
+ swf_ParseDefineText(tag,textcallback, 0);
+ }
}
void handleDefineSound(TAG*tag)
printf(" URL: %s\n", s);
}
else if(tag->id == ST_DEFINETEXT || tag->id == ST_DEFINETEXT2) {
- if(showtext)
- handleText(tag);
- else
- printf("\n");
+ handleText(tag, myprefix);
}
else if(tag->id == ST_DEFINESCALINGGRID) {
U16 id = swf_GetU16(tag);
for(t=0;t<nr;t++)
{
- int xx = startx + advance[t]/20;
- if(x|y|w|h) {
- /* TODO: this does not do any matrix handling yet */
+ int xx = startx + advance[t];
+ int yy = starty;
+ MATRIX*m = (MATRIX*)self;
+
+ SPOINT p = {xx,yy};
+ p = swf_TurnPoint(p, m);
+ xx = p.x / 20;
+ yy = p.y / 20;
- if(xx < x || starty < y || xx > x+w || starty > y+h) {
+ if(x|y|w|h) {
+ if(xx < x || yy < y || xx > x+w || yy > y+h) {
/* outside of bounding box */
- continue;
+ ///printf("(%d+%d,%d) -> (%d,%d)\n", startx, advance[t]/20, starty, xx, yy);
+ if(t==nr-1) return;
+ else continue;
}
}
swf_FontFree(font);
}
+TAG**id2tag = 0;
int main (int argc,char ** argv)
{
if(!h) h = (swf.movieSize.ymax - swf.movieSize.ymin) / 20;
}
+ id2tag = malloc(sizeof(TAG)*65536);
+
fontnum = 0;
swf_FontEnumerate(&swf,&fontcallback1, 0);
fonts = (SWFFONT**)malloc(fontnum*sizeof(SWFFONT*));
while (tag)
{
if(swf_isTextTag(tag)) {
- swf_ParseDefineText(tag, textcallback, 0);
+ id2tag[swf_GetDefineID(tag)] = tag;
+ } else if(swf_isPlaceTag(tag)) {
+ SWFPLACEOBJECT po;
+ swf_SetTagPos(tag, 0);
+ swf_GetPlaceObject(tag, &po);
+ if(!po.move && id2tag[po.id]) {
+ TAG*text = id2tag[po.id];
+ swf_SetTagPos(text, 0);
+ swf_GetU16(text);
+ swf_GetRect(text, NULL);
+ swf_ResetReadBits(text);
+ MATRIX m,tm;
+ swf_GetMatrix(text, &tm);
+ swf_MatrixJoin(&m, &po.matrix, &tm);
+ swf_ParseDefineText(text, textcallback, &m);
+ }
}
tag = tag->next;
}