Skip to content

Commit

Permalink
feat: Adds viewBox option for SVG
Browse files Browse the repository at this point in the history
Thanks to @mjy @MattDahEpic and #98 and #66
  • Loading branch information
whomwah committed May 6, 2021
1 parent c7a46d5 commit a8edfc2
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 6 deletions.
7 changes: 5 additions & 2 deletions README.md
Expand Up @@ -95,6 +95,9 @@ standalone - whether to make this a full SVG file, or only an svg to embed
use_path - Use <path> to render SVG rather than <rect> to significantly reduce size
and quality. This will become the default in future versions.
(default false)
viewbox - replace the `svg.width` and `svg.height` attribute with `svg.viewBox` to
allow CSS scaling
(default false)
```
Example
```ruby
Expand All @@ -104,11 +107,11 @@ qrcode = RQRCode::QRCode.new("http://github.com/")

# NOTE: showing with default options specified explicitly
svg = qrcode.as_svg(
offset: 0,
color: '000',
shape_rendering: 'crispEdges',
module_size: 11,
standalone: true
standalone: true,
use_path: true
)
```

Expand Down
12 changes: 9 additions & 3 deletions lib/rqrcode/export/svg.rb
Expand Up @@ -143,27 +143,33 @@ def end_y
# use_path - Use <path> to render SVG rather than <rect> to significantly reduce size
# and quality. This will become the default in future versions.
# (default false)
# viewbox - replace `width` and `height` in <svg> with a viewBox, allows CSS scaling
# (default false)
#
def as_svg(options = {})
fill = options[:fill]
use_path = options[:use_path]
offset = options[:offset].to_i || 0
color = options[:color] || "000"
shape_rendering = options[:shape_rendering] || "crispEdges"
module_size = options[:module_size] || 11
standalone = options[:standalone].nil? ? true : options[:standalone]
viewbox = options[:viewbox].nil? ? false : options[:viewbox]

# height and width dependent on offset and QR complexity
dimension = (@qrcode.module_count * module_size) + (2 * offset)
# use dimensions differently if we are using a viewBox
dimensions_attr = viewbox ? %(viewBox="0 0 #{dimension} #{dimension}") : %(width="#{dimension}" height="#{dimension}")

xml_tag = %(<?xml version="1.0" standalone="yes"?>)
open_tag = %(<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events" width="#{dimension}" height="#{dimension}" shape-rendering="#{shape_rendering}">)
open_tag = %(<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events" #{dimensions_attr} shape-rendering="#{shape_rendering}">)
close_tag = "</svg>"

output_tag = (use_path ? Path : Rect).new(@qrcode)
output_tag.build(module_size, offset, color)

if options[:fill]
output_tag.result.unshift %(<rect width="#{dimension}" height="#{dimension}" x="0" y="0" style="fill:##{options[:fill]}"/>)
if fill
output_tag.result.unshift %(<rect width="#{dimension}" height="#{dimension}" x="0" y="0" style="fill:##{fill}"/>)
end

if standalone
Expand Down
4 changes: 4 additions & 0 deletions spec/rqrcode/data.rb
Expand Up @@ -18,6 +18,10 @@
<path d="M0 0h7v7h-7zM8 0h7v2h-1v1h1v1h-2v-2h-1v-1h-2v2h-2v-1h1v-1h-1zM17 0h3v2h1v5h-1v-2h-1v2h-1v-3h-2v-1h2v1h1v-2h-1v-1h-1zM22 0h7v7h-7zM1 1v5h5v-5zM23 1v5h5v-5zM2 2h3v3h-3zM11 2h1v1h-1zM24 2h3v3h-3zM8 4h1v1h-1zM10 4h1v1h1v1h-1v1h-1v-1h-1v-1h1zM13 5h1v1h-1zM15 5h2v2h-1v-1h-1zM8 6h1v1h1v1h2v-2h1v1h1v-1h1v1h-1v1h-2v1h-3v-1h-1zM15 7h1v1h1v1h-1v3h1v-1h1v-1h1v1h-1v2h-1v1h1v1h-2v-2h-1v-1h-1v1h-1v-2h1v-1h1v-1h-1v-1h1zM5 8h2v1h-1v1h2v1h-2v1h1v1h-1v1h-2v-1h1v-2h-1v-1h-1v4h-1v-2h-1v1h-1v-3h1v-1h4zM18 8h3v1h1v-1h1v2h1v-2h1v2h1v-2h1v1h1v-1h1v1h-1v1h-1v1h-1v3h-2v-1h1v-1h-1v-1h-1v3h1v1h-2v-2h-1v-1h1v-1h-2v-2h-2zM12 9h1v1h-1zM1 10v1h1v-1zM10 10h2v2h-1v2h1v1h1v-1h1v-1h1v1h-1v1h1v1h1v2h2v-1h1v-2h1v-1h-1v-2h1v1h1v3h-1v1h-1v2h-3v1h2v1h-3v-1h-1v-2h-1v1h-1v-3h-2v1h-1v-1h-1v1h-2v1h3v1h1v1h-1v1h1v1h2v-2h-1v-1h1v1h1v1h1v1h-1v1h1v-1h1v1h1v1h-1v1h-3v-1h-1v-1h-1v2h1v1h2v2h-1v-1h-2v-1h-1v-2h-1v-1h1v-1h-1v-2h-1v-1h-2v-1h-1v-1h1v-2h1v-1h1v-1h1v-2h1v1h1zM27 12h1v1h-1zM9 13v1h1v-1zM28 13h1v1h-1zM0 14h2v1h1v-1h1v2h-1v1h-1v1h1v1h2v1h-2v1h-1v-2h-1v2h-1zM7 14v1h-1v1h1v-1h1v-1zM24 15h3v3h-2v-1h-1zM22 16h1v1h-1zM28 16h1v3h-1zM14 17v1h1v-1zM20 17h1v2h2v-2h1v3h1v-1h1v1h-1v1h1v-1h2v1h-1v1h-2v1h1v1h-1v1h-1v1h1v-1h3v2h-1v-1h-1v1h-1v2h-1v-2h-1v1h-1v-1h-1v1h-2v-1h-1v-1h-3v-1h1v-1h1v-1h2v-1h-1v-1h1v-2h1zM5 20h2v1h-2zM19 21v1h1v-1zM21 21v3h3v-3zM0 22h7v7h-7zM22 22h1v1h-1zM27 22h1v1h-1zM1 23v5h5v-5zM28 23h1v1h-1zM2 24h3v3h-3zM17 24v1h1v-1zM21 25v1h2v-1zM14 26h1v1h1v1h1v1h-3zM9 27h1v1h-1zM26 27h1v1h-1zM28 27h1v1h-1z" style="fill:#000" transform="translate(0,0) scale(11)"/>
SVG

AS_SVG4 = <<~SVG.chomp
<?xml version="1.0" standalone="yes"?><svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events" viewBox="0 0 319 319" shape-rendering="crispEdges"><path d="M0 0h7v7h-7zM8 0h7v2h-1v1h1v1h-2v-2h-1v-1h-2v2h-2v-1h1v-1h-1zM17 0h3v2h1v5h-1v-2h-1v2h-1v-3h-2v-1h2v1h1v-2h-1v-1h-1zM22 0h7v7h-7zM1 1v5h5v-5zM23 1v5h5v-5zM2 2h3v3h-3zM11 2h1v1h-1zM24 2h3v3h-3zM8 4h1v1h-1zM10 4h1v1h1v1h-1v1h-1v-1h-1v-1h1zM13 5h1v1h-1zM15 5h2v2h-1v-1h-1zM8 6h1v1h1v1h2v-2h1v1h1v-1h1v1h-1v1h-2v1h-3v-1h-1zM15 7h1v1h1v1h-1v3h1v-1h1v-1h1v1h-1v2h-1v1h1v1h-2v-2h-1v-1h-1v1h-1v-2h1v-1h1v-1h-1v-1h1zM5 8h2v1h-1v1h2v1h-2v1h1v1h-1v1h-2v-1h1v-2h-1v-1h-1v4h-1v-2h-1v1h-1v-3h1v-1h4zM18 8h3v1h1v-1h1v2h1v-2h1v2h1v-2h1v1h1v-1h1v1h-1v1h-1v1h-1v3h-2v-1h1v-1h-1v-1h-1v3h1v1h-2v-2h-1v-1h1v-1h-2v-2h-2zM12 9h1v1h-1zM1 10v1h1v-1zM10 10h2v2h-1v2h1v1h1v-1h1v-1h1v1h-1v1h1v1h1v2h2v-1h1v-2h1v-1h-1v-2h1v1h1v3h-1v1h-1v2h-3v1h2v1h-3v-1h-1v-2h-1v1h-1v-3h-2v1h-1v-1h-1v1h-2v1h3v1h1v1h-1v1h1v1h2v-2h-1v-1h1v1h1v1h1v1h-1v1h1v-1h1v1h1v1h-1v1h-3v-1h-1v-1h-1v2h1v1h2v2h-1v-1h-2v-1h-1v-2h-1v-1h1v-1h-1v-2h-1v-1h-2v-1h-1v-1h1v-2h1v-1h1v-1h1v-2h1v1h1zM27 12h1v1h-1zM9 13v1h1v-1zM28 13h1v1h-1zM0 14h2v1h1v-1h1v2h-1v1h-1v1h1v1h2v1h-2v1h-1v-2h-1v2h-1zM7 14v1h-1v1h1v-1h1v-1zM24 15h3v3h-2v-1h-1zM22 16h1v1h-1zM28 16h1v3h-1zM14 17v1h1v-1zM20 17h1v2h2v-2h1v3h1v-1h1v1h-1v1h1v-1h2v1h-1v1h-2v1h1v1h-1v1h-1v1h1v-1h3v2h-1v-1h-1v1h-1v2h-1v-2h-1v1h-1v-1h-1v1h-2v-1h-1v-1h-3v-1h1v-1h1v-1h2v-1h-1v-1h1v-2h1zM5 20h2v1h-2zM19 21v1h1v-1zM21 21v3h3v-3zM0 22h7v7h-7zM22 22h1v1h-1zM27 22h1v1h-1zM1 23v5h5v-5zM28 23h1v1h-1zM2 24h3v3h-3zM17 24v1h1v-1zM21 25v1h2v-1zM14 26h1v1h1v1h1v1h-3zM9 27h1v1h-1zM26 27h1v1h-1zM28 27h1v1h-1z" style="fill:#000" transform="translate(0,0) scale(11)"/></svg>
SVG

AS_BASIC = <<~STR
XXXXXXXOOOXOXOOXXXOOOOXXXXXXX
XOOOOOXOOXXXXXOOXOXOOOXOOOOOX
Expand Down
11 changes: 10 additions & 1 deletion spec/rqrcode/export_svg_spec.rb
Expand Up @@ -33,11 +33,20 @@
end

context "standalone false" do
it "must export to svg" do
it "will not include the <xml>" do
expect(RQRCode::QRCode.new("https://kyan.com").as_svg(
standalone: false,
use_path: true
)).to eq(AS_SVG3)
end
end

context "viewbox true" do
it "will use the viewBox attr" do
expect(RQRCode::QRCode.new("https://kyan.com").as_svg(
viewbox: true,
use_path: true
)).to eq(AS_SVG4)
end
end
end

0 comments on commit a8edfc2

Please sign in to comment.