Initial commit
This commit is contained in:
336
templates/image-editing.ts
Normal file
336
templates/image-editing.ts
Normal file
@@ -0,0 +1,336 @@
|
||||
/**
|
||||
* OpenAI Images API - Image Editing Examples (GPT-Image-1)
|
||||
*
|
||||
* This template demonstrates:
|
||||
* - Basic image editing
|
||||
* - Compositing multiple images
|
||||
* - Transparent backgrounds
|
||||
* - Different output formats
|
||||
* - Compression settings
|
||||
*
|
||||
* NOTE: Image editing uses multipart/form-data, not JSON
|
||||
*/
|
||||
|
||||
import fs from 'fs';
|
||||
import FormData from 'form-data';
|
||||
|
||||
const OPENAI_API_KEY = process.env.OPENAI_API_KEY;
|
||||
|
||||
// =============================================================================
|
||||
// BASIC IMAGE EDITING
|
||||
// =============================================================================
|
||||
|
||||
async function basicEdit() {
|
||||
const formData = new FormData();
|
||||
formData.append('model', 'gpt-image-1');
|
||||
formData.append('image', fs.createReadStream('./input-image.jpg'));
|
||||
formData.append('prompt', 'Change the sky to a sunset with orange and pink colors');
|
||||
formData.append('size', '1024x1024');
|
||||
|
||||
const response = await fetch('https://api.openai.com/v1/images/edits', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${OPENAI_API_KEY}`,
|
||||
...formData.getHeaders(),
|
||||
},
|
||||
body: formData,
|
||||
});
|
||||
|
||||
const data: any = await response.json();
|
||||
console.log('Edited image URL:', data.data[0].url);
|
||||
|
||||
return data.data[0].url;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// COMPOSITE TWO IMAGES
|
||||
// =============================================================================
|
||||
|
||||
async function compositeImages() {
|
||||
const formData = new FormData();
|
||||
formData.append('model', 'gpt-image-1');
|
||||
formData.append('image', fs.createReadStream('./woman.jpg'));
|
||||
formData.append('image_2', fs.createReadStream('./logo.png'));
|
||||
formData.append('prompt', 'Add the logo to the woman\'s top, as if stamped into the fabric.');
|
||||
formData.append('input_fidelity', 'high'); // Stay close to original
|
||||
formData.append('size', '1024x1024');
|
||||
|
||||
const response = await fetch('https://api.openai.com/v1/images/edits', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${OPENAI_API_KEY}`,
|
||||
...formData.getHeaders(),
|
||||
},
|
||||
body: formData,
|
||||
});
|
||||
|
||||
const data: any = await response.json();
|
||||
console.log('Composite image URL:', data.data[0].url);
|
||||
|
||||
return data.data[0].url;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// REMOVE BACKGROUND (Transparent)
|
||||
// =============================================================================
|
||||
|
||||
async function removeBackground() {
|
||||
const formData = new FormData();
|
||||
formData.append('model', 'gpt-image-1');
|
||||
formData.append('image', fs.createReadStream('./product.jpg'));
|
||||
formData.append('prompt', 'Remove the background, keeping only the product.');
|
||||
formData.append('format', 'png'); // Required for transparency
|
||||
formData.append('background', 'transparent');
|
||||
formData.append('size', '1024x1024');
|
||||
|
||||
const response = await fetch('https://api.openai.com/v1/images/edits', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${OPENAI_API_KEY}`,
|
||||
...formData.getHeaders(),
|
||||
},
|
||||
body: formData,
|
||||
});
|
||||
|
||||
const data: any = await response.json();
|
||||
console.log('Transparent background URL:', data.data[0].url);
|
||||
|
||||
// Download and save
|
||||
const imageResponse = await fetch(data.data[0].url);
|
||||
const buffer = Buffer.from(await imageResponse.arrayBuffer());
|
||||
fs.writeFileSync('product-no-bg.png', buffer);
|
||||
console.log('Saved to: product-no-bg.png');
|
||||
|
||||
return data.data[0].url;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// INPUT FIDELITY OPTIONS
|
||||
// =============================================================================
|
||||
|
||||
async function fidelityComparison() {
|
||||
const baseFormData = () => {
|
||||
const formData = new FormData();
|
||||
formData.append('model', 'gpt-image-1');
|
||||
formData.append('image', fs.createReadStream('./portrait.jpg'));
|
||||
formData.append('prompt', 'Add sunglasses to the person');
|
||||
return formData;
|
||||
};
|
||||
|
||||
// Low fidelity (more creative freedom)
|
||||
const lowFidelity = baseFormData();
|
||||
lowFidelity.append('input_fidelity', 'low');
|
||||
|
||||
const lowResponse = await fetch('https://api.openai.com/v1/images/edits', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${OPENAI_API_KEY}`,
|
||||
...lowFidelity.getHeaders(),
|
||||
},
|
||||
body: lowFidelity,
|
||||
});
|
||||
|
||||
const lowData: any = await lowResponse.json();
|
||||
console.log('Low fidelity URL:', lowData.data[0].url);
|
||||
|
||||
// High fidelity (stay closer to original)
|
||||
const highFidelity = baseFormData();
|
||||
highFidelity.append('input_fidelity', 'high');
|
||||
|
||||
const highResponse = await fetch('https://api.openai.com/v1/images/edits', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${OPENAI_API_KEY}`,
|
||||
...highFidelity.getHeaders(),
|
||||
},
|
||||
body: highFidelity,
|
||||
});
|
||||
|
||||
const highData: any = await highResponse.json();
|
||||
console.log('High fidelity URL:', highData.data[0].url);
|
||||
|
||||
return { low: lowData.data[0].url, high: highData.data[0].url };
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// OUTPUT FORMATS AND COMPRESSION
|
||||
// =============================================================================
|
||||
|
||||
async function formatComparison() {
|
||||
const basePrompt = 'Add a blue sky to the background';
|
||||
|
||||
// PNG (supports transparency, larger file)
|
||||
const pngFormData = new FormData();
|
||||
pngFormData.append('model', 'gpt-image-1');
|
||||
pngFormData.append('image', fs.createReadStream('./scene.jpg'));
|
||||
pngFormData.append('prompt', basePrompt);
|
||||
pngFormData.append('format', 'png');
|
||||
|
||||
const pngResponse = await fetch('https://api.openai.com/v1/images/edits', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${OPENAI_API_KEY}`,
|
||||
...pngFormData.getHeaders(),
|
||||
},
|
||||
body: pngFormData,
|
||||
});
|
||||
|
||||
const pngData: any = await pngResponse.json();
|
||||
console.log('PNG format URL:', pngData.data[0].url);
|
||||
|
||||
// JPEG (smaller file, no transparency)
|
||||
const jpegFormData = new FormData();
|
||||
jpegFormData.append('model', 'gpt-image-1');
|
||||
jpegFormData.append('image', fs.createReadStream('./scene.jpg'));
|
||||
jpegFormData.append('prompt', basePrompt);
|
||||
jpegFormData.append('format', 'jpeg');
|
||||
jpegFormData.append('output_compression', '80'); // 0-100
|
||||
|
||||
const jpegResponse = await fetch('https://api.openai.com/v1/images/edits', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${OPENAI_API_KEY}`,
|
||||
...jpegFormData.getHeaders(),
|
||||
},
|
||||
body: jpegFormData,
|
||||
});
|
||||
|
||||
const jpegData: any = await jpegResponse.json();
|
||||
console.log('JPEG format URL:', jpegData.data[0].url);
|
||||
|
||||
// WebP (best compression, supports transparency)
|
||||
const webpFormData = new FormData();
|
||||
webpFormData.append('model', 'gpt-image-1');
|
||||
webpFormData.append('image', fs.createReadStream('./scene.jpg'));
|
||||
webpFormData.append('prompt', basePrompt);
|
||||
webpFormData.append('format', 'webp');
|
||||
webpFormData.append('output_compression', '85');
|
||||
|
||||
const webpResponse = await fetch('https://api.openai.com/v1/images/edits', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${OPENAI_API_KEY}`,
|
||||
...webpFormData.getHeaders(),
|
||||
},
|
||||
body: webpFormData,
|
||||
});
|
||||
|
||||
const webpData: any = await webpResponse.json();
|
||||
console.log('WebP format URL:', webpData.data[0].url);
|
||||
|
||||
return { png: pngData.data[0].url, jpeg: jpegData.data[0].url, webp: webpData.data[0].url };
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// COMMON EDITING TASKS
|
||||
// =============================================================================
|
||||
|
||||
async function commonEdits() {
|
||||
// 1. Color correction
|
||||
const colorCorrect = new FormData();
|
||||
colorCorrect.append('model', 'gpt-image-1');
|
||||
colorCorrect.append('image', fs.createReadStream('./photo.jpg'));
|
||||
colorCorrect.append('prompt', 'Increase brightness and saturation, make colors more vibrant');
|
||||
|
||||
// 2. Object removal
|
||||
const objectRemoval = new FormData();
|
||||
objectRemoval.append('model', 'gpt-image-1');
|
||||
objectRemoval.append('image', fs.createReadStream('./scene.jpg'));
|
||||
objectRemoval.append('prompt', 'Remove the person from the background');
|
||||
|
||||
// 3. Style transfer
|
||||
const styleTransfer = new FormData();
|
||||
styleTransfer.append('model', 'gpt-image-1');
|
||||
styleTransfer.append('image', fs.createReadStream('./photo.jpg'));
|
||||
styleTransfer.append('prompt', 'Transform this photo into a watercolor painting style');
|
||||
|
||||
// 4. Add text/overlay
|
||||
const addText = new FormData();
|
||||
addText.append('model', 'gpt-image-1');
|
||||
addText.append('image', fs.createReadStream('./poster.jpg'));
|
||||
addText.append('prompt', 'Add the text "SALE" in large bold letters at the top');
|
||||
|
||||
console.log('Common editing tasks prepared');
|
||||
|
||||
return { colorCorrect, objectRemoval, styleTransfer, addText };
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// ERROR HANDLING
|
||||
// =============================================================================
|
||||
|
||||
async function withErrorHandling() {
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append('model', 'gpt-image-1');
|
||||
formData.append('image', fs.createReadStream('./input.jpg'));
|
||||
formData.append('prompt', 'Edit the image');
|
||||
|
||||
const response = await fetch('https://api.openai.com/v1/images/edits', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${OPENAI_API_KEY}`,
|
||||
...formData.getHeaders(),
|
||||
},
|
||||
body: formData,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
throw new Error(`API error: ${error.error?.message}`);
|
||||
}
|
||||
|
||||
const data: any = await response.json();
|
||||
return data.data[0].url;
|
||||
} catch (error: any) {
|
||||
if (error.message.includes('file not found')) {
|
||||
console.error('Input image file not found');
|
||||
} else if (error.message.includes('rate limit')) {
|
||||
console.error('Rate limit exceeded - wait and retry');
|
||||
} else {
|
||||
console.error('Unexpected error:', error.message);
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// MAIN EXECUTION
|
||||
// =============================================================================
|
||||
|
||||
async function main() {
|
||||
console.log('=== OpenAI Image Editing (GPT-Image-1) Examples ===\n');
|
||||
|
||||
console.log('Note: This script requires input images to run.');
|
||||
console.log('Create test images first or modify the file paths.\n');
|
||||
|
||||
// Uncomment the examples you want to run:
|
||||
|
||||
// console.log('1. Basic Edit:');
|
||||
// await basicEdit();
|
||||
// console.log();
|
||||
|
||||
// console.log('2. Composite Images:');
|
||||
// await compositeImages();
|
||||
// console.log();
|
||||
|
||||
// console.log('3. Remove Background:');
|
||||
// await removeBackground();
|
||||
// console.log();
|
||||
}
|
||||
|
||||
// Run if executed directly
|
||||
if (require.main === module) {
|
||||
main().catch(console.error);
|
||||
}
|
||||
|
||||
export {
|
||||
basicEdit,
|
||||
compositeImages,
|
||||
removeBackground,
|
||||
fidelityComparison,
|
||||
formatComparison,
|
||||
commonEdits,
|
||||
withErrorHandling,
|
||||
};
|
||||
Reference in New Issue
Block a user