Spaces:
Sleeping
Sleeping
Enhance mask handling in image processing: resize and validate dimensions, update demo link, and correct copyright year in footer
311bfbf
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Magic Eraser API Documentation</title> | |
| <style> | |
| body { | |
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; | |
| line-height: 1.6; | |
| color: #333; | |
| max-width: 1100px; | |
| margin: 0 auto; | |
| padding: 20px; | |
| } | |
| header { | |
| border-bottom: 1px solid #eee; | |
| padding-bottom: 20px; | |
| margin-bottom: 30px; | |
| } | |
| h1 { | |
| color: #2c3e50; | |
| } | |
| h2 { | |
| color: #3498db; | |
| margin-top: 40px; | |
| } | |
| h3 { | |
| color: #2980b9; | |
| } | |
| pre { | |
| background-color: #f5f7f9; | |
| border-radius: 5px; | |
| padding: 15px; | |
| overflow-x: auto; | |
| } | |
| code { | |
| font-family: 'Courier New', Courier, monospace; | |
| } | |
| .endpoint { | |
| background-color: #f8f9fa; | |
| border-left: 4px solid #3498db; | |
| padding: 15px; | |
| margin-bottom: 20px; | |
| } | |
| .method { | |
| display: inline-block; | |
| padding: 3px 6px; | |
| border-radius: 4px; | |
| color: white; | |
| font-size: 14px; | |
| margin-right: 10px; | |
| } | |
| .get { | |
| background-color: #3498db; | |
| } | |
| .post { | |
| background-color: #2ecc71; | |
| } | |
| table { | |
| border-collapse: collapse; | |
| width: 100%; | |
| } | |
| th, td { | |
| text-align: left; | |
| padding: 12px; | |
| border-bottom: 1px solid #ddd; | |
| } | |
| th { | |
| background-color: #f2f2f2; | |
| } | |
| .container { | |
| margin-top: 20px; | |
| } | |
| .demo-section { | |
| margin-top: 40px; | |
| padding: 20px; | |
| background-color: #f9f9f9; | |
| border-radius: 8px; | |
| } | |
| .btn { | |
| display: inline-block; | |
| padding: 10px 15px; | |
| background-color: #3498db; | |
| color: white; | |
| text-decoration: none; | |
| border-radius: 4px; | |
| border: none; | |
| cursor: pointer; | |
| } | |
| .btn:hover { | |
| background-color: #2980b9; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <header> | |
| <h1>📷 Magic Eraser API</h1> | |
| <p>An AI-powered REST API for removing unwanted objects from images and performing content-aware resizing.</p> | |
| <p>Check out the InnoAI Space for the streamline demo frontend: <a href="https://huggingface.co/spaces/innoai/Magic-Eraser-Pub" target="_blank">Magic Eraser Demo</a></p> | |
| </header> | |
| <section> | |
| <h2>Features</h2> | |
| <ul> | |
| <li><strong>Object Removal</strong>: Remove unwanted objects from images with advanced AI inpainting</li> | |
| <li><strong>Seam Carving</strong>: Content-aware image resizing and object removal</li> | |
| <li><strong>Simple Integration</strong>: Easy-to-use REST API endpoints</li> | |
| </ul> | |
| </section> | |
| <section> | |
| <h2>API Endpoints</h2> | |
| <div class="endpoint"> | |
| <h3><span class="method get">GET</span> /</h3> | |
| <p>Health check endpoint. Returns a status message if the API is running.</p> | |
| <h4>Response</h4> | |
| <pre><code>{ | |
| "status": "API is running" | |
| }</code></pre> | |
| </div> | |
| <div class="endpoint"> | |
| <h3><span class="method post">POST</span> /api/inpaint</h3> | |
| <p>Removes objects from images and fills in the background using AI.</p> | |
| <h4>Request Body</h4> | |
| <pre><code>{ | |
| "image": "data:image/png;base64,<base64-encoded-image>", | |
| "mask": "data:image/png;base64,<base64-encoded-mask>" | |
| }</code></pre> | |
| <table> | |
| <tr> | |
| <th>Parameter</th> | |
| <th>Type</th> | |
| <th>Description</th> | |
| </tr> | |
| <tr> | |
| <td>image</td> | |
| <td>string</td> | |
| <td>Base64-encoded image with data URL prefix</td> | |
| </tr> | |
| <tr> | |
| <td>mask</td> | |
| <td>string</td> | |
| <td>Base64-encoded mask where transparent areas (alpha=0) indicate what to remove</td> | |
| </tr> | |
| </table> | |
| <h4>Response</h4> | |
| <pre><code>{ | |
| "result": "data:image/png;base64,<base64-encoded-result>" | |
| }</code></pre> | |
| </div> | |
| <div class="endpoint"> | |
| <h3><span class="method post">POST</span> /api/seam-carve</h3> | |
| <p>Content-aware resizing or object removal using the seam carving algorithm.</p> | |
| <h4>Request Body</h4> | |
| <pre><code>{ | |
| "image": "data:image/png;base64,<base64-encoded-image>", | |
| "mask": "data:image/png;base64,<base64-encoded-mask>", | |
| "vs": 50, | |
| "hs": 30, | |
| "mode": "resize" | |
| }</code></pre> | |
| <table> | |
| <tr> | |
| <th>Parameter</th> | |
| <th>Type</th> | |
| <th>Description</th> | |
| </tr> | |
| <tr> | |
| <td>image</td> | |
| <td>string</td> | |
| <td>Base64-encoded image with data URL prefix</td> | |
| </tr> | |
| <tr> | |
| <td>mask</td> | |
| <td>string</td> | |
| <td>Base64-encoded mask (optional for resize mode, required for remove mode)</td> | |
| </tr> | |
| <tr> | |
| <td>vs</td> | |
| <td>integer</td> | |
| <td>Number of vertical seams to add/remove (positive = add, negative = remove)</td> | |
| </tr> | |
| <tr> | |
| <td>hs</td> | |
| <td>integer</td> | |
| <td>Number of horizontal seams to add/remove (positive = add, negative = remove)</td> | |
| </tr> | |
| <tr> | |
| <td>mode</td> | |
| <td>string</td> | |
| <td>Either "resize" (change dimensions) or "remove" (remove objects)</td> | |
| </tr> | |
| </table> | |
| <h4>Response</h4> | |
| <pre><code>{ | |
| "result": "data:image/png;base64,<base64-encoded-result>" | |
| }</code></pre> | |
| </div> | |
| </section> | |
| <section> | |
| <h2>JavaScript Example</h2> | |
| <p>Here's how to use the API in a JavaScript application:</p> | |
| <h3>Inpainting Example</h3> | |
| <pre><code>async function removeObject(imageBase64, maskBase64) { | |
| const response = await fetch('{{ api_url }}/api/inpaint', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify({ | |
| image: imageBase64, | |
| mask: maskBase64, | |
| }), | |
| }); | |
| const data = await response.json(); | |
| return data.result; // base64 encoded result image | |
| }</code></pre> | |
| <h3>Seam Carving Example</h3> | |
| <pre><code>async function resizeImage(imageBase64, maskBase64) { | |
| const response = await fetch('{{ api_url }}/api/seam-carve', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify({ | |
| image: imageBase64, | |
| mask: maskBase64, | |
| vs: -50, // Remove 50 vertical seams (make narrower) | |
| hs: 30, // Add 30 horizontal seams (make taller) | |
| mode: 'resize', // or 'remove' to remove objects | |
| }), | |
| }); | |
| const data = await response.json(); | |
| return data.result; | |
| }</code></pre> | |
| </section> | |
| <section> | |
| <h2>Setting Up a Drawing Canvas</h2> | |
| <p>To integrate with our API, you'll need a way for users to draw masks over images. Here's a simple HTML5 Canvas example:</p> | |
| <pre><code>function setupCanvas(imageUrl) { | |
| // Create canvas elements | |
| const imageCanvas = document.createElement('canvas'); | |
| const maskCanvas = document.createElement('canvas'); | |
| const container = document.getElementById('canvas-container'); | |
| container.appendChild(imageCanvas); | |
| container.appendChild(maskCanvas); | |
| // Load image | |
| const img = new Image(); | |
| img.onload = function() { | |
| // Set canvas dimensions | |
| imageCanvas.width = maskCanvas.width = img.width; | |
| imageCanvas.height = maskCanvas.height = img.height; | |
| // Draw image on image canvas | |
| const imgCtx = imageCanvas.getContext('2d'); | |
| imgCtx.drawImage(img, 0, 0); | |
| // Setup mask canvas for drawing | |
| const maskCtx = maskCanvas.getContext('2d'); | |
| maskCtx.fillStyle = 'rgba(255, 0, 0, 0.5)'; | |
| // Drawing state | |
| let isDrawing = false; | |
| // Mouse/touch event handlers | |
| maskCanvas.addEventListener('mousedown', startDrawing); | |
| maskCanvas.addEventListener('mousemove', draw); | |
| maskCanvas.addEventListener('mouseup', stopDrawing); | |
| maskCanvas.addEventListener('mouseleave', stopDrawing); | |
| function startDrawing(e) { | |
| isDrawing = true; | |
| draw(e); | |
| } | |
| function draw(e) { | |
| if (!isDrawing) return; | |
| const rect = maskCanvas.getBoundingClientRect(); | |
| const x = e.clientX - rect.left; | |
| const y = e.clientY - rect.top; | |
| maskCtx.beginPath(); | |
| maskCtx.arc(x, y, 15, 0, Math.PI * 2); | |
| maskCtx.fill(); | |
| } | |
| function stopDrawing() { | |
| isDrawing = false; | |
| } | |
| }; | |
| img.src = imageUrl; | |
| }</code></pre> | |
| </section> | |
| <section class="demo-section"> | |
| <h2>Try It Out</h2> | |
| <p>Visit InnoAI interactive demo frontend:</p> | |
| <a href="https://huggingface.co/spaces/innoai/Magic" class="btn" target="_blank">Open Demo Frontend</a> | |
| <p><small>Demo frontend connects to this API for processing images.</small></p> | |
| </section> | |
| <footer> | |
| <p><small>© 2025 Magic Eraser API. MIT License.</small></p> | |
| </footer> | |
| </body> | |
| </html> | |