From: Sam Moore Date: Fri, 8 Aug 2014 08:08:30 +0000 (+0800) Subject: Merge branch 'master' of git://git.ucc.asn.au/ipdf/code X-Git-Url: https://git.ucc.asn.au/?p=ipdf%2Fcode.git;a=commitdiff_plain;h=239870c67910883756cffe6c963c7f7fa44402b9;hp=-c Merge branch 'master' of git://git.ucc.asn.au/ipdf/code --- 239870c67910883756cffe6c963c7f7fa44402b9 diff --combined src/document.cpp index a4d6be6,6c281c1..a6c6fad --- a/src/document.cpp +++ b/src/document.cpp @@@ -3,6 -3,8 +3,8 @@@ #include #include + #include "stb_truetype.h" + using namespace IPDF; using namespace std; @@@ -280,16 -282,16 +282,16 @@@ void Document::LoadSVG(const string & f input.close(); // Combine all SVG tags into one thing because lazy - for (xml_node svg : doc_xml.children("svg")) + for (xml_node svg = doc_xml.child("svg"); svg; svg = svg.next_sibling("svg")) { - Real width = svg.attribute("width").as_float() * bounds.w; - Real height = svg.attribute("width").as_float() * bounds.h; + Real width = Real(svg.attribute("width").as_float()) * bounds.w; + Real height = Real(svg.attribute("width").as_float()) * bounds.h; // Rectangles Real coords[4]; const char * attrib_names[] = {"x", "y", "width", "height"}; - for (pugi::xml_node rect : svg.children("rect")) + for (pugi::xml_node rect = svg.child("rect"); rect; rect = rect.next_sibling("rect")) { for (size_t i = 0; i < 4; ++i) coords[i] = rect.attribute(attrib_names[i]).as_float(); @@@ -300,7 -302,7 +302,7 @@@ } // Circles - for (pugi::xml_node circle : svg.children("circle")) + for (pugi::xml_node circle = svg.child("circle"); circle; circle = circle.next_sibling("circle")) { Real cx = circle.attribute("cx").as_float(); Real cy = circle.attribute("cy").as_float(); @@@ -308,8 -310,8 +310,8 @@@ Real x = (cx - r)/width + bounds.x; Real y = (cy - r)/height + bounds.y; - Real w = 2*r/width; - Real h = 2*r/height; + Real w = Real(2)*r/width; + Real h = Real(2)*r/height; Rect rect(x,y,w,h); Add(CIRCLE_FILLED, rect,0); @@@ -318,7 -320,7 +320,7 @@@ } // paths - for (pugi::xml_node path : svg.children("path")) + for (pugi::xml_node path = svg.child("path"); path; path = path.next_sibling("path")) { string d = path.attribute("d").as_string(); @@@ -394,9 -396,9 +396,9 @@@ void Document::AddPathFromString(const if (command == "m" || command == "M") { Debug("Construct moveto command"); - Real dx = strtod(GetToken(d,token,i).c_str(),NULL) / bounds.w; + Real dx = Real(strtod(GetToken(d,token,i).c_str(),NULL)) / bounds.w; assert(GetToken(d,token,i) == ","); - Real dy = strtod(GetToken(d,token,i).c_str(),NULL) / bounds.h; + Real dy = Real(strtod(GetToken(d,token,i).c_str(),NULL)) / bounds.h; x[0] = (relative) ? x[0] + dx : dx; y[0] = (relative) ? y[0] + dy : dy; @@@ -409,25 -411,25 +411,25 @@@ else if (command == "c" || command == "C" || command == "q" || command == "Q") { Debug("Construct curveto command"); - Real dx = strtod(GetToken(d,token,i).c_str(),NULL)/bounds.w; + Real dx = Real(strtod(GetToken(d,token,i).c_str(),NULL))/bounds.w; assert(GetToken(d,token,i) == ","); - Real dy = strtod(GetToken(d,token,i).c_str(),NULL)/bounds.h; + Real dy = Real(strtod(GetToken(d,token,i).c_str(),NULL))/bounds.h; x[1] = (relative) ? x[0] + dx : dx; y[1] = (relative) ? y[0] + dy : dy; - dx = strtod(GetToken(d,token,i).c_str(),NULL) / bounds.w; + dx = Real(strtod(GetToken(d,token,i).c_str(),NULL)) / bounds.w; assert(GetToken(d,token,i) == ","); - dy = strtod(GetToken(d,token,i).c_str(),NULL) / bounds.h; + dy = Real(strtod(GetToken(d,token,i).c_str(),NULL)) / bounds.h; x[2] = (relative) ? x[0] + dx : dx; y[2] = (relative) ? y[0] + dy : dy; if (command != "q" && command != "Q") { - dx = strtod(GetToken(d,token,i).c_str(),NULL) / bounds.w; + dx = Real(strtod(GetToken(d,token,i).c_str(),NULL)) / bounds.w; assert(GetToken(d,token,i) == ","); - dy = strtod(GetToken(d,token,i).c_str(),NULL) / bounds.h; + dy = Real(strtod(GetToken(d,token,i).c_str(),NULL)) / bounds.h; x[3] = (relative) ? x[0] + dx : dx; y[3] = (relative) ? y[0] + dy : dy; } @@@ -435,6 -437,11 +437,11 @@@ { x[3] = x[2]; y[3] = y[2]; + Real old_x1(x[1]), old_y1(y[1]); + x[1] = x[0] + Real(2) * (old_x1 - x[0])/ Real(3); + y[1] = y[0] + Real(2) * (old_y1 - y[0])/ Real(3); + x[2] = x[3] + Real(2) * (old_x1 - x[3])/ Real(3); + y[2] = y[3] + Real(2) * (old_y1 - y[3])/ Real(3); } unsigned index = AddBezierData(Bezier(x[0],y[0],x[1],y[1],x[2],y[2],x[3],y[3])); @@@ -452,12 -459,12 +459,12 @@@ { Debug("Construct lineto command"); - Real dx = strtod(GetToken(d,token,i).c_str(),NULL) / bounds.w; + Real dx = Real(strtod(GetToken(d,token,i).c_str(),NULL)) / bounds.w; assert(GetToken(d,token,i) == ","); - Real dy = strtod(GetToken(d,token,i).c_str(),NULL) / bounds.h; + Real dy = Real(strtod(GetToken(d,token,i).c_str(),NULL)) / bounds.h; - x[1] = (relative) ? x0 + dx : dx; - y[1] = (relative) ? y0 + dy : dy; + x[1] = (relative) ? x[0] + dx : dx; + y[1] = (relative) ? y[0] + dy : dy; x[2] = x[1]; y[2] = y[1]; @@@ -508,3 -515,57 +515,57 @@@ prev_i = i; } } + + void Document::AddFontGlyphAtPoint(stbtt_fontinfo *font, int character, Real scale, Real x, Real y) + { + int glyph_index = stbtt_FindGlyphIndex(font, character); + + // Check if there is actully a glyph to render. + if (stbtt_IsGlyphEmpty(font, glyph_index)) + { + return; + } + + stbtt_vertex *instructions; + int num_instructions = stbtt_GetGlyphShape(font, glyph_index, &instructions); + + Real current_x(0), current_y(0); + + for (int i = 0; i < num_instructions; ++i) + { + // TTF uses 16-bit signed ints for coordinates: + // with the y-axis inverted compared to us. + // Convert and scale any data. + Real inst_x = Real(instructions[i].x)*scale; + Real inst_y = Real(instructions[i].y)*-scale; + Real inst_cx = Real(instructions[i].cx)*scale; + Real inst_cy = Real(instructions[i].cy)*-scale; + Real old_x(current_x), old_y(current_y); + current_x = inst_x; + current_y = inst_y; + unsigned bezier_index; + switch(instructions[i].type) + { + // Move To + case STBTT_vmove: + break; + // Line To + case STBTT_vline: + bezier_index = AddBezierData(Bezier(old_x + x, old_y + y, old_x + x, old_y + y, current_x + x, current_y + y, current_x + x, current_y + y)); + Add(BEZIER,Rect(0,0,1,1),bezier_index); + break; + // Quadratic Bezier To: + case STBTT_vcurve: + // Quadratic -> Cubic: + // - Endpoints are the same. + // - cubic1 = quad0+(2/3)*(quad1-quad0) + // - cubic2 = quad2+(2/3)*(quad1-quad2) + bezier_index = AddBezierData(Bezier(old_x + x, old_y + y, old_x + Real(2)*(inst_cx-old_x)/Real(3) + x, old_y + Real(2)*(inst_cy-old_y)/Real(3) + y, + current_x + Real(2)*(inst_cx-current_x)/Real(3) + x, current_y + Real(2)*(inst_cy-current_y)/Real(3) + y, current_x + x, current_y + y)); + Add(BEZIER,Rect(0,0,1,1),bezier_index); + break; + } + } + + stbtt_FreeShape(font, instructions); + } diff --combined src/document.h index c0adc52,c1f026b..62f624c --- a/src/document.h +++ b/src/document.h @@@ -4,6 -4,8 +4,8 @@@ #include "ipdf.h" #include "quadtree.h" + typedef struct stbtt_fontinfo stbtt_fontinfo; + namespace IPDF { class Document @@@ -12,7 -14,7 +14,7 @@@ Document(const std::string & filename = "") : m_objects(), m_count(0) {Load(filename);} virtual ~Document() {} - void LoadSVG(const std::string & filename, const Rect & bounds = {0,0,1,1}); + void LoadSVG(const std::string & filename, const Rect & bounds = Rect(0,0,1,1)); void Load(const std::string & filename = ""); void Save(const std::string & filename); @@@ -29,6 -31,8 +31,8 @@@ void AddPathFromString(const std::string & d, const Rect & bounds); + void AddFontGlyphAtPoint(stbtt_fontinfo *font, int character, Real scale, Real x, Real y); + #ifndef QUADTREE_DISABLED inline const QuadTree& GetQuadTree() { if (m_quadtree.root_id == QUADTREE_EMPTY) { GenBaseQuadtree(); } return m_quadtree; } QuadTreeIndex GenQuadChild(QuadTreeIndex parent, QuadTreeNodeChildren type);