New command that will use Pexels to generate random cover images for media.

main
Zed A. Shaw 1 year ago
parent e27092843e
commit 578b58794b
  1. 161
      commands/examples/coverimage.js

@ -0,0 +1,161 @@
// you may not need all of these but they come up a lot
import fs from "fs";
import assert from "assert";
import logging from '../lib/logging.js';
import glob from "fast-glob";
import path from "path";
import { fabric } from "fabric";
import { defer } from "../lib/api.js";
import { createClient } from 'pexels';
import { exec_i } from "../lib/builderator.js";
import { pexels } from "../lib/config.js";
import fetch from "node-fetch";
import { playstart, playstop } from "../lib/testing.js";
const log = logging.create(import.meta.url);
export const description = "Gets a random image from Pexels and places the text on it."
// your command uses the npm package commander's options format
export const options = [
["--background <filename>", "The file name to save the background image.", "background.jpg"],
["--force", "Force overwriting the background.jpg temp file."],
["--query <text>", "Query to give pexels for the image", "keyboard"],
["--color <color>", "General color of the image"],
["--text-color <color>", "The border around text.", "#fff"],
["--font-family <name>", "Font to use", "Andale Mono"],
["--font-size <pts>", "Font size to use", 140],
["--blend-mode <mode>", "One of: none, multiply, screen, add, diff, subtract, darken, lighten, overlay, exclusion, tint", "screen"],
["--pixelate <blocksize>", "Pixelate the image with blocksize (try 8)"],
]
// example of a positional argument, it's the 1st argument to main
export const argument = ["text", "The message to put on the image."];
// put required options in the required variable
export const required = [
["--output <string>", "Image file to save."],
]
// handy function for checking things are good and aborting
const check = (test, fail_message) => {
if(!test) {
log.error(fail_message);
process.exit(1);
}
}
export const main = async (title, opts) => {
const per_page = 50;
const ext_check = path.parse(opts.output).ext;
check(ext_check === "", `Do not add an extension to the output. You have ${ext_check}.`);
title = title.replaceAll("\\n", "\n");
if(opts.force || !fs.existsSync(opts.background)) {
const client = createClient(pexels.key);
const result = await client.photos.search({
query: opts.query,
per_page,
orientation: opts.orientation,
color: opts.color });
const randi = Math.floor(Math.random() * per_page);
const image = await client.photos.show({id: result.photos[randi].id});
const img_fetch = await fetch(image.src.large);
const img_data = await img_fetch.arrayBuffer();
await fs.writeFileSync(opts.background, new Uint8Array(img_data));
}
const background = path.join(process.cwd(), opts.background);
let canvas = new fabric.Canvas('c', { width: 1600, height: 900 })
let gradient = new fabric.Gradient({
type: 'linear',
gradientUnits: 'pixels', // or 'percentage'
coords: { x1: 0, y1: 0, x2: canvas.height, y2: canvas.width },
colorStops:[
{ offset: 0, color: '#000' },
{ offset: 1, color: '#fff'}
]
})
let image_def = defer();
fabric.Image.fromURL(`file:///${background}`, img => {
let blur = new fabric.Image.filters.Blur({ blur: 0.05 });
img.set('scaleY', canvas.height / img.height);
img.set('scaleX', canvas.width / img.width);
if(opts.pixelate) {
let pixelate = new fabric.Image.filters.Pixelate({
blocksize: parseInt(opts.pixelate, 10)
});
img.filters.push(pixelate);
}
let blend = new fabric.Image.filters.BlendColor({
color: opts.color,
mode: opts.blendMode,
});
img.filters.push(blend);
img.filters.push(blur);
img.applyFilters();
image_def.resolve(img);
});
let bg_img = await image_def;
let rect = new fabric.Rect({
left: 0,
top: 0,
fill: opts.color,
width: canvas.width,
height: canvas.height,
opacity: 0.3
});
let text = new fabric.Text(title, {
fontFamily: opts.fontFamily,
fontSize: opts.fontSize,
strokeWidth: 5,
originX: "center",
originY: "center",
left: canvas.width / 2,
top: canvas.height / 2,
stroke: opts.textColor,
shadow: 'rgba(0, 0, 0, 1) 10px 10px 10px',
});
canvas.add(bg_img);
// canvas.add(rect);
canvas.add(text);
const output_svg = `${opts.output}.svg`;
const output_jpg = `${opts.output}.jpg`;
const output_png = `${opts.output}.png`;
fs.writeFileSync(output_svg, canvas.toSVG());
const {browser, context, p} = await playstart(`file:///${path.resolve(output_svg)}`);
await p.setViewportSize({
width: canvas.width,
height: canvas.height });
await p.screenshot({ path: output_png,
type: "png", omitBackground: true});
await playstop(browser, p);
exec_i(`convert ${output_png} -sampling-factor 4:2:0 -strip -quality 85 -interlace JPEG -colorspace RGB ${output_jpg}`);
// due to how async/await works it's just easier to manually exit with exit codes
process.exit(0);
}
Loading…
Cancel
Save