Skip to content

Commit

Permalink
feat(options): add blur option plus documentation (#24)
Browse files Browse the repository at this point in the history
fixes #20
  • Loading branch information
axe312ger authored and efegurkan committed Feb 26, 2018
1 parent d1652d2 commit f6ec0f3
Show file tree
Hide file tree
Showing 14 changed files with 47 additions and 14 deletions.
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,16 @@ SQIP - SVG-Based Image Placeholder
"SQIP" (pronounced \skwɪb\ like the non-magical folk of magical descent) is a
SVG-based [LQIP](https://www.guypo.com/introducing-lqip-low-quality-image-placeholders/) technique.

**LQIP | SQIP | Original in comparison**
[![LQIP vs. SQIP](demo/lqip-vs-sqip.jpg)](https://raw.githubusercontent.com/technopagan/sqip/master/demo/lqip-vs-sqip.jpg)
## Examples

| Original | LQIP | SQIP default | SQIP complex |
|----------|------|--------------|----------------------|
| <img width="180" src="demo/beach.jpg"> | <img width="180" src="demo/beach-lqip.jpg"> | <img width="180" src="demo/beach-sqip.svg"> | <img width="180" src="./demo/beach-sqip-no-blur-50-all-shapes.svg"> |
| Size: | 354B (gz: 282B) | 895B (gz: 479B)| 3104B (gz: 1241B)- 50 shapes |
| <img width="180" src="./demo/monkey-selfie.jpg"> | <img width="180" src="./demo/monkey-selfie-lqip.jpg"> | <img width="180" src="./demo/monkey-selfie-sqip.svg"> | <img width="180" src="./demo/monkey-selfie-sqip-no-blur-25-all-shapes.svg"> |
| Size: | 435B (gz: 369B) | 980B (gz: 513B)| 2258B (gz: 924B) - 25 shapes |
| <img width="180" src="./demo/mona-lisa.jpg"> | <img width="180" src="./demo/mona-lisa-lqip.jpg"> | <img width="180" src="./demo/mona-lisa-sqip.svg"> | <img width="180" src="./demo/mona-lisa-sqip-3-blur-50-triangles.svg"> |
| Size: | 442B (gz: 372B) | 937B (gz: 487B) | 3273B (gz: 1394B)- 50 triangles |

## Requirements
* Node.js >= v.6 (https://nodejs.org/en/)
Expand Down Expand Up @@ -97,6 +105,9 @@ sqip -n 4 input.jpg
# Specify the type of primitive shapes that will be used to generate the image (default=0)
# 0=combo, 1=triangle, 2=rect, 3=ellipse, 4=circle, 5=rotatedrect, 6=beziers, 7=rotatedellipse, 8=polygon
sqip -m 4 input.jpg

# Set the gaussian blur (default=12)
sqip -b 3 input.jpg
```

### NODE API
Expand All @@ -107,6 +118,7 @@ Input options:
- filename (required)
- numberOfPrimitives (default=8)
- mode (default=0)
- blur (default=12)

Returns:
- final_svg - string
Expand Down
Binary file added demo/beach-lqip.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions demo/beach-sqip-no-blur-50-all-shapes.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
Binary file removed demo/lqip-vs-sqip.jpg
Binary file not shown.
Binary file added demo/mona-lisa-lqip.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions demo/mona-lisa-sqip-3-blur-50-triangles.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
File renamed without changes
Binary file added demo/monkey-selfie-lqip.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions demo/monkey-selfie-sqip-no-blur-25-all-shapes.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
40 changes: 29 additions & 11 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ const argvOptions = [{
0=combo, 1=triangle, 2=rect, 3=ellipse, 4=circle, 5=rotatedrect,
6=beziers, 7=rotatedellipse, 8=polygon`,
example: "'sqip --mode=3' or 'sqip -m 3'"
},
{
name: 'blur',
short: 'b',
type: 'int',
description: `GaussianBlur SVG filter value. Disable via 0, defaults to 12`,
example: "'sqip --blur=3' or 'sqip -b 3'"
}
];
const getArguments = () => argv.option(argvOptions).run();
Expand Down Expand Up @@ -140,18 +147,22 @@ const patchSVGGroup = (svg) => {
// Add viewbox and preserveAspectRatio attributes as well as a Gaussian Blur filter to the SVG
// When missing, add group (element with blur applied) using patchSVGGroup()
// We initially worked with a proper DOM parser to manipulate the SVG's XML, but it was very opinionated about SVG syntax and kept introducing unwanted tags. So we had to resort to RegEx replacements
const replaceSVGAttrs = (svg, { width, height }) => {
let blurStdDev = 12;
const replaceSVGAttrs = (svg, { width, height, blur }) => {
let filter = '';
let blurStdDev = blur;
let blurFilterId = 'b';
let newSVG = svg;
if (svg.match(/<svg.*?><path.*?><g/) === null) {
blurStdDev = 55;
newSVG = patchSVGGroup(newSVG);
blurFilterId = 'c';
} else {
newSVG = newSVG.replace(/(<g)/, '<g filter="url(#b)"');
if (blur) {
if (svg.match(/<svg.*?><path.*?><g/) === null) {
blurStdDev = 55;
newSVG = patchSVGGroup(newSVG);
blurFilterId = 'c';
} else {
newSVG = newSVG.replace(/(<g)/, `<g filter="url(#${blurFilterId})"`);
}
filter = `<filter id="${blurFilterId}"><feGaussianBlur stdDeviation="${blurStdDev}" /></filter>`
}
return newSVG.replace(/(<svg)(.*?)(>)/,`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width} ${height}"><filter id="${blurFilterId}"><feGaussianBlur stdDeviation="${blurStdDev}" /></filter>`);
return newSVG.replace(/(<svg)(.*?)(>)/,`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width} ${height}">${filter}`);
}

// If the user chooses to save the SVG to a file using the --output parameter, write the file
Expand All @@ -174,11 +185,18 @@ const printFinalResult = ({ width, height }, filename, svg_base64encoded) => {
//#############################################################################

const main = (filename, options) => {
const img_dimensions = getDimensions(filename);
const img_dimensions = getDimensions(filename)
const svgOptions = Object.assign({
blur: options.blur
}, img_dimensions);

// Do not pass blur to primitive
delete options.blur

runPrimitive(filename, options, primitive_output_file, img_dimensions);
const primitive_output = readPrimitiveTempFile(primitive_output_file);
const svgo_output = runSVGO(primitive_output);
const final_svg = replaceSVGAttrs(svgo_output, img_dimensions);
const final_svg = replaceSVGAttrs(svgo_output, svgOptions);
const svg_base64encoded = encodeBase64(final_svg);

return { final_svg, svg_base64encoded, img_dimensions };
Expand Down

0 comments on commit f6ec0f3

Please sign in to comment.