aboutsummaryrefslogtreecommitdiff
path: root/posts/2020-03-27-create-placeholder-images-with-sharp.md
diff options
context:
space:
mode:
Diffstat (limited to 'posts/2020-03-27-create-placeholder-images-with-sharp.md')
-rw-r--r--posts/2020-03-27-create-placeholder-images-with-sharp.md85
1 files changed, 85 insertions, 0 deletions
diff --git a/posts/2020-03-27-create-placeholder-images-with-sharp.md b/posts/2020-03-27-create-placeholder-images-with-sharp.md
new file mode 100644
index 0000000..ef035c9
--- /dev/null
+++ b/posts/2020-03-27-create-placeholder-images-with-sharp.md
@@ -0,0 +1,85 @@
1---
2Title: Create placeholder images with sharp Node.js image processing library
3Description: Create placeholder images with sharp Node.js image processing library
4Slug: create-placeholder-images-with-sharp
5Listing: true
6Created: 2020, March 27
7Tags: []
8---
9
10I have been searching for a solution to pre-generate some placeholder images for image server I needed to develop that resizes images on S3. I though this would be a 15min job and quickly found out how very mistaken I was.
11
12Even though Node.js is not really the best way to do this kind of things (surely something written in C or Rust or even Golang would be the correct way to do this but we didn't need the speed in our case) I found an excellent library [sharp - High performance Node.js image processing](https://github.com/lovell/sharp).
13
14Getting things running was a breeze.
15
16## Fetch image from S3 and save resized
17
18```js
19const sharp = require('sharp');
20const aws = require('aws-sdk');
21
22const x,y = 100;
23const s3 = new aws.S3({});
24
25aws.config.update({
26 secretAccessKey: 'secretAccessKey',
27 accessKeyId: 'accessKeyId',
28 region: 'region'
29});
30
31const originalImage = await s3.getObject({
32 Bucket: 'some-bucket-name',
33 Key: 'image.jpg',
34}).promise();
35
36const resizedImage = await sharp(originalImage.Body)
37 .resize(x, y)
38 .jpeg({ progressive: true })
39 .toBuffer();
40
41s3.putObject({
42 Bucket: 'some-bucket-name',
43 Key: `optimized/${x}x${y}/image.jpg`,
44 Body: resizedImage,
45 ContentType: 'image/jpeg',
46 ACL: 'public-read'
47}).promise();
48```
49
50All this code was wrapped inside a web service with some additional security checks and defensive coding to detect if key is missing on S3.
51
52And at that point I needed to return placeholder images as a response in case key is missing or x,y are not allowed by the server etc. I could have created PNG in Gimp and just serve them but I wanted to respect aspect ratio and I didn't want to return some mangled images.
53
54> Main problem with finding a clean solution I could copy and paste and change a bit was a task. API is changing constantly and there weren't clear examples or I was unable to find them.
55
56## Generating placeholder images using SVG
57
58What I ended up was using SVG to generate text and created image with sharp and used composition to combine both layers. Response returned by this function is a buffer you can use to either upload to S3 or save to local file.
59
60```js
61const generatePlaceholderImageWithText = async (width, height, message) => {
62 const overlay = `<svg width="${width - 20}" height="${height - 20}">
63 <text x="50%" y="50%" font-family="sans-serif" font-size="16" text-anchor="middle">${message}</text>
64 </svg>`;
65
66 return await sharp({
67 create: {
68 width: width,
69 height: height,
70 channels: 4,
71 background: { r: 230, g: 230, b: 230, alpha: 1 }
72 }
73 })
74 .composite([{
75 input: Buffer.from(overlay),
76 gravity: 'center',
77 }])
78 .jpeg()
79 .toBuffer();
80}
81```
82
83That is about it. Nothing more to it. You can change the color of the image by changing `background` and if you want to change text styling you can adapt SVG to your needs.
84
85> Also be careful about the length of the text. This function positions text at the center and adds `20px` padding on all sides. If text is longer than the image it will get cut.