Skip to content

Commit

Permalink
use threaded workers
Browse files Browse the repository at this point in the history
  • Loading branch information
Razzmatazzz committed Oct 21, 2023
1 parent f6d76dd commit 0e972b3
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 40 deletions.
67 changes: 27 additions & 40 deletions index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import promptSync from 'prompt-sync';
import dotenv from 'dotenv';
import { DateTime } from 'luxon';

import WorkerPromise from './worker-promise.mjs';

dotenv.config();
const prompt = promptSync();

Expand Down Expand Up @@ -249,13 +251,13 @@ const prompt = promptSync();
const minZoom = process.env.MIN_ZOOM || 0;

await fs.mkdir('output').catch(error => {
if (!error.code === 'EEXIST') {
if (error.code !== 'EEXIST') {
console.log(error);
}
});

await fs.mkdir(`output/${mapName}`).catch(error => {
if (!error.code === 'EEXIST') {
if (error.code !== 'EEXIST') {
console.log(error);
}
});
Expand All @@ -280,7 +282,7 @@ const prompt = promptSync();

const tiles = [];
const tileCheck = async () => {
if (tiles.length > 32) {
if (tiles.length > 8) {
await Promise.all(tiles);
tiles.length = 0;
}
Expand All @@ -289,56 +291,41 @@ const prompt = promptSync();
const zoomSpinner = ora({text: mapName, prefixText: '0.00%'});
zoomSpinner.start();
const startTime = DateTime.now();
const inputImageBuffer = (await inputImage.toBuffer()).buffer;
for (let z = minZoom; z <= maxZoom; z++) {
const scaledSize = tileSize * Math.pow(2, z);
zoomSpinner.suffixText = `| z ${z}/${maxZoom} Resizing to ${scaledSize}`;
const scaledMap = sharp(
await inputImage
.clone()
.resize({
width: scaledSize,
height: scaledSize,
fit: sharp.fit.contain,
position: sharp.gravity.northwest,
background: {r: 1, g: 0, b: 0, alpha: 0}
})
.toBuffer(),
{unlimited: true, limitInputPixels: false}
);
const workerResult = await new WorkerPromise('resize-worker.mjs').start({tileSize, z, image: inputImageBuffer});
await fs.mkdir(`output/${mapName}/${z}`).catch(error => {
if (!error.code === 'EEXIST') {
if (error.code !== 'EEXIST') {
console.log(error);
}
});
for (let x = 0; x < scaledSize / tileSize; x++) {
await fs.mkdir(`output/${mapName}/${z}/${x}`).catch(error => {
if (!error.code === 'EEXIST') {
if (error.code !== 'EEXIST') {
console.log(error);
}
});
for (let y = 0; y < scaledSize / tileSize; y++) {
tiles.push(
scaledMap
.clone()
.extract({
left: x * tileSize,
top: y * tileSize,
width: tileSize,
height: tileSize
})
.toFile(`output/${mapName}/${z}/${x}/${y}.png`)
.then(() => {
zoomSpinner.suffixText = `| z ${z}/${maxZoom} | x ${x}/${
scaledSize / tileSize - 1
} | y ${y}/${scaledSize / tileSize - 1}`;
completedTiles++;
zoomSpinner.prefixText = `${(
Math.round(
(completedTiles / totalTiles) * 10000
) / 100
).toFixed(2)}%`;
})
);
tiles.push(new WorkerPromise('tile-worker.mjs').start({
mapName,
tileSize,
x,
y,
z,
image: workerResult.image,
}).then(() => {
zoomSpinner.suffixText = `| z ${z}/${maxZoom} | x ${x}/${
scaledSize / tileSize - 1
} | y ${y}/${scaledSize / tileSize - 1}`;
completedTiles++;
zoomSpinner.prefixText = `${(
Math.round(
(completedTiles / totalTiles) * 10000
) / 100
).toFixed(2)}%`;
}));
await tileCheck();
}
}
Expand Down
26 changes: 26 additions & 0 deletions resize-worker.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { parentPort } from 'worker_threads';

import sharp from 'sharp';

parentPort.once('message', async (options) => {
const tileSize = parseInt(options.tileSize);
const z = parseInt(options.z);
const inputImage = sharp(options.image, {unlimited: true, limitInputPixels: false});
const metadata = await inputImage.metadata();

const scaledSize = tileSize * Math.pow(2, z);

if (scaledSize !== metadata.width || scaledSize !== metadata.height) {
inputImage.resize({
width: scaledSize,
height: scaledSize,
fit: sharp.fit.contain,
position: sharp.gravity.northwest,
background: {r: 1, g: 0, b: 0, alpha: 0}
});
}

const imageBuffer = await inputImage.toBuffer();

parentPort.postMessage({message: 'complete', image: imageBuffer.buffer});
});
28 changes: 28 additions & 0 deletions tile-worker.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { parentPort } from 'worker_threads';

import sharp from 'sharp';

parentPort.once('message', async (options) => {
const mapName = options.mapName;
const tileSize = parseInt(options.tileSize);
const x = parseInt(options.x);
const y = parseInt(options.y);
const z = parseInt(options.z);
const inputImage = sharp(options.image, {unlimited: true, limitInputPixels: false});
const metadata = await inputImage.metadata();

const scaledSize = tileSize * Math.pow(2, z);

const filePath = `output/${mapName}/${z}/${x}/${y}.png`;

if (scaledSize !== metadata.width || scaledSize !== metadata.height) {
await inputImage.extract({
left: x * tileSize,
top: y * tileSize,
width: tileSize,
height: tileSize
}).toFile(filePath);
}

parentPort.postMessage({message: 'complete'});
});
25 changes: 25 additions & 0 deletions worker-promise.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Worker } from 'worker_threads';

class WorkerPromise {
constructor(workerFile) {
this.promise = new Promise((resolve, reject) => {
this.worker = new Worker(`./${workerFile}`);
this.worker.on('message', (data) => {
//console.log(data);
if (data.message === 'complete') {
resolve(data);
}
});
this.worker.on('error', (msg) => {
reject(msg);
});
});
}

start(options) {
this.worker.postMessage(options);
return this.promise;
}
}

export default WorkerPromise;

0 comments on commit 0e972b3

Please sign in to comment.