GList<DjVuTXT::Zone *> DjVuTXT::find_text_in_rect(GRect target_rect, GUTF8String &text) const // returns a list of zones of type WORD in the nearest/selected paragraph { GList<Zone *> zone_list; GList<Zone *> lines; get_zones((int)PARAGRAPH, &page_zone, zone_list); // it's possible that no paragraph structure exists for reasons that // 1) ocr engine is not capable 2) file was modified by user. In such case, // we can only make a rough guess, i.e., select all the lines intersected with // target_rect if (zone_list.isempty()) { get_zones((int)LINE, &page_zone, zone_list); GPosition pos; for(pos=zone_list; pos; ++pos) { GRect rect=zone_list[pos]->rect; int h0=rect.height()/2; if(rect.intersect(rect,target_rect) && rect.height()>h0) lines.append(zone_list[pos]); } } else { GPosition pos, pos_sel=zone_list; float ar=0; for(pos=zone_list; pos; ++pos) { GRect rect=zone_list[pos]->rect; int area=rect.area(); if (rect.intersect(rect, target_rect)) { float ftmp=rect.area()/(float)area; if ( !ar || ar<ftmp ) { ar=ftmp; pos_sel=pos; } } } Zone *parag = 0; if ( ar>0 ) parag=zone_list[pos_sel]; zone_list.empty(); if ( ar>0 ) { get_zones((int)LINE, parag, zone_list); if ( !zone_list.isempty() ) { for(GPosition pos=zone_list; pos; ++pos) { GRect rect=zone_list[pos]->rect; int h0=rect.height()/2; if(rect.intersect(rect,target_rect) && rect.height()>h0) lines.append(zone_list[pos]); } } } } zone_list.empty(); if (!lines.isempty()) { int i=1, lsize=lines.size(); GList<Zone *> words; for (GPosition pos=lines; pos; ++pos, ++i) { words.empty(); get_zones((int)WORD, lines[pos], words); if ( lsize==1 ) { for(GPosition p=words;p;++p) { GRect rect=words[p]->rect; if(rect.intersect(rect,target_rect)) //if (target_rect.contains(words[p]->rect)) zone_list.append(words[p]); } } else { if (i==1) { bool start=true; for(GPosition p=words; p; ++p) { if ( start ) { GRect rect=words[p]->rect; if(rect.intersect(rect,target_rect)) //if (target_rect.contains(words[p]->rect)) { start=false; zone_list.append(words[p]); } } else zone_list.append(words[p]); } } else if (i==lsize) { bool end=true; for(GPosition p=words.lastpos();p;--p) { if ( end ) { GRect rect=words[p]->rect; if(rect.intersect(rect,target_rect)) //if(target_rect.contains(words[p]->rect) ) { end=false; zone_list.append(words[p]); } } else zone_list.append(words[p]); } } if (i!=1 && i!=lsize ) { for(GPosition p=words;p;++p) zone_list.append(words[p]); } } } } return zone_list; }
void lt_XMLParser::Impl::ChangeAnno( const int width, const int height, DjVuFile &dfile, const lt_XMLTags &map ) { dfile.resume_decode(true); const GP<DjVuInfo> info(dfile.info); const GP<DjVuAnno> ganno(DjVuAnno::create()); DjVuAnno &anno=*ganno; GPosition map_pos; map_pos=map.contains(areatag); if(dfile.contains_anno()) { GP<ByteStream> annobs=dfile.get_merged_anno(); if(annobs) { anno.decode(annobs); if(anno.ant && info) { anno.ant->map_areas.empty(); } } // dfile.remove_anno(); } if(info && map_pos) { const int h=info->height; const int w=info->width; double ws=1.0; double hs=1.0; if(width && width != w) { ws=((double)w)/((double)width); } if(height && height != h) { hs=((double)h)/((double)height); } if(!anno.ant) { anno.ant=DjVuANT::create(); } GPList<GMapArea> &map_areas=anno.ant->map_areas; map_areas.empty(); GPList<lt_XMLTags> gareas=map[map_pos]; for(GPosition pos=gareas;pos;++pos) { if(gareas[pos]) { lt_XMLTags &areas=*(gareas[pos]); GMap<GUTF8String,GUTF8String> args(areas.get_args()); GList<int> coords; // ****************************************************** // Parse the coords attribute: first read the raw data into // a list, then scale the x, y data into another list. For // circles, you also get a radius element with (looks like an x // with no matching y). // ****************************************************** { GPosition coords_pos=args.contains("coords"); if(coords_pos) { GList<int> raw_coords; intList(args[coords_pos],raw_coords); for(GPosition raw_pos=raw_coords;raw_pos;++raw_pos) { const int r=raw_coords[raw_pos]; const int x=(int)(ws*(double)r+0.5); coords.append(x); int y=h-1; if(! ++raw_pos) { y-=(int)(hs*(double)r+0.5); }else { y-=(int)(hs*(double)raw_coords[raw_pos]+0.5); } coords.append(y); // DjVuPrintMessage("Coords (%d,%d)\n",x,y); } } } GUTF8String shape; { GPosition shape_pos=args.contains("shape"); if(shape_pos) { shape=args[shape_pos]; } } GP<GMapArea> a; if(shape == "default") { GRect rect(0,0,w,h); a=GMapRect::create(rect); }else if(!shape.length() || shape == "rect") { int xx[4]; int i=0; for(GPosition rect_pos=coords;(rect_pos)&&(i<4);++rect_pos,++i) { xx[i]=coords[rect_pos]; } if(i!=4) { G_THROW( ERR_MSG("XMLAnno.bad_rect") ); } int xmin,xmax; if(xx[0]>xx[2]) { xmax=xx[0]; xmin=xx[2]; }else { xmin=xx[0]; xmax=xx[2]; } int ymin,ymax; if(xx[1]>xx[3]) { ymax=xx[1]; ymin=xx[3]; }else { ymin=xx[1]; ymax=xx[3]; } GRect rect(xmin,ymin,xmax-xmin,ymax-ymin); a=GMapRect::create(rect); }else if(shape == "circle") { int xx[4]; int i=0; GPosition rect_pos=coords.lastpos(); if(rect_pos) { coords.append(coords[rect_pos]); for(rect_pos=coords;(rect_pos)&&(i<4);++rect_pos) { xx[i++]=coords[rect_pos]; } } if(i!=4) { G_THROW( ERR_MSG("XMLAnno.bad_circle") ); } int x=xx[0],y=xx[1],rx=xx[2],ry=(h-xx[3])-1; GRect rect(x-rx,y-ry,2*rx,2*ry); a=GMapOval::create(rect); }else if(shape == "oval") { int xx[4]; int i=0; for(GPosition rect_pos=coords;(rect_pos)&&(i<4);++rect_pos,++i) { xx[i]=coords[rect_pos]; } if(i!=4) { G_THROW( ERR_MSG("XMLAnno.bad_oval") ); } int xmin,xmax; if(xx[0]>xx[2]) { xmax=xx[0]; xmin=xx[2]; }else { xmin=xx[0]; xmax=xx[2]; } int ymin,ymax; if(xx[1]>xx[3]) { ymax=xx[1]; ymin=xx[3]; }else { ymin=xx[1]; ymax=xx[3]; } GRect rect(xmin,ymin,xmax-xmin,ymax-ymin); a=GMapOval::create(rect); }else if(shape == "poly") { GP<GMapPoly> p=GMapPoly::create(); for(GPosition poly_pos=coords;poly_pos;++poly_pos) { int x=coords[poly_pos]; if(! ++poly_pos) break; int y=coords[poly_pos]; p->add_vertex(x,y); } p->close_poly(); a=p; }else { G_THROW( ( ERR_MSG("XMLAnno.unknown_shape") "\t")+shape ); } if(a) { GPosition pos; if((pos=args.contains("href"))) { a->url=args[pos]; } if((pos=args.contains("target"))) { a->target=args[pos]; } if((pos=args.contains("alt"))) { a->comment=args[pos]; } if((pos=args.contains("bordertype"))) { GUTF8String b=args[pos]; static const GMap<GUTF8String,GMapArea::BorderType> typeMap=BorderTypeMap(); if((pos=typeMap.contains(b))) { a->border_type=typeMap[pos]; }else { G_THROW( (ERR_MSG("XMLAnno.unknown_border") "\t")+b ); } } a->border_always_visible=!!args.contains("visible"); if((pos=args.contains("bordercolor"))) { a->border_color=convertToColor(args[pos]); } if((pos=args.contains("highlight"))) { a->hilite_color=convertToColor(args[pos]); } if((pos=args.contains("border"))) { a->border_width=args[pos].toInt(); //atoi(args[pos]); } map_areas.append(a); } } } } dfile.set_modified(true); dfile.anno=ByteStream::create(); anno.encode(dfile.anno); }