feat: compress EVERYTHING!
106
bin/compress_s3.js
Normal file
@ -0,0 +1,106 @@
|
||||
import { Client } from "minio";
|
||||
import sharp from "sharp"
|
||||
import {config} from "dotenv"
|
||||
config()
|
||||
|
||||
// Retrieve MinIO details from environment variables
|
||||
const minioEndpoint = process.env["S3_ENDPOINT_URL"] || "your-minio-endpoint";
|
||||
const minioAccessKey = process.env["S3_ACCESS_KEY"] || "your-access-key";
|
||||
const minioSecretKey = process.env["S3_SECRET_ACCESS_KEY"] || "your-secret-key";
|
||||
const minioBucketName = "silvester23";
|
||||
|
||||
const minioClient = new Client({
|
||||
endPoint: minioEndpoint,
|
||||
accessKey: minioAccessKey,
|
||||
secretKey: minioSecretKey,
|
||||
});
|
||||
|
||||
|
||||
const objects = [];
|
||||
|
||||
const objectStream = minioClient.listObjects(minioBucketName);
|
||||
|
||||
for await (const obj of objectStream) {
|
||||
objects.push(obj);
|
||||
}
|
||||
|
||||
async function compressObject(pngBuffer, fileName, format) {
|
||||
|
||||
const newFilePath = `${fileName.slice(0, -4)}.${format}`;
|
||||
|
||||
let buffer;
|
||||
switch (format) {
|
||||
case "webp":
|
||||
buffer = await sharp(pngBuffer).webp({ quality: 80 }).toBuffer();
|
||||
break;
|
||||
case "jpg":
|
||||
buffer = await sharp(pngBuffer).jpeg({ quality: 80 }).toBuffer();
|
||||
break;
|
||||
case "avif":
|
||||
buffer = await sharp(pngBuffer).avif({ quality: 80 }).toBuffer();
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unknown format ${format}`);
|
||||
}
|
||||
|
||||
// Upload the JPG buffer back to the same MinIO bucket
|
||||
await minioClient.putObject(minioBucketName, newFilePath, buffer, {
|
||||
'Content-Type': 'image/' + format,
|
||||
});
|
||||
|
||||
console.log(`Uploaded ${newFilePath} to MinIO`);
|
||||
}
|
||||
|
||||
async function fetchBuffer(objectName) {
|
||||
const chunks = [];
|
||||
|
||||
return new Promise((res, rej) => {
|
||||
minioClient.getObject(minioBucketName,objectName, function (err, dataStream) {
|
||||
if (err) {
|
||||
return console.log(err)
|
||||
}
|
||||
dataStream.on('data', function (chunk) {
|
||||
chunks.push(chunk);
|
||||
})
|
||||
dataStream.on('end', function () {
|
||||
res(Buffer.concat(chunks))
|
||||
})
|
||||
dataStream.on('error', function (err) {
|
||||
console.log(err)
|
||||
rej(err)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const pngs = objects.filter((o) => o.name.endsWith(".png"));
|
||||
console.log(`Found ${pngs.length} PNGs`);
|
||||
|
||||
for (const obj of pngs) {
|
||||
const pngFilePath = obj.name;
|
||||
const jpgFilePath = pngFilePath.slice(0, -4) + ".jpg";
|
||||
const avifFilePath = pngFilePath.slice(0, -4) + ".avif";
|
||||
const webpFilePath = pngFilePath.slice(0, -4) + ".webp";
|
||||
|
||||
const hasJpg = objects.some((o) => o.name === jpgFilePath);
|
||||
const hasAvif = objects.some((o) => o.name === avifFilePath);
|
||||
const hasWebp = objects.some((o) => o.name === webpFilePath);
|
||||
|
||||
if(hasAvif && hasJpg && hasWebp) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const pngBuffer = await fetchBuffer(pngFilePath);
|
||||
|
||||
if(!hasJpg) {
|
||||
await compressObject(pngBuffer, pngFilePath, "jpg");
|
||||
}
|
||||
|
||||
if(!hasAvif) {
|
||||
await compressObject(pngBuffer, pngFilePath, "avif");
|
||||
}
|
||||
if(!hasWebp) {
|
||||
await compressObject(pngBuffer, pngFilePath, "webp");
|
||||
}
|
||||
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
import { Client } from "npm:minio";
|
||||
import Jimp from 'npm:jimp';
|
||||
import { config } from "https://deno.land/x/dotenv/mod.ts";
|
||||
config({ export: true });
|
||||
|
||||
interface MinioObject {
|
||||
name: string;
|
||||
}
|
||||
|
||||
// Retrieve MinIO details from environment variables
|
||||
const minioEndpoint = Deno.env.get("S3_ENDPOINT_URL") || "your-minio-endpoint";
|
||||
const minioAccessKey = Deno.env.get("S3_ACCESS_KEY") || "your-access-key";
|
||||
const minioSecretKey = Deno.env.get("S3_SECRET_ACCESS_KEY") || "your-secret-key";
|
||||
const minioBucketName = "silvester23";
|
||||
|
||||
const minioClient = new Client({
|
||||
endPoint: minioEndpoint,
|
||||
accessKey: minioAccessKey,
|
||||
secretKey: minioSecretKey,
|
||||
});
|
||||
|
||||
|
||||
const objects: MinioObject[] = [];
|
||||
|
||||
const objectStream = minioClient.listObjects(minioBucketName);
|
||||
|
||||
for await (const obj of objectStream) {
|
||||
objects.push({
|
||||
name: obj.name,
|
||||
});
|
||||
}
|
||||
|
||||
// Process and upload images
|
||||
for (const obj of objects) {
|
||||
const pngFilePath = obj.name;
|
||||
const jpgFilePath = `${pngFilePath.slice(0, -4)}.jpg`;
|
||||
|
||||
// Check if the PNG file exists and there is no corresponding JPG file
|
||||
if (!objects.some((o) => o.name === jpgFilePath)) {
|
||||
// Download the PNG file from MinIO
|
||||
const pngBuffer = await minioClient.getObject(minioBucketName, pngFilePath);
|
||||
console.log(`Downloaded ${pngFilePath} from MinIO`);
|
||||
|
||||
// Use Jimp to compress and convert the PNG to JPG
|
||||
const image = await Jimp.read(`http://s3-api.app.max-richter.dev/silvester23/${pngFilePath}`);
|
||||
const jpgBuffer = await image.quality(80).getBufferAsync(Jimp.MIME_JPEG);
|
||||
|
||||
// Upload the JPG buffer back to the same MinIO bucket
|
||||
await minioClient.putObject(minioBucketName, jpgFilePath, jpgBuffer, {
|
||||
'Content-Type': 'image/jpeg',
|
||||
});
|
||||
|
||||
console.log(`Uploaded ${jpgFilePath} to MinIO`);
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@
|
||||
"@sveltejs/kit": "^1.27.5",
|
||||
"@typescript-eslint/eslint-plugin": "^6.10.0",
|
||||
"@typescript-eslint/parser": "^6.10.0",
|
||||
"dotenv": "^16.3.1",
|
||||
"eslint": "^8.53.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-svelte": "^2.35.0",
|
||||
@ -34,6 +35,7 @@
|
||||
"jimp": "^0.22.10",
|
||||
"minio": "^7.1.3",
|
||||
"openai": "^4.17.4",
|
||||
"pocketbase": "^0.19.0"
|
||||
"pocketbase": "^0.19.0",
|
||||
"sharp": "^0.32.6"
|
||||
}
|
||||
}
|
||||
|
249
pnpm-lock.yaml
@ -20,6 +20,9 @@ dependencies:
|
||||
pocketbase:
|
||||
specifier: ^0.19.0
|
||||
version: 0.19.0
|
||||
sharp:
|
||||
specifier: ^0.32.6
|
||||
version: 0.32.6
|
||||
|
||||
devDependencies:
|
||||
'@sveltejs/adapter-node':
|
||||
@ -34,6 +37,9 @@ devDependencies:
|
||||
'@typescript-eslint/parser':
|
||||
specifier: ^6.10.0
|
||||
version: 6.10.0(eslint@8.53.0)(typescript@5.2.2)
|
||||
dotenv:
|
||||
specifier: ^16.3.1
|
||||
version: 16.3.1
|
||||
eslint:
|
||||
specifier: ^8.53.0
|
||||
version: 8.53.0
|
||||
@ -1171,6 +1177,10 @@ packages:
|
||||
dequal: 2.0.3
|
||||
dev: true
|
||||
|
||||
/b4a@1.6.4:
|
||||
resolution: {integrity: sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==}
|
||||
dev: false
|
||||
|
||||
/balanced-match@1.0.2:
|
||||
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
||||
dev: true
|
||||
@ -1192,6 +1202,14 @@ packages:
|
||||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/bl@4.1.0:
|
||||
resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
|
||||
dependencies:
|
||||
buffer: 5.7.1
|
||||
inherits: 2.0.4
|
||||
readable-stream: 3.6.2
|
||||
dev: false
|
||||
|
||||
/block-stream2@2.1.0:
|
||||
resolution: {integrity: sha512-suhjmLI57Ewpmq00qaygS8UgEq2ly2PCItenIyhMqVjo4t4pGzqMvfgJuX8iWTeSDdfSSqS6j38fL4ToNL7Pfg==}
|
||||
dependencies:
|
||||
@ -1290,6 +1308,10 @@ packages:
|
||||
fsevents: 2.3.3
|
||||
dev: true
|
||||
|
||||
/chownr@1.1.4:
|
||||
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
|
||||
dev: false
|
||||
|
||||
/code-red@1.0.4:
|
||||
resolution: {integrity: sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==}
|
||||
dependencies:
|
||||
@ -1305,11 +1327,24 @@ packages:
|
||||
engines: {node: '>=7.0.0'}
|
||||
dependencies:
|
||||
color-name: 1.1.4
|
||||
dev: true
|
||||
|
||||
/color-name@1.1.4:
|
||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||
dev: true
|
||||
|
||||
/color-string@1.9.1:
|
||||
resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
|
||||
dependencies:
|
||||
color-name: 1.1.4
|
||||
simple-swizzle: 0.2.2
|
||||
dev: false
|
||||
|
||||
/color@4.2.3:
|
||||
resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==}
|
||||
engines: {node: '>=12.5.0'}
|
||||
dependencies:
|
||||
color-convert: 2.0.1
|
||||
color-string: 1.9.1
|
||||
dev: false
|
||||
|
||||
/combined-stream@1.0.8:
|
||||
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
||||
@ -1374,6 +1409,18 @@ packages:
|
||||
engines: {node: '>=0.10'}
|
||||
dev: false
|
||||
|
||||
/decompress-response@6.0.0:
|
||||
resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
mimic-response: 3.1.0
|
||||
dev: false
|
||||
|
||||
/deep-extend@0.6.0:
|
||||
resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
|
||||
engines: {node: '>=4.0.0'}
|
||||
dev: false
|
||||
|
||||
/deep-is@0.1.4:
|
||||
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
|
||||
dev: true
|
||||
@ -1407,6 +1454,11 @@ packages:
|
||||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/detect-libc@2.0.2:
|
||||
resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==}
|
||||
engines: {node: '>=8'}
|
||||
dev: false
|
||||
|
||||
/devalue@4.3.2:
|
||||
resolution: {integrity: sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg==}
|
||||
dev: true
|
||||
@ -1436,12 +1488,23 @@ packages:
|
||||
resolution: {integrity: sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==}
|
||||
dev: false
|
||||
|
||||
/dotenv@16.3.1:
|
||||
resolution: {integrity: sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==}
|
||||
engines: {node: '>=12'}
|
||||
dev: true
|
||||
|
||||
/ecdsa-sig-formatter@1.0.11:
|
||||
resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==}
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
dev: false
|
||||
|
||||
/end-of-stream@1.4.4:
|
||||
resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
|
||||
dependencies:
|
||||
once: 1.4.0
|
||||
dev: false
|
||||
|
||||
/es6-promise@3.3.1:
|
||||
resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==}
|
||||
dev: true
|
||||
@ -1644,6 +1707,11 @@ packages:
|
||||
resolution: {integrity: sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw==}
|
||||
dev: false
|
||||
|
||||
/expand-template@2.0.3:
|
||||
resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
|
||||
engines: {node: '>=6'}
|
||||
dev: false
|
||||
|
||||
/extend@3.0.2:
|
||||
resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
|
||||
dev: false
|
||||
@ -1652,6 +1720,10 @@ packages:
|
||||
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
||||
dev: true
|
||||
|
||||
/fast-fifo@1.3.2:
|
||||
resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==}
|
||||
dev: false
|
||||
|
||||
/fast-glob@3.3.2:
|
||||
resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
|
||||
engines: {node: '>=8.6.0'}
|
||||
@ -1760,6 +1832,10 @@ packages:
|
||||
web-streams-polyfill: 4.0.0-beta.3
|
||||
dev: false
|
||||
|
||||
/fs-constants@1.0.0:
|
||||
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
|
||||
dev: false
|
||||
|
||||
/fs.realpath@1.0.0:
|
||||
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
|
||||
dev: true
|
||||
@ -1815,6 +1891,10 @@ packages:
|
||||
omggif: 1.0.10
|
||||
dev: false
|
||||
|
||||
/github-from-package@0.0.0:
|
||||
resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
|
||||
dev: false
|
||||
|
||||
/glob-parent@5.1.2:
|
||||
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
|
||||
engines: {node: '>= 6'}
|
||||
@ -2039,6 +2119,10 @@ packages:
|
||||
/inherits@2.0.4:
|
||||
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
||||
|
||||
/ini@1.3.8:
|
||||
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
|
||||
dev: false
|
||||
|
||||
/ipaddr.js@2.1.0:
|
||||
resolution: {integrity: sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==}
|
||||
engines: {node: '>= 10'}
|
||||
@ -2052,6 +2136,10 @@ packages:
|
||||
has-tostringtag: 1.0.0
|
||||
dev: false
|
||||
|
||||
/is-arrayish@0.3.2:
|
||||
resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
|
||||
dev: false
|
||||
|
||||
/is-binary-path@2.1.0:
|
||||
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
|
||||
engines: {node: '>=8'}
|
||||
@ -2279,7 +2367,6 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
yallist: 4.0.0
|
||||
dev: true
|
||||
|
||||
/magic-string@0.27.0:
|
||||
resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==}
|
||||
@ -2338,6 +2425,11 @@ packages:
|
||||
hasBin: true
|
||||
dev: false
|
||||
|
||||
/mimic-response@3.1.0:
|
||||
resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
|
||||
engines: {node: '>=10'}
|
||||
dev: false
|
||||
|
||||
/min-document@2.19.0:
|
||||
resolution: {integrity: sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==}
|
||||
dependencies:
|
||||
@ -2364,7 +2456,6 @@ packages:
|
||||
|
||||
/minimist@1.2.8:
|
||||
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
|
||||
dev: true
|
||||
|
||||
/minio@7.1.3:
|
||||
resolution: {integrity: sha512-xPrLjWkTT5E7H7VnzOjF//xBp9I40jYB4aWhb2xTFopXXfw+Wo82DDWngdUju7Doy3Wk7R8C4LAgwhLHHnf0wA==}
|
||||
@ -2386,6 +2477,10 @@ packages:
|
||||
xml2js: 0.5.0
|
||||
dev: false
|
||||
|
||||
/mkdirp-classic@0.5.3:
|
||||
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
|
||||
dev: false
|
||||
|
||||
/mkdirp@0.5.6:
|
||||
resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
|
||||
hasBin: true
|
||||
@ -2416,10 +2511,25 @@ packages:
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/napi-build-utils@1.0.2:
|
||||
resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
|
||||
dev: false
|
||||
|
||||
/natural-compare@1.4.0:
|
||||
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
|
||||
dev: true
|
||||
|
||||
/node-abi@3.51.0:
|
||||
resolution: {integrity: sha512-SQkEP4hmNWjlniS5zdnfIXTk1x7Ome85RDzHlTbBtzE97Gfwz/Ipw4v/Ryk20DWIy3yCNVLVlGKApCnmvYoJbA==}
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
semver: 7.5.4
|
||||
dev: false
|
||||
|
||||
/node-addon-api@6.1.0:
|
||||
resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==}
|
||||
dev: false
|
||||
|
||||
/node-domexception@1.0.0:
|
||||
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
|
||||
engines: {node: '>=10.5.0'}
|
||||
@ -2454,7 +2564,6 @@ packages:
|
||||
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
|
||||
dependencies:
|
||||
wrappy: 1.0.2
|
||||
dev: true
|
||||
|
||||
/openai@4.17.4:
|
||||
resolution: {integrity: sha512-ThRFkl6snLbcAKS58St7N3CaKuI5WdYUvIjPvf4s+8SdymgNtOfzmZcZXVcCefx04oKFnvZJvIcTh3eAFUUhAQ==}
|
||||
@ -2652,6 +2761,25 @@ packages:
|
||||
source-map-js: 1.0.2
|
||||
dev: true
|
||||
|
||||
/prebuild-install@7.1.1:
|
||||
resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
detect-libc: 2.0.2
|
||||
expand-template: 2.0.3
|
||||
github-from-package: 0.0.0
|
||||
minimist: 1.2.8
|
||||
mkdirp-classic: 0.5.3
|
||||
napi-build-utils: 1.0.2
|
||||
node-abi: 3.51.0
|
||||
pump: 3.0.0
|
||||
rc: 1.2.8
|
||||
simple-get: 4.0.1
|
||||
tar-fs: 2.1.1
|
||||
tunnel-agent: 0.6.0
|
||||
dev: false
|
||||
|
||||
/prelude-ls@1.2.1:
|
||||
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
@ -2678,6 +2806,13 @@ packages:
|
||||
engines: {node: '>= 0.6.0'}
|
||||
dev: false
|
||||
|
||||
/pump@3.0.0:
|
||||
resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==}
|
||||
dependencies:
|
||||
end-of-stream: 1.4.4
|
||||
once: 1.4.0
|
||||
dev: false
|
||||
|
||||
/punycode@2.3.1:
|
||||
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
||||
engines: {node: '>=6'}
|
||||
@ -2704,6 +2839,20 @@ packages:
|
||||
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
||||
dev: true
|
||||
|
||||
/queue-tick@1.0.1:
|
||||
resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==}
|
||||
dev: false
|
||||
|
||||
/rc@1.2.8:
|
||||
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
deep-extend: 0.6.0
|
||||
ini: 1.3.8
|
||||
minimist: 1.2.8
|
||||
strip-json-comments: 2.0.1
|
||||
dev: false
|
||||
|
||||
/readable-stream@3.6.2:
|
||||
resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
|
||||
engines: {node: '>= 6'}
|
||||
@ -2808,7 +2957,6 @@ packages:
|
||||
hasBin: true
|
||||
dependencies:
|
||||
lru-cache: 6.0.0
|
||||
dev: true
|
||||
|
||||
/set-cookie-parser@2.6.0:
|
||||
resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==}
|
||||
@ -2824,6 +2972,21 @@ packages:
|
||||
has-property-descriptors: 1.0.1
|
||||
dev: false
|
||||
|
||||
/sharp@0.32.6:
|
||||
resolution: {integrity: sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==}
|
||||
engines: {node: '>=14.15.0'}
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
color: 4.2.3
|
||||
detect-libc: 2.0.2
|
||||
node-addon-api: 6.1.0
|
||||
prebuild-install: 7.1.1
|
||||
semver: 7.5.4
|
||||
simple-get: 4.0.1
|
||||
tar-fs: 3.0.4
|
||||
tunnel-agent: 0.6.0
|
||||
dev: false
|
||||
|
||||
/shebang-command@2.0.0:
|
||||
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
||||
engines: {node: '>=8'}
|
||||
@ -2844,6 +3007,24 @@ packages:
|
||||
object-inspect: 1.13.1
|
||||
dev: false
|
||||
|
||||
/simple-concat@1.0.1:
|
||||
resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
|
||||
dev: false
|
||||
|
||||
/simple-get@4.0.1:
|
||||
resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==}
|
||||
dependencies:
|
||||
decompress-response: 6.0.0
|
||||
once: 1.4.0
|
||||
simple-concat: 1.0.1
|
||||
dev: false
|
||||
|
||||
/simple-swizzle@0.2.2:
|
||||
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
|
||||
dependencies:
|
||||
is-arrayish: 0.3.2
|
||||
dev: false
|
||||
|
||||
/sirv@2.0.3:
|
||||
resolution: {integrity: sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==}
|
||||
engines: {node: '>= 10'}
|
||||
@ -2878,6 +3059,13 @@ packages:
|
||||
engines: {node: '>=6'}
|
||||
dev: false
|
||||
|
||||
/streamx@2.15.4:
|
||||
resolution: {integrity: sha512-uSXKl88bibiUCQ1eMpItRljCzDENcDx18rsfDmV79r0e/ThfrAwxG4Y2FarQZ2G4/21xcOKmFFd1Hue+ZIDwHw==}
|
||||
dependencies:
|
||||
fast-fifo: 1.3.2
|
||||
queue-tick: 1.0.1
|
||||
dev: false
|
||||
|
||||
/strict-uri-encode@2.0.0:
|
||||
resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==}
|
||||
engines: {node: '>=4'}
|
||||
@ -2903,6 +3091,11 @@ packages:
|
||||
min-indent: 1.0.1
|
||||
dev: true
|
||||
|
||||
/strip-json-comments@2.0.1:
|
||||
resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: false
|
||||
|
||||
/strip-json-comments@3.1.1:
|
||||
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
|
||||
engines: {node: '>=8'}
|
||||
@ -3052,6 +3245,42 @@ packages:
|
||||
periscopic: 3.1.0
|
||||
dev: true
|
||||
|
||||
/tar-fs@2.1.1:
|
||||
resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==}
|
||||
dependencies:
|
||||
chownr: 1.1.4
|
||||
mkdirp-classic: 0.5.3
|
||||
pump: 3.0.0
|
||||
tar-stream: 2.2.0
|
||||
dev: false
|
||||
|
||||
/tar-fs@3.0.4:
|
||||
resolution: {integrity: sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==}
|
||||
dependencies:
|
||||
mkdirp-classic: 0.5.3
|
||||
pump: 3.0.0
|
||||
tar-stream: 3.1.6
|
||||
dev: false
|
||||
|
||||
/tar-stream@2.2.0:
|
||||
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
|
||||
engines: {node: '>=6'}
|
||||
dependencies:
|
||||
bl: 4.1.0
|
||||
end-of-stream: 1.4.4
|
||||
fs-constants: 1.0.0
|
||||
inherits: 2.0.4
|
||||
readable-stream: 3.6.2
|
||||
dev: false
|
||||
|
||||
/tar-stream@3.1.6:
|
||||
resolution: {integrity: sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==}
|
||||
dependencies:
|
||||
b4a: 1.6.4
|
||||
fast-fifo: 1.3.2
|
||||
streamx: 2.15.4
|
||||
dev: false
|
||||
|
||||
/text-table@0.2.0:
|
||||
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
|
||||
dev: true
|
||||
@ -3114,6 +3343,12 @@ packages:
|
||||
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
|
||||
dev: true
|
||||
|
||||
/tunnel-agent@0.6.0:
|
||||
resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
dev: false
|
||||
|
||||
/type-check@0.4.0:
|
||||
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
@ -3277,7 +3512,6 @@ packages:
|
||||
|
||||
/wrappy@1.0.2:
|
||||
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
|
||||
dev: true
|
||||
|
||||
/xhr@2.6.0:
|
||||
resolution: {integrity: sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==}
|
||||
@ -3324,7 +3558,6 @@ packages:
|
||||
|
||||
/yallist@4.0.0:
|
||||
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
|
||||
dev: true
|
||||
|
||||
/yaml@1.10.2:
|
||||
resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
|
||||
|
@ -1,20 +1,56 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
export let src: string;
|
||||
export let alt = '';
|
||||
const u = new URL(src);
|
||||
const filename = u.pathname.split('/').pop() || '9a8sda';
|
||||
const int = (parseInt(filename?.slice(0, 8), 16) % 7) + 1;
|
||||
const frame = `/frames/frame_0${int}`;
|
||||
|
||||
let handlingError = false;
|
||||
function handleError() {
|
||||
if (handlingError) return;
|
||||
handlingError = true;
|
||||
console.log('error', { src });
|
||||
const oldSrc = src;
|
||||
src = '';
|
||||
setTimeout(() => {
|
||||
src = oldSrc;
|
||||
handlingError = false;
|
||||
}, 1000);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="frame" style="--frame: url(/frames/frame_0{int}.png)">
|
||||
<img src="/hang.png" class="hang" />
|
||||
<picture>
|
||||
<picture class="painting-frame">
|
||||
<!-- Load AVIF format -->
|
||||
<source srcset="{frame}.avif" type="image/avif" />
|
||||
|
||||
<!-- If AVIF is not supported, load WebP format -->
|
||||
<source srcset="{frame}.webp" type="image/webp" />
|
||||
|
||||
<!-- If neither AVIF nor WebP are supported, load PNG format -->
|
||||
<img src="{frame}.png" alt="Painting Frame" />
|
||||
</picture>
|
||||
|
||||
<img src="/hang.png" class="hang" alt="painting hanging cord" />
|
||||
<picture class="person">
|
||||
<source srcset={src.replace('.png', '.avif')} type="image/avif" />
|
||||
<source srcset={src.replace('.png', '.webp')} type="image/webp" />
|
||||
<source srcset={src.replace('.png', '.jpg')} type="image/jpeg" />
|
||||
<img {src} {alt} />
|
||||
<img {src} {alt} on:error={() => handleError()} />
|
||||
</picture>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.painting-frame > * {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
filter: drop-shadow(0px 0px 10px black) brightness(0.6) contrast(1.1);
|
||||
}
|
||||
.hang {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
@ -34,13 +70,13 @@
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background: var(--frame);
|
||||
/* background: var(--frame); */
|
||||
background-position: center center;
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
filter: drop-shadow(0px 0px 20px black);
|
||||
}
|
||||
img {
|
||||
.person img {
|
||||
z-index: -1;
|
||||
max-width: 70%;
|
||||
max-height: 70%;
|
||||
|
@ -22,6 +22,7 @@
|
||||
portraitHairType?: 'straight' | 'curly' | 'bald';
|
||||
portraitHairColor?: 'red' | 'brown' | 'blonde' | 'black' | 'grey' | 'white';
|
||||
portraitHairLength?: 'short' | 'medium' | 'long';
|
||||
portraitSkinColor?: 'very light' | 'light' | 'medium' | 'dark' | 'very dark';
|
||||
portraitAccepted?: boolean;
|
||||
portraitPublic?: boolean;
|
||||
|
||||
@ -62,7 +63,8 @@
|
||||
body: JSON.stringify({
|
||||
hairType: $data.portraitHairType,
|
||||
hairColor: $data.portraitHairColor,
|
||||
hairLength: $data.portraitHairLength
|
||||
hairLength: $data.portraitHairLength,
|
||||
skinColor: $data.portraitSkinColor
|
||||
})
|
||||
});
|
||||
|
||||
@ -224,6 +226,14 @@
|
||||
{#if $data.providePortrait && !loadingPortrait && !$data.portraitUrl}
|
||||
<p>
|
||||
Wir werden {$data.adelsTitel || $data.name} mit
|
||||
<select placeholder="Typ" bind:value={$data.portraitSkinColor}>
|
||||
<option value="very light">sehr heller</option>
|
||||
<option value="light">heller</option>
|
||||
<option value="medium">medium</option>
|
||||
<option value="dark">dunkler</option>
|
||||
<option value="very dark">sehr dunkler</option>
|
||||
</select>
|
||||
Haut und
|
||||
<select placeholder="Typ" bind:value={$data.portraitHairType}>
|
||||
<option value="straight">glatten</option>
|
||||
<option value="curly">lockigen</option>
|
||||
@ -297,21 +307,17 @@
|
||||
margin-bottom: 200px;
|
||||
}
|
||||
|
||||
.portrait-frame {
|
||||
margin-top: 100px;
|
||||
}
|
||||
|
||||
.portrait-frame.loaded {
|
||||
margin-top: 100px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
button {
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
border-radius: 2px;
|
||||
padding: 5px 9px;
|
||||
margin-right: 10px;
|
||||
background: #866831;
|
||||
box-shadow: 3px 3px 8px #e1b45f inset;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ export async function getPublicPortraits() {
|
||||
})).items
|
||||
}
|
||||
|
||||
export function createPerson({ name, confidence, portrait, portrait_public, noble_name, hair_color, hair_type, hair_length }: { name: string, portrait: string, portrait_public: boolean, hair_type: string, hair_length: string, hair_color: string, confidence: number, noble_name: string }) {
|
||||
export function createPerson({ name, confidence, portrait, portrait_public, noble_name, hair_color, hair_type, hair_length, skin_color }: { name: string, portrait: string, portrait_public: boolean, hair_type: string, hair_length: string, hair_color: string, confidence: number, noble_name: string, skin_color: string }) {
|
||||
return pb.collection("invites").create({
|
||||
name,
|
||||
confidence,
|
||||
@ -18,6 +18,7 @@ export function createPerson({ name, confidence, portrait, portrait_public, nobl
|
||||
noble_name,
|
||||
hair_type,
|
||||
hair_length,
|
||||
hair_color
|
||||
hair_color,
|
||||
skin_color
|
||||
})
|
||||
}
|
||||
|
@ -1,8 +1,43 @@
|
||||
import { json } from "@sveltejs/kit";
|
||||
import Jimp from "jimp";
|
||||
import type { RequestHandler } from "./$types";
|
||||
import { putObject } from "$lib/helpers/minio";
|
||||
import { generateImage } from "$lib/helpers/stability";
|
||||
import sharp from "sharp";
|
||||
|
||||
|
||||
async function compressImage(imageName: string, imageBuffer: Buffer) {
|
||||
|
||||
const ja = performance.now()
|
||||
const jpgBuffer = await sharp(imageBuffer)
|
||||
.jpeg({ quality: 70 })
|
||||
.withMetadata()
|
||||
.toBuffer();
|
||||
|
||||
await putObject(imageName.replace(".png", ".jpg"), jpgBuffer, { "Content-Type": "image/jpeg" });
|
||||
|
||||
const jb = performance.now() - ja;
|
||||
console.log(`[AI] JPG compression took ${jb}ms`)
|
||||
|
||||
const wa = performance.now()
|
||||
const webpBuffer = await sharp(imageBuffer)
|
||||
.webp({ quality: 70 })
|
||||
.withMetadata()
|
||||
.toBuffer()
|
||||
|
||||
await putObject(imageName.replace(".png", ".webp"), webpBuffer, { "Content-Type": "image/webp" });
|
||||
const wb = performance.now() - wa;
|
||||
console.log(`[AI] WebP compression took ${wb}ms`)
|
||||
|
||||
const aa = performance.now()
|
||||
const aviBuffer = await sharp(imageBuffer)
|
||||
.avif({ quality: 70 })
|
||||
.withMetadata()
|
||||
.toBuffer()
|
||||
|
||||
await putObject(imageName.replace(".png", ".avif"), aviBuffer, { "Content-Type": "image/avif" });
|
||||
const ab = performance.now() - aa;
|
||||
console.log(`[AI] AVIF compression took ${ab}ms`)
|
||||
}
|
||||
|
||||
export const POST: RequestHandler = async ({ params, request }) => {
|
||||
|
||||
@ -14,33 +49,39 @@ export const POST: RequestHandler = async ({ params, request }) => {
|
||||
throw new Error("Name too long");
|
||||
}
|
||||
|
||||
const { hairType, hairColor, hairLength } = await request.json();
|
||||
console.log(hairType, hairColor, hairLength)
|
||||
const { hairType, hairColor, hairLength, skinColor } = await request.json();
|
||||
console.log(`[AI] Generating image for ${inputName} ${JSON.stringify({ hairType, hairColor, hairLength, skinColor })}`)
|
||||
|
||||
if (!hairType || !hairColor || !hairLength) {
|
||||
throw new Error("Missing hairType, hairColor or hairLength");
|
||||
}
|
||||
|
||||
const prompt = `realistic portrait oil painting of a masked ${inputName}, baroque, in the style of Charles Vess, masked ball attire, opulence, mystery, elegance, ${hairLength} ${hairType} ${hairColor} hair, darker skin`;
|
||||
const prompt = `realistic portrait oil painting of a masked ${inputName}, baroque, in the style of Charles Vess, masked ball attire, opulence, mystery, elegance, ${hairLength} ${hairType} ${hairColor} hair, ${skinColor} skin`;
|
||||
const negativePrompt = "blurry, multiple persons, picture frame"
|
||||
|
||||
const a = performance.now()
|
||||
// #const image = await openai.image(prompt);
|
||||
const image = await generateImage(prompt, negativePrompt);
|
||||
const duration = performance.now() - a;
|
||||
const d = performance.now() - a;
|
||||
console.log(`[AI] Image generation took ${d}ms`)
|
||||
|
||||
|
||||
const imageName = `${Math.random().toString(16).substring(3, 10)}-${inputName.toLowerCase().split(" ").slice(0, 5).join("-").slice(0, 25)}.png`
|
||||
|
||||
await putObject(imageName, Buffer.from(image.base64, 'base64'), { "Content-Type": "image/png" });
|
||||
const imageBuffer = Buffer.from(image.base64, 'base64');
|
||||
|
||||
const img = await Jimp.read(Buffer.from(image.base64, "base64"));
|
||||
const jpgBuffer = await img.quality(70).getBufferAsync(Jimp.MIME_JPEG);
|
||||
const a2 = performance.now()
|
||||
const pngBuffer = await sharp(imageBuffer)
|
||||
.png({ compressionLevel: 9, adaptiveFiltering: true, force: true })
|
||||
.withMetadata()
|
||||
.toBuffer()
|
||||
|
||||
await putObject(imageName.replace(".png", ".jpg"), jpgBuffer, { "Content-Type": "image/jpeg" });
|
||||
await putObject(imageName, pngBuffer, { "Content-Type": "image/png" });
|
||||
const d2 = performance.now() - a2;
|
||||
console.log(`[AI] PNG compression took ${d2}ms`)
|
||||
|
||||
await compressImage(imageName, imageBuffer)
|
||||
|
||||
return json({
|
||||
duration,
|
||||
url: `https://s3-api.app.max-richter.dev/silvester23/${imageName}`
|
||||
url: `https://s3.max-richter.dev/silvester23/${imageName}`
|
||||
})
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ export const POST: RequestHandler = async ({ request }) => {
|
||||
hair_type: body.portraitHairType,
|
||||
hair_color: body.portraitHairColor,
|
||||
portrait_public: body.portraitPublic,
|
||||
skin_color: body.portraitSkinColor,
|
||||
});
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
|
@ -93,6 +93,7 @@
|
||||
:global(html) {
|
||||
background-image: url(/pattern.jpg) !important;
|
||||
backdrop-filter: brightness(0.5) !important;
|
||||
background-size: 25%;
|
||||
}
|
||||
.wrapper {
|
||||
max-width: 1300px;
|
||||
|
@ -1,7 +0,0 @@
|
||||
<script lang="ts">
|
||||
import ImageFrame from '$lib/components/ImageFrame.svelte';
|
||||
</script>
|
||||
|
||||
<ImageFrame
|
||||
src="https://s3-api.app.max-richter.dev/silvester23/13770f0-earl-maximus-of-richterla.png"
|
||||
/>
|
BIN
static/frames/frame_01.avif
Normal file
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 427 KiB |
BIN
static/frames/frame_01.webp
Normal file
After Width: | Height: | Size: 43 KiB |
BIN
static/frames/frame_02.avif
Normal file
Before Width: | Height: | Size: 669 KiB After Width: | Height: | Size: 613 KiB |
BIN
static/frames/frame_02.webp
Normal file
After Width: | Height: | Size: 49 KiB |
BIN
static/frames/frame_03.avif
Normal file
Before Width: | Height: | Size: 1.5 MiB After Width: | Height: | Size: 417 KiB |
BIN
static/frames/frame_03.webp
Normal file
After Width: | Height: | Size: 43 KiB |
BIN
static/frames/frame_04.avif
Normal file
Before Width: | Height: | Size: 1.8 MiB After Width: | Height: | Size: 608 KiB |
BIN
static/frames/frame_04.webp
Normal file
After Width: | Height: | Size: 74 KiB |
BIN
static/frames/frame_05.avif
Normal file
Before Width: | Height: | Size: 12 MiB After Width: | Height: | Size: 479 KiB |
BIN
static/frames/frame_05.webp
Normal file
After Width: | Height: | Size: 80 KiB |
BIN
static/frames/frame_06.avif
Normal file
Before Width: | Height: | Size: 1.8 MiB After Width: | Height: | Size: 397 KiB |
BIN
static/frames/frame_06.webp
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
static/frames/frame_07.avif
Normal file
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 424 KiB |
BIN
static/frames/frame_07.webp
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
static/frames/frame_08.avif
Normal file
Before Width: | Height: | Size: 453 KiB After Width: | Height: | Size: 328 KiB |
BIN
static/frames/frame_08.webp
Normal file
After Width: | Height: | Size: 37 KiB |