# GPT Image 2.6 markup: редактирование по разметке и проверка слоя

> Markup в GPT Image 2.6 — прозрачный PNG размером с фото: он показывает, где править, prompt — что. 200 в ответе не значит, что маршрут прочитал слой.

- URL: https://blog.laozhang.ai/ru/posts/gpt-image-2-6-image-markup-api
- Published: 2026-11-05
- Updated: 2026-11-05
- Author: LaoZhang AI Team (https://blog.laozhang.ai/ru/about)
- Topic: Руководства по API
- Tags: GPT Image 2.6, markup, редактирование изображений, OpenAI API, Flare, Sunburst

---
Параметр `markup` в GPT Image 2.6 — это отдельный прозрачный PNG того же размера, что и фото, на котором вы обводите или зарисовываете место правки. Слой разметки отвечает на вопрос «где», а что именно поменять, вы по-прежнему пишете в `prompt`. Отправляется он в `POST /v1/images/edits` с моделью `gpt-image-2.6-flare` или `gpt-image-2.6-sunburst`: в multipart-запросе — файлом в поле `markup`, в JSON — объектом `"markup": {"image_url": ...}` или `{"file_id": ...}` рядом с массивом `images`. Это не маска: вместе с `mask` и `prompt_rewriter` слой передавать нельзя, и действует он только на первое входное изображение. OpenAI добавила разметку в API вместе с Images 2.6 4 ноября 2026 года, отдельной платы за неё нет.

Перед платным вызовом проверьте слой локально: после учёта EXIF-ориентации у него должны быть те же ширина и высота, что у фото, в нём должны быть настоящие прозрачные пиксели, не больше 16 777 216 пикселей и не больше 50 МБ. Скрипт на Python ниже собирает такой слой по координатам и проверяет все четыре правила. После ответа сравните с оригиналом всё, что лежит за пределами круга, иначе вы не узнаете, перерисовала ли модель заодно остальную картинку.

Главное условие — маршрут, через который идёт запрос. Ответ 200 не означает, что разметку прочитали: 5 ноября 2026 года поштучные маршруты LaoZhang API `gpt-image-2.6-web` и `gpt-image-2.6-sunburst-vip` приняли слой без ошибки, но обведённый стул ни разу не перекрасили, и с разметкой результат был таким же, как без неё. Поэтому `markup` отправляйте напрямую в OpenAI или через маршрут, который передаёт тело запроса OpenAI без изменений.

*Примечание: [laozhang.ai — наш собственный сервис](https://blog.laozhang.ai/ru/about#laozhang); его цены — наши тарифы, а не независимое сравнение.*

## Слой разметки, маска или только текст: что выбрать для точечной правки

Слой разметки нужен, когда цель трудно назвать словами: в кадре несколько одинаковых предметов, и фраза «второй стул слева» уже не раз приводила к правке не того объекта. Если объект в кадре один и легко называется, хватит текста. Маска (`mask`) — другой параметр со своими правилами, и в Responses API для правки отдельной области руководство OpenAI предлагает именно её, потому что `markup` есть только в Image API.

| Что сравниваем | Слой разметки (`markup`) | Маска (`mask`) | Только текст |
| --- | --- | --- | --- |
| Как задаётся место | Круги, наброски и другие пометки на прозрачном PNG | PNG с альфа-каналом, отмечающим область правки | Описание объекта в `prompt` |
| Где работает | Только Image API, `/v1/images/edits` | Image API и Responses API | Везде |
| Насколько точно соблюдается область | Модель видит, куда указали, но перерисовывает картинку целиком; в примере OpenAI за кругом изменилось 4,3–8,4 % | По руководству OpenAI, маска — ориентир для модели, и её форма может соблюдаться неточно | Модель угадывает цель; 5 ноября 2026 года без пометки жёлтым стал не тот из четырёх стульев |
| Ограничения | Нельзя вместе с `mask` и `prompt_rewriter`; действует на первое изображение | Тот же формат и размер, что у фото, меньше 50 МБ; действует на первое изображение | Нет |
| Когда брать | Несколько похожих объектов, нужно указать один | Правка через Responses API или область уже есть в виде маски | Объект уникален в кадре |

Если вы правите картинку не через API, а в приложении ChatGPT, там есть собственная кнопка разметки, и она перерисовывает изображение заново — об этом в статье [Редактор фото ChatGPT: каждая кнопка заново рисует картинку](https://blog.laozhang.ai/ru/posts/chatgpt-image-editor).

## Требования к слою markup: размер после EXIF, прозрачность, 16 777 216 пикселей

Требования к слою разметки по [руководству OpenAI по генерации изображений, раздел Guide an edit with markup](https://developers.openai.com/api/docs/guides/image-generation#guide-an-edit-with-markup), по состоянию на 5 ноября 2026 года: отдельный прозрачный PNG с той же шириной и высотой, что у первого входного изображения после учёта ориентации, с прозрачными пикселями и не наложенный на оригинал. Первое изображение и слой могут содержать не больше 16 777 216 пикселей каждый (например, 4096×4096), файл слоя — не больше 50 МБ. Чаще всего ломаются первые два правила, и оба легко поймать до отправки.

| Правило | Типичная причина нарушения | Как проверяет скрипт ниже |
| --- | --- | --- |
| Ширина и высота как у первого изображения после учёта ориентации | Фото с телефона хранится повёрнутым и поворачивается по EXIF, а слой нарисован по другому виду; слой экспортирован в другом масштабе | Поворачивает фото по EXIF и сравнивает размеры |
| Есть прозрачные пиксели, слой не сведён с фото | Экспорт с «объединить слои», сохранение в JPEG, отправка фото с уже нарисованным кругом | Требует RGBA и хотя бы один пиксель с альфой меньше 255 |
| Лимит пикселей для фото и для слоя | Снимок с камеры на 24 Мп | Перемножает ширину и высоту |
| Лимит размера файла слоя | Несжатый PNG очень большого разрешения | Смотрит размер файла |
| Слой относится к первому изображению; остальные — референсы | Исходное фото стоит в `images` не первым | Не проверяет: это порядок в запросе |
| Без `mask` и `prompt_rewriter` | Параметры остались от старой функции правки | Не проверяет: это поля запроса |

В JSON-запросе есть ещё одно ограничение. По [справочнику OpenAI по методу images.edit](https://developers.openai.com/api/reference/resources/images/methods/edit) строка `image_url` не длиннее 20 971 520 символов, а base64 раздувает файл на треть, поэтому в data URL помещается примерно 15 МБ PNG (20 971 520 × 3/4 = 15 728 640 байт). Слой больше этого отправляйте через multipart или по `file_id`.

![Четыре правила для слоя markup, результат проверки скриптом на фото 1200×900 и поля, которых не должно быть в запросе](https://blog.laozhang.ai/posts/ru/gpt-image-2-6-image-markup-api/img/markup-layer-checks.webp)

## Как собрать слой разметки и проверить его до платного вызова

Слой проще нарисовать кодом, чем в редакторе: так он гарантированно совпадёт с фото по размеру и останется прозрачным. Скрипт ниже (Python, Pillow) поворачивает фото по EXIF, рисует красный эллипс на полностью прозрачном холсте того же размера и проверяет четыре правила из предыдущего раздела. Координаты `x0 y0 x1 y1` — прямоугольник, в который вписан эллипс, в пикселях фото в том виде, в каком оно отображается после поворота.

```python
"""Собирает и проверяет слой разметки для правок GPT Image 2.6 / 2.5.
Рисует красный эллипс на полностью прозрачном холсте размером с фото (после учёта EXIF-ориентации)
и проверяет правила OpenAI: та же ширина и высота, что у первого входного изображения, есть прозрачные
пиксели, не больше 16 777 216 пикселей, файл не больше 50 МБ.
Запуск: python3 make_markup_overlay.py photo.jpg x0 y0 x1 y1 [out.png]"""
import os, sys
from PIL import Image, ImageDraw, ImageOps

MAX_PIXELS = 16_777_216
MAX_BYTES = 50 * 1024 * 1024


def build(photo, box, out):
    img = ImageOps.exif_transpose(Image.open(photo))  # API сравнивает размеры после учёта ориентации
    overlay = Image.new("RGBA", img.size, (0, 0, 0, 0))
    ImageDraw.Draw(overlay).ellipse(box, outline=(230, 20, 20, 255), width=max(4, img.width // 150))
    overlay.save(out)
    return img.size


def check(photo, out):
    img = ImageOps.exif_transpose(Image.open(photo))
    ov = Image.open(out)
    problems = []
    if ov.size != img.size:
        problems.append(f"size {ov.size} != photo {img.size}")
    if ov.mode != "RGBA" or ov.getchannel("A").getextrema()[0] == 255:
        problems.append("no transparent pixels (flattened overlay)")
    if ov.width * ov.height > MAX_PIXELS:
        problems.append("overlay over 16,777,216 pixels")
    if os.path.getsize(out) > MAX_BYTES:
        problems.append("overlay over 50 MB")
    return problems


if __name__ == "__main__":
    photo, *nums = sys.argv[1:6]
    out = sys.argv[6] if len(sys.argv) > 6 else "markup.png"
    size = build(photo, [int(n) for n in nums], out)
    issues = check(photo, out)
    print(f"photo {size[0]}x{size[1]} -> {out} ({os.path.getsize(out)} bytes)")
    print("OK" if not issues else "FAIL: " + "; ".join(issues))
```

5 ноября 2026 года скрипт прогнали на кухонном фото 1200×900 из примера OpenAI, обведя передний левый стул: команда `python3 make_markup_overlay.py kitchen.png 235 610 465 785 markup.png` вывела `photo 1200x900 -> markup.png (5645 bytes)` и `OK`. Готовый слой из другого источника проверяется той же функцией: `python3 -c "from make_markup_overlay import check; print(check('kitchen.png', 'overlay.png'))"`. Слой 1000×750 к тому же фото она отклонила с сообщением `size (1000, 750) != photo (1200, 900)`, слой, сведённый на белый фон, — с `no transparent pixels (flattened overlay)`, а слой из примера OpenAI прошёл с пустым списком замечаний. Скрипт строгий: палитровый PNG с прозрачностью он тоже отклонит, так что сохраняйте слой в RGBA.

Проверка повторяет правила из документации OpenAI, а не ответ сервера. Она нужна потому, что некоторые маршруты не возвращают ошибку на неверный слой, и без локальной проверки вы заплатите за правку, в которой разметка ничего не значила.

## Как отправить markup в /v1/images/edits: multipart и JSON

Запрос с разметкой — это обычная правка, в которую добавлено одно поле. Порядок такой:

1. Поставьте исходное фото первым: в multipart это поле `image`, в JSON — первый элемент массива `images`. Дополнительные изображения после него модель использует как референсы, разметка к ним не относится.
2. Передайте слой в поле `markup`: в multipart — файлом, в JSON — объектом ровно с одним из ключей `image_url` (HTTPS-адрес или base64 data URL) или `file_id`.
3. В `prompt` назовите объект через пометку («the chair inside the red circle»), опишите изменение, перечислите, что сохранить, и попросите убрать красный круг из готового фото — так сделано в примере OpenAI. Как формулировать такие правки по схеме «измени только X, сохрани Y», разобрано в [руководстве по промптам GPT Image 2.6](https://blog.laozhang.ai/ru/posts/gpt-image-2-6-prompt-guide).
4. Задайте `size` явно (размеры кратны 16, соотношение сторон от 1:3 до 3:1, для фото 4:3 подходит `1536x1152`) или `auto`. Для точечной правки OpenAI советует начинать с `complexity: "low"`, а `quality` выбирать по задаче.
5. Не передавайте `mask`, `prompt_rewriter` и `input_fidelity`: первые два несовместимы с разметкой, третий OpenAI просит не указывать при правках.
6. Сохраните результат из `data[0].b64_json` и сравните его с оригиналом (процедура в разделе о проверке ниже).

Multipart через официальный Python SDK повторяет пример из руководства OpenAI:

```python
import base64
from pathlib import Path
from openai import OpenAI

PROMPT = ("Recolor the chair inside the red circle to bright mustard-yellow leather. Keep its shape. "
          "Keep the other chairs white and keep the rest of the kitchen unchanged. "
          "Remove the red circle from the finished photo.")

client = OpenAI()  # ключ из OPENAI_API_KEY
with open("kitchen.png", "rb") as image, open("markup.png", "rb") as markup:
    result = client.images.edit(
        model="gpt-image-2.6-sunburst",
        image=("kitchen.png", image, "image/png"),
        markup=("markup.png", markup, "image/png"),
        prompt=PROMPT,
        quality="medium",
        size="1536x1152",
    )
Path("edited.png").write_bytes(base64.b64decode(result.data[0].b64_json))
```

В JSON входные изображения передаются массивом `images`, а слой — объектом. Если версия SDK у вас старая и не знает поля `markup`, этот вариант через `requests` от неё не зависит:

```python
import base64, os
from pathlib import Path
import requests

def data_url(path):
    return "data:image/png;base64," + base64.b64encode(Path(path).read_bytes()).decode()

body = {
    "model": "gpt-image-2.6-sunburst",
    "images": [{"image_url": data_url("kitchen.png")}],  # первое изображение — то, которое правим
    "markup": {"image_url": data_url("markup.png")},     # ровно один ключ: image_url или file_id
    "prompt": PROMPT,                                     # тот же текст, что в примере выше
    "quality": "medium",
    "complexity": "low",
    "size": "1536x1152",
}
r = requests.post(
    "https://api.openai.com/v1/images/edits",
    headers={"Authorization": f"Bearer {os.environ['OPENAI_API_KEY']}"},
    json=body,
    timeout=300,
)
r.raise_for_status()
Path("edited.png").write_bytes(base64.b64decode(r.json()["data"][0]["b64_json"]))
```

## Где markup действительно читается: тест маршрутов 5 ноября 2026 года

Напрямую в OpenAI разметка работает по документации и по опубликованному примеру. На поштучных маршрутах LaoZhang API `gpt-image-2.6-web` и `gpt-image-2.6-sunburst-vip` 5 ноября 2026 года она видимой разницы не дала. Тест был устроен так, чтобы текст сам по себе не подсказывал цель: на кухонном фото 1200×900 четыре одинаковых белых стула, слой разметки обводит передний левый, а промпт называет только «стул внутри красного круга» и просит перекрасить его в горчично-жёлтый, оставив остальные белыми. Каждую ячейку запускали по одному разу.

*Примечание: [laozhang.ai — наш собственный сервис](https://blog.laozhang.ai/ru/about#laozhang); его цены — наши тарифы, а не независимое сравнение.*

| Маршрут | Слой разметки | Размер ответа | Какой стул стал жёлтым | Время |
| --- | --- | --- | --- | --- |
| `gpt-image-2.6-web` | есть | 1448×1086 | передний правый (не тот) | 24 с |
| `gpt-image-2.6-web` | нет | 1448×1086 | стулья справа (не те) | 24 с |
| `gpt-image-2.6-sunburst-vip`, `size: "1536x1152"` | есть | 1536×1152 | передний правый (не тот) | 38 с |
| `gpt-image-2.6-sunburst-vip`, `size: "1536x1152"` | нет | 1536×1152 | передний правый (не тот) | 38 с |

Обведённый стул во всех четырёх случаях остался белым, красного круга ни в одном ответе не было. Первый раунд с вазой из примера OpenAI этого не показал бы: вазу на столе модель перекрашивала и без разметки, и с расплывчатым «Make the vase blue.», потому что её легко найти по одному тексту. В том же раунде VIP-маршрут принял слой неверного размера (1000×750) и непрозрачный слой с ответом 200 и без единой ошибки. Отсюда практическое правило: чтобы проверить, читает ли маршрут разметку, обведите один из нескольких одинаковых предметов и сравните ответ с разметкой и без неё.

![Тест маршрутов web и sunburst-vip со слоем и без: во всех четырёх случаях жёлтым стал не обведённый стул](https://blog.laozhang.ai/posts/ru/gpt-image-2-6-image-markup-api/img/markup-route-test.webp)

Квадратный результат вместо исходного кадра — отдельная ловушка VIP-маршрута. Без параметра `size` он возвращал 2048×2048 и перекомпоновывал кухню 4:3 в квадрат, а с явным `size: "1536x1152"` сохранил 4:3. Маршрут `gpt-image-2.6-web` с разметкой отдал 1448×1086, тот же размер, что и опубликованные результаты OpenAI для этого фото с `size="auto"`.

Для разметки через LaoZhang нужен официальный проброс: модели `gpt-image-2.6-flare` и `gpt-image-2.6-sunburst` в группе `OpenAI Official` (или `OpenAI Official Enterprise` с наценкой 20 %), оплата по токенным ценам OpenAI. По [документации LaoZhang API по GPT Image](https://docs.laozhang.ai/ru/api-capabilities/gpt-image-2-5) тело запроса там такое же, как у официального API, меняется только `model`; в Python это `OpenAI(base_url="https://api.laozhang.ai/v1", api_key=...)` с ключом из этой группы. О `markup` документация не пишет, и отдельного прогона разметки через официальный проброс 5 ноября 2026 года не было, поэтому перед рабочей нагрузкой проверьте его тестом с одинаковыми предметами. Поштучные маршруты стоят $0,03 за вызов, правки включены, но для разметки они, судя по тесту выше, не годятся.

Сама разметка ничего не добавляет к цене. По [руководству OpenAI](https://developers.openai.com/api/docs/guides/image-generation#guide-an-edit-with-markup) правки с разметкой считаются по тем же токенным тарифам, что и остальные правки; у GPT Image 2.6 это $8 за 1 млн входных токенов изображения, $30 за 1 млн выходных и $5 за 1 млн входных текстовых. Для ориентира: одна обычная правка без разметки на Sunburst с `quality: "low"` через официальный проброс LaoZhang в замере команды документации LaoZhang обошлась в $0,03301.

## Как проверить, что правка осталась внутри круга

Модель не вклеивает изменение в старые пиксели, а перерисовывает изображение целиком, поэтому разница с оригиналом за пределами пометки никогда не равна нулю. Вопрос в том, насколько она велика. OpenAI в примере с вазой сама советует сравнить остальную часть каждого изображения с оригиналом, и это можно сделать числом:

1. Возьмите исходное фото и тот же слой разметки, что отправляли.
2. Запустите скрипт ниже: он уменьшает результат до размера оригинала, закрашивает эллипс по границам пометки и выводит среднюю разницу пикселей внутри и снаружи в процентах от полной шкалы.
3. Сравните два числа: внутри круга разница должна быть заметно больше, чем снаружи.
4. Посмотрите глазами на то, что важно за кругом (лица, надписи, края мебели), и убедитесь, что красного круга в результате нет.
5. Если снаружи изменилось много, повторите с `complexity: "low"` и явным «keep the rest unchanged» в промпте или попробуйте `gpt-image-2.6-sunburst` на `medium` или `high`.

```python
"""Сравнивает результат правки с оригиналом внутри и снаружи пометки.
Использование: python3 check_edit_area.py photo.png markup.png result.png"""
import sys
import numpy as np
from PIL import Image, ImageDraw, ImageOps

photo_path, markup_path, result_path = sys.argv[1:4]
orig = ImageOps.exif_transpose(Image.open(photo_path)).convert("RGB")
alpha = np.array(Image.open(markup_path).convert("RGBA"))[:, :, 3]
ys, xs = np.nonzero(alpha > 0)                      # непрозрачные пиксели пометки
region = Image.new("L", orig.size, 0)
ImageDraw.Draw(region).ellipse([xs.min(), ys.min(), xs.max(), ys.max()], fill=255)
inside = np.array(region) > 0                       # закрашенный круг пометки

result = Image.open(result_path).convert("RGB")
print("размер результата:", result.size, "оригинал:", orig.size)
a = np.array(orig).astype(float)
b = np.array(result.resize(orig.size, Image.LANCZOS)).astype(float)
diff = np.abs(b - a).mean(axis=2) / 255 * 100       # средняя разница, % от полной шкалы
print(f"внутри пометки: {diff[inside].mean():.1f} %")
print(f"снаружи:        {diff[~inside].mean():.1f} %")
```

Скрипт рассчитан на одну пометку: при нескольких кругах или свободном наброске он берёт эллипс, вписанный в общий прямоугольник всех пометок, и тогда «внутри» окажется больше, чем вы обвели.

Ориентиры дают опубликованные OpenAI результаты примера с вазой, разобранные этим способом 5 ноября 2026 года. Оба ответа пришли размером 1448×1086 при входе 1200×900. Внутри круга изменилось 12,1 % у Sunburst и 11,2 % у Flare, снаружи — 4,3 % у Sunburst и 8,4 % у Flare, то есть в этом примере Flare изменил остальную кухню примерно вдвое сильнее. Собственный контрольный расчёт блога 5 ноября 2026 года показывает, сколько из этого шум масштабирования: если исходное фото 1200×900 увеличить до 1448×1086 и вернуть обратно фильтром LANCZOS, тот же скрипт даёт около 0,3 % снаружи, так что почти вся разница — работа модели. Это один пример, а не рейтинг моделей; OpenAI отдельно пишет, что Sunburst стабильнее от правки к правке на `medium` и `high`.

## Markup и GPT Image 2.5: что пишут руководство и справочник OpenAI

Документы OpenAI по состоянию на 5 ноября 2026 года расходятся в том, каким моделям доступна разметка. [Руководство по генерации изображений](https://developers.openai.com/api/docs/guides/image-generation#guide-an-edit-with-markup) говорит о правках с разметкой для «supported GPT Image 2.5 and 2.6 models», а [справочник по методу images.edit](https://developers.openai.com/api/reference/resources/images/methods/edit) в описании поля `markup` пишет только «Supports GPT Image 2.5». Анонс Images 2.6, где разметка «comes to the API», и пример в руководстве с `gpt-image-2.6-flare` говорят в пользу 2.6, поэтому на 2.6 разметку можно отправлять. GPT Image 2.5 называют оба документа, хотя руководство пишет о «поддерживаемых» моделях 2.5 и списка не даёт.

Многие страницы, где разметку называют функцией GPT Image 2.5, написаны до 4 ноября 2026 года, когда у 2.6 ещё не было ID модели в API; теперь они есть — `gpt-image-2.6-flare` и `gpt-image-2.6-sunburst`. Стоит ли переводить на 2.6 остальные задачи и сколько это стоит по уровням качества, разобрано в статье [GPT Image 2.6: отличия от 2.5 — GIF, SVG и low в 4 раза дороже](https://blog.laozhang.ai/ru/posts/gpt-image-2-6-vs-2-5).

## Источники

Внешние страницы, на которые ссылается это руководство, в порядке упоминания. Последнее обновление: 2026-11-05.

- [руководству OpenAI по генерации изображений, раздел Guide an edit with markup](https://developers.openai.com/api/docs/guides/image-generation) (developers.openai.com)
- [справочнику OpenAI по методу images.edit](https://developers.openai.com/api/reference/resources/images/methods/edit) (developers.openai.com)
