pixelforge-ai-studio / components /image-processor.js
moreiraj93's picture
MAKE EVERYTHING FUNCTIONAL USE OPEN HUGGING FACE MODELS FOR THE IMAGE TO IMAGE
f058db1 verified
```javascript
class ImageProcessor extends HTMLElement {
constructor() {
super();
this.selectedModel = 'prompthero/openjourney';
this.uploadedImage = null;
}
connectedCallback() {
this.render();
this.attachEventListeners();
}
render() {
this.innerHTML = `
<style>
.processor-container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.model-selector {
display: flex;
gap: 15px;
margin-bottom: 30px;
flex-wrap: wrap;
}
.model-option {
padding: 15px;
border: 2px solid #e5e7eb;
border-radius: 8px;
cursor: pointer;
flex: 1;
min-width: 200px;
text-align: center;
transition: all 0.3s;
}
.model-option:hover {
border-color: #3b82f6;
}
.model-option.active {
border-color: #3b82f6;
background-color: #dbeafe;
}
.upload-area {
border: 2px dashed #d1d5db;
border-radius: 8px;
padding: 40px;
text-align: center;
margin-bottom: 30px;
position: relative;
}
.upload-area.drag-over {
border-color: #3b82f6;
background-color: #eff6ff;
}
.preview-container {
display: flex;
gap: 30px;
flex-wrap: wrap;
}
.image-preview {
flex: 1;
min-width: 300px;
}
.preview-image {
max-width: 100%;
max-height: 400px;
display: block;
margin: 0 auto;
border-radius: 8px;
}
.controls {
margin: 20px 0;
}
.prompt-input {
width: 100%;
padding: 12px;
border: 1px solid #d1d5db;
border-radius: 6px;
margin-bottom: 15px;
}
.process-btn {
background-color: #10b981;
color: white;
border: none;
padding: 12px 24px;
border-radius: 6px;
cursor: pointer;
font-weight: bold;
width: 100%;
}
.process-btn:hover:not(:disabled) {
background-color: #059669;
}
.process-btn:disabled {
background-color: #9ca3af;
cursor: not-allowed;
}
.result-container {
position: relative;
min-height: 400px;
display: flex;
align-items: center;
justify-content: center;
}
.processing-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(255, 255, 255, 0.8);
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
z-index: 10;
}
.spinner {
border: 4px solid #f3f3f3;
border-top: 4px solid #3b82f6;
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
margin-bottom: 15px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.action-buttons {
display: flex;
gap: 15px;
margin-top: 20px;
}
.action-btn {
flex: 1;
padding: 12px;
border: none;
border-radius: 6px;
font-weight: bold;
cursor: pointer;
}
.download-btn {
background-color: #3b82f6;
color: white;
}
.save-btn {
background-color: #ef4444;
color: white;
}
.action-btn:disabled {
background-color: #9ca3af;
cursor: not-allowed;
}
</style>
<div class="processor-container">
<h2>AI Image Processor</h2>
<div class="model-selector">
<div class="model-option active" data-model="prompthero/openjourney">
<h3>Artistic Style Transfer</h3>
<p>Apply artistic styles to your images</p>
</div>
<div class="model-option" data-model="stabilityai/stable-diffusion-x4-upscaler">
<h3>Super Resolution</h3>
<p>Enhance image resolution and details</p>
</div>
<div class="model-option" data-model="lllyasviel/sd-controlnet-canny">
<h3>Edge Enhancement</h3>
<p>Transform images using edge detection</p>
</div>
</div>
<div class="upload-area" id="drop-zone">
<p>Drag & drop your image here or click to browse</p>
<input type="file" id="file-input" accept="image/*" style="display: none;">
<button id="browse-btn">Select Image</button>
<img id="preview" class="preview-image" style="display: none; margin-top: 20px;">
</div>
<div class="preview-container">
<div class="image-preview">
<h3>Input Image</h3>
<div id="input-preview" class="result-container">
<p>No image selected</p>
</div>
</div>
<div class="image-preview">
<h3>Processed Result</h3>
<div id="output-preview" class="result-container">
<p>Processed image will appear here</p>
</div>
</div>
</div>
</div>
`;
}
attachEventListeners() {
// Model selection
const modelOptions = this.querySelectorAll('.model-option');
modelOptions.forEach(option => {
option.addEventListener('click', (e) => {
modelOptions.forEach(opt => opt.classList.remove('active'));
e.currentTarget.classList.add('active');
this.selectedModel = e.currentTarget.dataset.model;
});
});
// File upload
const dropZone = this.querySelector('#drop-zone');
const fileInput = this.querySelector('#file-input');
const browseBtn = this.querySelector('#browse-btn');
const preview = this.querySelector('#preview');
browseBtn.addEventListener('click', () => fileInput.click());
fileInput.addEventListener('change', (e) => {
if (e.target.files.length) {
this.handleFile(e.target.files[0]);
}
});
// Drag and drop events
dropZone.addEventListener('dragover', (e) => {
e.preventDefault();
dropZone.classList.add('drag-over');
});
dropZone.addEventListener('dragleave', () => {
dropZone.classList.remove('drag-over');
});
dropZone.addEventListener('drop', (e) => {
e.preventDefault();
dropZone.classList.remove('drag-over');
if (e.dataTransfer.files.length) {
this.handleFile(e.dataTransfer.files[0]);
}
});
}
handleFile(file) {
if (!file.type.match('image.*')) {
alert('Please select an image file');
return;
}
const reader = new FileReader();
reader.onload = (e) => {
this.uploadedImage = e.target.result;
this.updatePreview();
};
reader.readAsDataURL(file);
}
updatePreview() {
const inputPreview = this.querySelector('#input-preview');
inputPreview.innerHTML = `<img src="${this.uploadedImage}" class="preview-image">`;
}
async processImage(prompt) {
if (!this.uploadedImage) {
alert('Please upload an image first');
return;
}
const outputPreview = this.querySelector('#output-preview');
outputPreview.innerHTML = `
<div class="processing-overlay">
<div class="spinner"></div>
<p>Processing image...</p>
</div>
<img src="${this.uploadedImage}" class="preview-image" style="opacity: 0.3;">
`;
try {
// Convert base64 to blob
const imageData = this.uploadedImage.split(',')[1];
const byteString = atob(imageData);
const mimeString = this.uploadedImage.split(',')[0].split(':')[1].split(';')[0];
const ab = new ArrayBuffer(byteString.length);
const ia = new Uint8Array(ab);
for (let i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
const blob = new Blob([ab], {type: mimeString});
// Prepare form data
const formData = new FormData();
formData.append('inputs', prompt);
formData.append('image', blob, 'input.png');
// Call Hugging Face API
const response = await fetch(
`https://api-inference.huggingface.co/models/${this.selectedModel}`,
{
headers: {
'Authorization': 'Bearer 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'
},
method: 'POST',
body: formData
}
);
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
const blobResult = await response.blob();
const imageUrl = URL.createObjectURL(blobResult);
// Display result
outputPreview.innerHTML = `
<img src="${imageUrl}" class="preview-image">
<div class="action-buttons">
<button class="action-btn download-btn" onclick="this.downloadImage('${imageUrl}')">Download</button>
<button class="action-btn save-btn">Save to Gallery</button>
</div>
`;
} catch (error) {
console.error('Error processing image:', error);
outputPreview.innerHTML = `
<p>Error processing image. Please try again.</p>
<img src="${this.uploadedImage}" class="preview-image" style="opacity: 0.3;">
`;
}
}
downloadImage(url) {
const link = document.createElement('a');
link.href = url;
link.download = 'processed-image.png';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}
customElements.define('image-processor', ImageProcessor);
>>>>>>> REPLACE