Virtual Try‑On

✅ THE PROPER SOLUTION FOR YOUR STACK (Flutter + Laravel + MySQL)

Google’s official Virtual Try-On API is the correct choice because:

“Virtual Try‑On lets you generate images of people modeling clothing products by providing a person image + clothing image.” [docs.cloud…google.com]

Gemini Flash Image / Nano Banana can also do image generation, but they’re secondary, not specialized for try-on.


🧱 RECOMMENDED SYSTEM ARCHITECTURE

Flutter App  →  Laravel Backend  →  Google Cloud
                                     |-> Virtual Try-On API  (for try‑on)
                                     |-> Gemini Flash Image/Nano (optional face swap/edit)
MySQL DB    ←  Laravel Backend  ←  (Stores user profile + sizes + image paths)

STEP 1 — Enable Google AI Services

1.1 Create a Google Cloud Project

1.2 Enable:

  • Vertex AI API
  • Generative AI API
  • Virtual Try-On API (Preview) → required for clothing try-on\ “Virtual Try-On supports models like virtual-try-on-preview-08-04…” [docs.cloud…google.com]

1.3 Create Service Account

  • Grant:
    • Vertex AI User
    • Storage Admin (for storing images if needed)

1.4 Download service-account.json

Store it in your Laravel backend (not Flutter).


STEP 2 — LARAVEL BACKEND IMPLEMENTATION

Your Laravel backend must:

  1. Receive user profile image + dress image
  2. Send both to Google’s Virtual Try-On API
  3. Receive base64 output image
  4. Store output image in storage (S3 / GCS / local)
  5. Return URL to Flutter

2.1 Install Google Auth PHP library

composer require google/auth


2.2 Add Helper to Generate Google Access Token

Create file app/Services/GoogleTokenService.php:

<?php

namespace App\Services;

use Google\Auth\Credentials\ServiceAccountCredentials;
use Google\Auth\HttpHandler\HttpHandlerFactory;

class GoogleTokenService {
    public static function getToken() {
        $credentials = new ServiceAccountCredentials(
            ['https://www.googleapis.com/auth/cloud-platform'],
            storagepath('app/google/service-account.json')
        );

        $token = $credentials->fetchAuthToken(HttpHandlerFactory::build());
        return $token['accesstoken'];
    }
}


2.3 Laravel Controller to Call Try‑On API

public function generateTryOn(Request $req)
{
    $person = $req->file('personImage');
    $product = $req->file('productImage');

    $personBase64 = base64encode(filegetcontents($person));
    $productBase64 = base64encode(filegetcontents($product));

    $body = [
        "instances" => [
            [
                "personImage" => [
                    "image" => [ "bytesBase64Encoded" => $personBase64 ]
                ],
                "productImages" => [
                    [
                        "image" => [ "bytesBase64Encoded" => $productBase64 ]
                    ]
                ]
            ]
        ],
        "parameters" => [
            "sampleCount" => 1,
            "addWatermark" => false
        ]
    ];

    $token = GoogleTokenService::getToken();

    $url = "https://us-central1-aiplatform.googleapis.com/v1/projects/YOURPROJECTID/locations/us-central1/publishers/google/models/virtual-try-on-preview-08-04:predict";

    $client = new \GuzzleHttp\Client();
    $response = $client->post($url, [
        'headers' => [
            'Authorization' => "Bearer $token",
            'Content-Type' => 'application/json'
        ],
        'body' => jsonencode($body),
    ]);

    $output = jsondecode($response->getBody(), true);

    // output contains base64 image
    $imageBase64 = $output['predictions'][0]['bytesBase64Encoded'];

    // Save to storage
    $filename = 'tryon/'.uniqid().'.png';
    \Storage::disk('public')->put($filename, base64decode($imageBase64));

    return response()->json([
        'imageurl' => asset('storage/'.$filename)
    ]);
}


STEP 3 — FLUTTER IMPLEMENTATION

3.1 Pick images

final profileImg = await picker.pickImage(source: ImageSource.gallery);
final productImg = await picker.pickImage(source: ImageSource.gallery);

3.2 Send to Laravel

var request = http.MultipartRequest(
  'POST',
  Uri.parse("https://yourserver.com/api/tryon"),
);

request.files.add(await http.MultipartFile.fromPath('personImage', profileImg.path));
request.files.add(await http.MultipartFile.fromPath('productImage', productImg.path));

var response = await request.send();
var resBody = await response.stream.bytesToString();

final data = jsonDecode(resBody);

String tryOnImageUrl = data["image_url"];

3.3 Display image

Image.network(tryOnImageUrl)


STEP 4 — OPTIONAL: Using Gemini for Face Swap / Custom Body Editing

Gemini Flash Image / Nano Banana supports generating and editing person images:

“Gemini 2.5 Flash Image can generate and edit images of people…” [docs.cloud…google.com]

You can call Gemini through REST or a PHP SDK wrapper.

Useful for:

  • Face swap
  • Background cleanup
  • Body shape approximation

Laravel can call Gemini just like any other REST API.


STEP 5 — USER SIZE RECOMMENDATION (Laravel + Gemini 3 Pro)

Use the Gemini model for reasoning:

$prompt = "
User details:
Height: $height
Weight: $weight
Chest: $chest
Hip: $hip

Based on the size chart below, recommend the best size:

$sizeChartJson

Return only size.
";

Call Gemini 3 Pro via REST API.


📌 FINAL DELIVERABLE FOR YOUR DEVELOPERS

Your developer team must build:

Laravel Backend

  • Upload endpoints
  • Try-On API integration
  • Gemini image-processing endpoints
  • Store results in MySQL
  • Serve final URLs to Flutter

Flutter App

  • Allow user to upload full-body / half-body photos
  • Allow product image selection
  • Call backend
  • Display try-on image
  • Save user sizes

MySQL

  • Users table
  • Body measurements table
  • Product table
  • Generated try-on results table

Did you find this article useful?