Enhancing Images with AI: Building a Free Photo Extender Using Next.js and Tailwind CSS

Enhancing Images with AI: Building a Free Photo Extender Using Next.js and Tailwind CSS In today's digital age, the demand for high-quality images is ever-increasing. Whether you're a developer, designer, or content creator, extending and enhancing images can be a valuable skill. In this tutorial, we'll walk through how to build a photo extender free application using Next.js and Tailwind CSS. We'll also leverage an AI service to perform the image extension, similar to the one found on Spark AI's AI Image Extender. Introduction Image outpainting, or extending the edges of an image, allows us to generate new content beyond the original boundaries of a photo. This can be incredibly useful for creating wallpapers, adapting images to different aspect ratios, or enhancing compositions. In this guide, we'll build a simple web application that lets users upload an image and extends it using AI. We'll focus on: Setting up a Next.js project Styling with Tailwind CSS Integrating with an AI image extension API Handling file uploads and displaying results Deploying the application Prerequisites Basic understanding of React and Next.js Node.js installed on your machine Familiarity with Tailwind CSS is a plus Setting Up the Next.js Project First, let's create a new Next.js application: npx create-next-app photo-extender-free cd photo-extender-free Installing Tailwind CSS We'll use Tailwind CSS for styling. Install Tailwind and its dependencies: npm install tailwindcss postcss autoprefixer npx tailwindcss init -p Configure tailwind.config.js: module.exports = { content: ['./pages/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}'], theme: { extend: {}, }, plugins: [], }; Add Tailwind directives to your styles/globals.css: @tailwind base; @tailwind components; @tailwind utilities; Building the Upload Component Create a new component at components/UploadImage.js: import { useState } from 'react'; export default function UploadImage({ onImageUpload }) { const [preview, setPreview] = useState(null); const handleChange = (e) => { const file = e.target.files[0]; if (!file) return; setPreview(URL.createObjectURL(file)); onImageUpload(file); }; return ( {preview && ( )} ); } This component handles the file selection, creates a preview URL, and invokes a callback onImageUpload with the selected file. Creating the Main Page Next, update pages/index.js to include the upload component, call the API, and display the result: import { useState } from 'react'; import UploadImage from '../components/UploadImage'; export default function Home() { const [file, setFile] = useState(null); const [extendedUrl, setExtendedUrl] = useState(''); const [loading, setLoading] = useState(false); const handleUpload = (file) => { setFile(file); setExtendedUrl(''); }; const extendImage = async () => { if (!file) return; setLoading(true); const formData = new FormData(); formData.append('image', file); const res = await fetch('/api/extend', { method: 'POST', body: formData, }); const data = await res.json(); setExtendedUrl(data.extendedImageUrl); setLoading(false); }; return ( Photo Extender Free {loading ? 'Extending...' : 'Extend Image'} {extendedUrl && ( Extended Image )} ); } Implementing the API Route Create an API route at pages/api/extend.js. This route will receive the uploaded file, forward it to the AI service, and return the extended image URL. import formidable from 'formidable'; import fs from 'fs'; export const config = { api: { bodyParser: false, }, }; export default async function handler(req, res) { const form = new formidable.IncomingForm(); form.parse(req, async (err, fields, files) => { if (err) return res.status(500).json({ error: 'Form parse error' }); const imageFile = files.image; const buffer = fs.readFileSync(imageFile.filepath); // Call the AI API (replace with real endpoint and key) const apiRes = await fetch('https://api.sparkaipro.com/v1/image-extender', { method: 'POST', headers: { 'Content-Type': 'application/octet-stream', 'Authorization': `Bearer ${process.env.SPARKAI_API_KEY}`, }, body: buffer, }); if (!apiRes.ok) { const errMsg = await apiRes.text(); return res.status(500).json({ error: errMsg }); } const result = await apiRes.json(); // Assuming the API returns { extendedImageUrl: string } res.status(200).json({ extendedImageUrl: result.extendedImageUrl }); }); } Be sure to set your SPARKAI_API_KEY in a .env.local file: SPARKAI_API_KEY=your_api_key_here Styling with Tailw

Apr 25, 2025 - 05:05
 0
Enhancing Images with AI: Building a Free Photo Extender Using Next.js and Tailwind CSS

Enhancing Images with AI: Building a Free Photo Extender Using Next.js and Tailwind CSS

In today's digital age, the demand for high-quality images is ever-increasing. Whether you're a developer, designer, or content creator, extending and enhancing images can be a valuable skill. In this tutorial, we'll walk through how to build a photo extender free application using Next.js and Tailwind CSS. We'll also leverage an AI service to perform the image extension, similar to the one found on Spark AI's AI Image Extender.

Introduction

Image outpainting, or extending the edges of an image, allows us to generate new content beyond the original boundaries of a photo. This can be incredibly useful for creating wallpapers, adapting images to different aspect ratios, or enhancing compositions.

In this guide, we'll build a simple web application that lets users upload an image and extends it using AI. We'll focus on:

  • Setting up a Next.js project
  • Styling with Tailwind CSS
  • Integrating with an AI image extension API
  • Handling file uploads and displaying results
  • Deploying the application

Prerequisites

  • Basic understanding of React and Next.js
  • Node.js installed on your machine
  • Familiarity with Tailwind CSS is a plus

Setting Up the Next.js Project

