Done
This commit is contained in:
@@ -2,4 +2,7 @@ images/processed
|
|||||||
images/processed_backup
|
images/processed_backup
|
||||||
images/background_removed
|
images/background_removed
|
||||||
images/unprocessed
|
images/unprocessed
|
||||||
|
images/liveries_background_removed
|
||||||
|
images/liveries_unprocessed
|
||||||
|
images/liveries_processed
|
||||||
node_modules
|
node_modules
|
||||||
+88
-15
@@ -5,9 +5,35 @@ const inputDirectory = "images/unprocessed";
|
|||||||
const outputDirectory = "images/processed";
|
const outputDirectory = "images/processed";
|
||||||
const backgroundRemovedDirectory = "images/background_removed";
|
const backgroundRemovedDirectory = "images/background_removed";
|
||||||
const watermarkImage = "images/Watermark.png";
|
const watermarkImage = "images/Watermark.png";
|
||||||
|
|
||||||
|
const liveryInputDirectory = "images/liveries_unprocessed"
|
||||||
|
const liveryOutputDirectory = "images/liveries_processed"
|
||||||
|
const liveryBackgroundRemovedDirectory = "images/liveries_background_removed"
|
||||||
|
|
||||||
|
|
||||||
import Replicate from "replicate";
|
import Replicate from "replicate";
|
||||||
import sharp from "sharp";
|
import sharp from "sharp";
|
||||||
|
|
||||||
|
const convertToPng = async () => {
|
||||||
|
const pngFiles = fs
|
||||||
|
.readdirSync(outputDirectory)
|
||||||
|
.filter((file) => file.toLowerCase().endsWith(".png"));
|
||||||
|
|
||||||
|
for (const file of pngFiles) {
|
||||||
|
const filePath = path.join(outputDirectory, file);
|
||||||
|
const fileBuffer = fs.readFileSync(filePath);
|
||||||
|
const metadata = await sharp(fileBuffer).metadata();
|
||||||
|
|
||||||
|
if (metadata.format !== 'png') {
|
||||||
|
console.log(`Converting to PNG: ${filePath}`);
|
||||||
|
const pngData = await sharp(fileBuffer).png().toBuffer();
|
||||||
|
fs.writeFileSync(filePath, pngData);
|
||||||
|
console.log(`Converted: ${filePath}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
const removeWatermark = async () => {
|
const removeWatermark = async () => {
|
||||||
const replicate = new Replicate({ auth: process.env.REPLICATE_API_TOKEN });
|
const replicate = new Replicate({ auth: process.env.REPLICATE_API_TOKEN });
|
||||||
|
|
||||||
@@ -23,24 +49,9 @@ const removeWatermark = async () => {
|
|||||||
const filePath = path.join(inputDirectory, file);
|
const filePath = path.join(inputDirectory, file);
|
||||||
const outputPath = path.join(outputDirectory, file);
|
const outputPath = path.join(outputDirectory, file);
|
||||||
|
|
||||||
// Ensure the output directory exists before every write
|
|
||||||
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
||||||
|
|
||||||
if (fs.existsSync(outputPath)) {
|
if (fs.existsSync(outputPath)) {
|
||||||
const fileBuffer = fs.readFileSync(outputPath);
|
|
||||||
const metadata = await sharp(fileBuffer).metadata();
|
|
||||||
|
|
||||||
if (metadata.format !== 'png') {
|
|
||||||
console.log(`About to write to: ${outputPath}`);
|
|
||||||
console.log(`Dir exists: ${fs.existsSync(path.dirname(outputPath))}`);
|
|
||||||
console.log(`Dir writable:`, (() => { try { fs.accessSync(path.dirname(outputPath), fs.constants.W_OK); return true; } catch { return false; } })());
|
|
||||||
console.log(`File writable:`, (() => { try { fs.accessSync(outputPath, fs.constants.W_OK); return true; } catch { return false; } })());
|
|
||||||
const pngData = await sharp(fileBuffer).png().toBuffer();
|
|
||||||
console.log(`PNG buffer size: ${pngData.length}`);
|
|
||||||
fs.writeFileSync(outputPath, pngData);
|
|
||||||
console.log(`Write succeeded`);
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,9 +115,71 @@ const removeBackground = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const generateLiveries = async () => {
|
||||||
|
const replicate = new Replicate({ auth: process.env.REPLICATE_API_TOKEN });
|
||||||
|
|
||||||
|
const prompt = "Generate a 2D, side-view digital technical illustration of the identical plane pictured - with no wheels (MAKE SURE TO REMOVE ANY WHEELS). (correct the perspective of the plane so it is side view) (in Norebbo's style, preserving the livery markings exactly), with a plain white background (no shadows) and with some mild lighting and sheen effects, correcting perspective if the plane is not side-on. Make sure to remove any wheels if they are visible. DO NOT ADD ANYTHING TO THE LIVERY THAT IS NOT IN THE ORIGINAL PHOTO";
|
||||||
|
|
||||||
|
fs.mkdirSync(liveryOutputDirectory, { recursive: true });
|
||||||
|
|
||||||
|
const imageFiles = fs
|
||||||
|
.readdirSync(liveryInputDirectory)
|
||||||
|
.filter((file) => /\.(png|jpg|jpeg|webp)$/i.test(file));
|
||||||
|
|
||||||
|
for (const file of imageFiles) {
|
||||||
|
const filePath = path.join(liveryInputDirectory, file);
|
||||||
|
const ext = path.extname(file).toLowerCase();
|
||||||
|
const outputFile = ext !== ".png" ? file.replace(/\.[^.]+$/, ".png") : file;
|
||||||
|
const outputPath = path.join(liveryOutputDirectory, outputFile);
|
||||||
|
|
||||||
|
if (fs.existsSync(outputPath)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Processing: ${filePath}`);
|
||||||
|
|
||||||
|
const mimeType = ext === ".jpg" || ext === ".jpeg" ? "image/jpeg"
|
||||||
|
: ext === ".webp" ? "image/webp"
|
||||||
|
: "image/png";
|
||||||
|
|
||||||
|
const fileBuffer = fs.readFileSync(filePath);
|
||||||
|
const blob = new Blob([fileBuffer], { type: mimeType });
|
||||||
|
const uploadedFile = await replicate.files.create(blob, {
|
||||||
|
filename: file,
|
||||||
|
contentType: mimeType,
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`Uploaded: ${uploadedFile.urls.get}`);
|
||||||
|
|
||||||
|
const output = await replicate.run("google/gemini-2.5-flash-image", {
|
||||||
|
input: {
|
||||||
|
prompt,
|
||||||
|
image_input: [uploadedFile.urls.get],
|
||||||
|
aspect_ratio: "16:9",
|
||||||
|
output_format: "png",
|
||||||
|
},
|
||||||
|
}) as ReadableStream;
|
||||||
|
|
||||||
|
const reader = output.getReader();
|
||||||
|
const chunks: Uint8Array[] = [];
|
||||||
|
while (true) {
|
||||||
|
const { done, value } = await reader.read();
|
||||||
|
if (done) break;
|
||||||
|
chunks.push(value);
|
||||||
|
}
|
||||||
|
const resultBuffer = Buffer.concat(chunks.map(c => Buffer.from(c)));
|
||||||
|
fs.writeFileSync(outputPath, resultBuffer);
|
||||||
|
|
||||||
|
console.log(`Saved: ${outputPath}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
const commands: Record<string, () => Promise<void>> = {
|
const commands: Record<string, () => Promise<void>> = {
|
||||||
removeWatermark,
|
removeWatermark,
|
||||||
removeBackground,
|
removeBackground,
|
||||||
|
convertToPng,
|
||||||
|
generateLiveries,
|
||||||
};
|
};
|
||||||
|
|
||||||
const command = process.argv[2];
|
const command = process.argv[2];
|
||||||
|
|||||||
Reference in New Issue
Block a user