1 module qrcode.renderer.image.svg; 2 3 import qrcode.renderer.image.abstractrender; 4 import qrcode.renderer.color.colorinterface; 5 6 7 import std.xml,std.conv, std.format; 8 /** 9 * SVG backend. 10 */ 11 class Svg : AbstractRenderer 12 { 13 /** 14 * SVG resource. 15 * 16 * @var Document 17 */ 18 protected Document svg; 19 20 protected Element defs; 21 /** 22 * Colors used for drawing. 23 * 24 * @var array 25 */ 26 protected ColorInterface[string]colors; 27 /** 28 * Prototype IDs. 29 * 30 * @var array 31 */ 32 protected string[string] prototypeIds; 33 34 /** 35 * init(): defined by RendererInterface. 36 * 37 * @see ImageRendererInterface::init() 38 * @return void 39 */ 40 public override void initRender() 41 { 42 auto tag = new Tag("svg"); 43 tag.attr["xmlns"] = "http://www.w3.org/2000/svg"; 44 tag.attr["xmlns:xlink"] = "http://www.w3.org/1999/xlink"; 45 tag.attr["version"] = "1.1"; 46 tag.attr["width"] = to!string(this.finalWidth) ~ "px"; 47 tag.attr["height"] = to!string(this.finalHeight) ~ "px"; 48 tag.attr["viewBox"] = "0 0 " ~ to!string(this.finalWidth) ~ " " ~ to!string(this.finalHeight); 49 this.svg = new Document(tag); 50 this.defs = new Element("defs"); 51 //this.svg ~= element; 52 } 53 54 55 /** 56 * addColor(): defined by RendererInterface. 57 * 58 * @see ImageRendererInterface::addColor() 59 * @param string id 60 * @param ColorInterface color 61 * @return void 62 * @throws Exception\InvalidArgumentException 63 */ 64 public override void addColor(string id, ColorInterface color) 65 { 66 this.colors[id] = color.toRgb(); 67 } 68 /** 69 * drawBackground(): defined by RendererInterface. 70 * 71 * @see ImageRendererInterface::drawBackground() 72 * @param string colorId 73 * @return void 74 */ 75 public override void drawBackground(string colorId) 76 { 77 auto rect = new Element("rect"); 78 rect.tag.attr["x"] = "0"; 79 rect.tag.attr["y"] = "0"; 80 rect.tag.attr["width"] = to!string(this.finalWidth); 81 rect.tag.attr["height"] = to!string(this.finalHeight); 82 rect.tag.attr["fill"] = "#" ~ this.colors[colorId].toString(); 83 this.svg ~= rect; 84 } 85 /** 86 * drawBlock(): defined by RendererInterface. 87 * 88 * @see ImageRendererInterface::drawBlock() 89 * @param integer x 90 * @param integer y 91 * @param string colorId 92 * @return void 93 */ 94 public override void drawBlock(int x, int y, string colorId) 95 { 96 97 auto use = new Element("use"); 98 use.tag.attr["x"] = to!string(x); 99 use.tag.attr["y"] = to!string(y); 100 use.tag.attr["xlink:href"] = this.getRectPrototypeId(colorId); 101 use.tag.attr["xmlns:xmi"] = "http://www.w3.org/1999/xlink"; 102 103 104 this.svg ~= use; 105 } 106 /** 107 * getByteStream(): defined by RendererInterface. 108 * 109 * @see ImageRendererInterface::getByteStream() 110 * @return string 111 */ 112 public override string getByteStream() 113 { 114 import std..string; 115 this.svg ~= this.defs; 116 this.prototypeIds = string[string].init; 117 return this.svg.toString(); 118 } 119 /** 120 * Get the prototype ID for a color. 121 * 122 * @param integer colorId 123 * @return string 124 */ 125 protected string getRectPrototypeId(string colorId) 126 { 127 auto p = colorId in this.prototypeIds; 128 if(p) 129 { 130 return *p; 131 } 132 auto id = "r" ~ format("%X", this.prototypeIds.length); 133 //srect = this.svg.defs.addChild('rect'); 134 auto rect = new Element("rect"); 135 rect.tag.attr["id"] = id; 136 rect.tag.attr["width"] = to!string(this.blockSize); 137 rect.tag.attr["height"] = to!string(this.blockSize); 138 rect.tag.attr["fill"] = "#" ~ this.colors[colorId].toString(); 139 this.defs ~= rect; 140 /*rect.addAttribute('id', id); 141 rect.addAttribute('width', this.blockSize); 142 rect.addAttribute('height', this.blockSize); 143 rect.addAttribute('fill', '#' . this.colors[colorId]); 144 */ 145 this.prototypeIds[colorId] = "#" ~ id; 146 return this.prototypeIds[colorId]; 147 } 148 }