How to enforce Ratio or Size with Nano Banana?

Hey folks,

I’l facing a little challenge here. I am trying to produce images with Nano Banana and end up with a ratio / size challenge.

I understand that the current API does not offer any parameter to control that. And from what I’ve read so far, it seems the only way to push the model in the right direction is to set-it at the prompt level.

I have tried several approaches, include json prompt and strict guideline prompting. I also tried image generation from scratch or image editing using my attached image as a reference to enforce the right ratio, etc.

Still, despite my best efforts, the model systematically renders a 1632x640 image in the end.

Do you have any idea, best practice or reco to tackle that? I understand it won’t be perfect, but I’m just trying to get rid of that rigid 1632x640 size thing for now.

In case that’s worth, here is my test code below.

Thanks a lot

 2. Set the local paths to your two reference images.
IMAGE_PATH_1 = "reference_image.png"
IMAGE_PATH_2 = "insertion_image.png"

# 3. Define your final text prompt.
USER_PROMPT = """
  {
  "rendering_protocol": "xxxxx",
  "instruction": "xxxx",
  "layout_framing": "xxxx",
  "compliance": "xxxxx.",
  "negative_prompt": "xxxx",
  "aspect_ratio": "1:1"
  }


 
 """

# 4. Set the base name for the output files.
OUTPUT_FILE_NAME = "generated_output"

################################################################################
# 🔚 END CONFIGURATION
################################################################################


def save_binary_file(file_name, data):
    """Saves raw binary data to a file."""
    with open(file_name, "wb") as f:
        f.write(data)
    print(f"File saved to: {file_name}")


def generate():
    """Main function to configure the client and generate content."""
    
    # Check if image paths are valid before proceeding
    for path in [IMAGE_PATH_1, IMAGE_PATH_2]:
        if not os.path.exists(path):
            raise FileNotFoundError(f"Error: Image file not found at '{path}'")

    client = genai.Client(api_key=API_KEY)

    # Read image files and determine their MIME types
    mime_type_1, _ = mimetypes.guess_type(IMAGE_PATH_1)
    with open(IMAGE_PATH_1, "rb") as f:
        image_data_1 = f.read()

    mime_type_2, _ = mimetypes.guess_type(IMAGE_PATH_2)
    with open(IMAGE_PATH_2, "rb") as f:
        image_data_2 = f.read()

    model = "gemini-2.5-flash-image-preview"
    contents = [
        types.Content(
            role="user",
            parts=[
                types.Part.from_bytes(
                    mime_type=mime_type_1,
                    data=image_data_1,
                ),
                types.Part.from_text(text="""Generate a persona wearing that belt for relaxation"""),
            ],
        ),
        types.Content(
            role="model",
            parts=[
                types.Part.from_bytes(
                    mime_type=mime_type_2,
                    data=image_data_2,
                ),
            ],
        ),
        types.Content(
            role="user",
            parts=[
                types.Part.from_text(text=USER_PROMPT),
            ],
        ),
    ]
    generate_content_config = types.GenerateContentConfig(
        response_modalities=[
            "IMAGE",
            "TEXT",
        ],
    )

    print("Generating content... 🖼️")
    file_index = 0
    for chunk in client.models.generate_content_stream(
        model=model,
        contents=contents,
        config=generate_content_config,
    ):
        if (
            chunk.candidates is None
            or not chunk.candidates[0].content
            or not chunk.candidates[0].content.parts
        ):
            continue
        
        part = chunk.candidates[0].content.parts[0]
        if part.inline_data and part.inline_data.data:
            file_name_base = f"{OUTPUT_FILE_NAME}_{file_index}"
            inline_data = part.inline_data
            data_buffer = inline_data.data
            file_extension = mimetypes.guess_extension(inline_data.mime_type) or ".bin"
            save_binary_file(f"{file_name_base}{file_extension}", data_buffer)
            file_index += 1
        elif chunk.text:
            print(chunk.text, end="", flush=True)
    print("\nGeneration complete. ✨")


if __name__ == "__main__":
    generate()
3 Likes

Ive had the same issue it seems to be a limitation of the model (currently). I am attempting to intelligently resize images to a specific aspect ratio and it will always re-use the source images dimensions. it’s probably just a “wait for them to fix it” kind of deal.

If you add a second image , your ‘scene’, and make sure that is the last image added to the prompt, it’s aspect ratio will be used.

4 Likes

Hero we need :slight_smile: Thanks…

Yes ! My bad I should have posted earlier, I actually found a similar fix. Actually I don’t have control over the second image size or ratio, it’s user uploaded. So here is how I tackled the problem

I eventually settled with a basic solution. Instead of forcing the model to generate the right ratio, I use an intermediary step.

In my case my reference image always come with the right size / target ratio I need, while other elements that need to be inserted don’t.

For instance, let’s say a random person sitting at a table as the reference image, and a cup of coffee I want to insert in the hand of that person.

I make sure the person reference image is built with the right initial ratio / size (for instance 1:1 1024x1024). As for the cup of coffee (let’s say a 16:9 ratio), I create a intermediary step where I insert the cup of into a 1:1 1024x1024 canva.

With this approach, all input images have the same size & ratio. Therefore the final image output also maintains the expected image ratio & size.

1 Like