First, let's create a new Next.js application:

npx create-next-app photo-extender-free
cd photo-extender-free

Installing Tailwind CSS

We'll use Tailwind CSS for styling. Install Tailwind and its dependencies:

npm install tailwindcss postcss autoprefixer
npx tailwindcss init -p

Configure tailwind.config.js:

module.exports = {
  content: ['./pages/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}'],
  theme: {
    extend: {},
  },
  plugins: [],
};

Add Tailwind directives to your styles/globals.css:

@tailwind base;
@tailwind components;
@tailwind utilities;

Building the Upload Component

Create a new component at components/UploadImage.js:

import { useState } from 'react';

export default function UploadImage({ onImageUpload }) {
  const [preview, setPreview] = useState(null);

  const handleChange = (e) => {
    const file = e.target.files[0];
    if (!file) return;
    setPreview(URL.createObjectURL(file));
    onImageUpload(file);
  };

  return (
    <div className="flex flex-col items-center justify-center p-4 border-2 border-dashed rounded-lg">
      <input
        type="file"
        accept="image/*"
        onChange={handleChange}
        className="mb-4"
      />
      {preview && (
        <img
          src={preview}
          alt="Preview"
          className="max-w-xs max-h-64 object-contain"
        />
      )}
    div>
  );
}

This component handles the file selection, creates a preview URL, and invokes a callback onImageUpload with the selected file.

Creating the Main Page

Next, update pages/index.js to include the upload component, call the API, and display the result:

import { useState } from 'react';
import UploadImage from '../components/UploadImage';

export default function Home() {
  const [file, setFile] = useState(null);
  const [extendedUrl, setExtendedUrl] = useState('');
  const [loading, setLoading] = useState(false);

  const handleUpload = (file) => {
    setFile(file);
    setExtendedUrl('');
  };

  const extendImage = async () => {
    if (!file) return;
    setLoading(true);
    const formData = new FormData();
    formData.append('image', file);

    const res = await fetch('/api/extend', {
      method: 'POST',
      body: formData,
    });

    const data = await res.json();
    setExtendedUrl(data.extendedImageUrl);
    setLoading(false);
  };

  return (
    <div className="min-h-screen flex flex-col items-center justify-center bg-gray-100">
      <h1 className="text-3xl font-bold mb-6">Photo Extender Freeh1>
      <UploadImage onImageUpload={handleUpload} />
      <button
        onClick={extendImage}
        disabled={!file || loading}
        className="mt-4 px-6 py-2 bg-blue-600 text-white rounded-lg disabled:opacity-50"
      >
        {loading ? 'Extending...' : 'Extend Image'}
      button>

      {extendedUrl && (
        <div className="mt-6">
          <h2 className="text-2xl font-semibold mb-2">Extended Imageh2>
          <img
            src={extendedUrl}
            alt="Extended Result"
            className="max-w-md rounded-lg shadow-lg"
          />
        div>
      )}
    div>
  );
}

Implementing the API Route

Create an API route at pages/api/extend.js. This route will receive the uploaded file, forward it to the AI service, and return the extended image URL.

import formidable from 'formidable';
import fs from 'fs';

export const config = {
  api: {
    bodyParser: false,
  },
};

export default async function handler(req, res) {
  const form = new formidable.IncomingForm();
  form.parse(req, async (err, fields, files) => {
    if (err) return res.status(500).json({ error: 'Form parse error' });

    const imageFile = files.image;
    const buffer = fs.readFileSync(imageFile.filepath);

    // Call the AI API (replace with real endpoint and key)
    const apiRes = await fetch('https://api.sparkaipro.com/v1/image-extender', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/octet-stream',
        'Authorization': `Bearer ${process.env.SPARKAI_API_KEY}`,
      },
      body: buffer,
    });

    if (!apiRes.ok) {
      const errMsg = await apiRes.text();
      return res.status(500).json({ error: errMsg });
    }

    const result = await apiRes.json();
    // Assuming the API returns { extendedImageUrl: string }
    res.status(200).json({ extendedImageUrl: result.extendedImageUrl });
  });
}

Be sure to set your SPARKAI_API_KEY in a .env.local file:

SPARKAI_API_KEY=your_api_key_here

Styling with Tailwind CSS

We've already used Tailwind utility classes throughout our components. Feel free to customize the design by:

  • Adjusting the color palette in tailwind.config.js
  • Adding custom spacing, fonts, or shadows
  • Using plugins like @tailwindcss/forms for better form controls

Testing the Application

Run the development server:

npm run dev

Navigate to http://localhost:3000. Upload an image, click Extend Image, and see the magic happen!

Deploying to Vercel

To share your application:

  1. Push your code to a GitHub repository.
  2. Log in to Vercel and import your repo.
  3. Add the SPARKAI_API_KEY environment variable in Vercel’s dashboard.
  4. Deploy — Vercel will handle building and hosting.

Your photo extender will be live at a Vercel subdomain, ready for users to enhance images for free.

Conclusion

We’ve built a fully functional photo extender free application using Next.js and Tailwind CSS, powered by an AI image extension API. You can now extend images beyond their original borders, perfect for creative projects, design mockups, and more. Feel free to enhance this base with additional features like:

  • Batch processing multiple images
  • Custom aspect ratio controls
  • User authentication and history tracking

Happy coding and image extending!