Внутри xlsx картинка — это файл в пакете: PNG или JPEG кладётся в xl/media, а лист получает описание привязки — якорь с ячейкой, смещением и режимом поведения. Отсюда следствие, которое объясняет половину вопросов про вес файла: каждая вставка копирует картинку целиком, и тридцать фото товара утяжеляют прайс на все их мегабайты, а не на ссылки. Второе следствие касается поведения: картинка привязана к ячейке не намертво, а по правилу, которое выбирает генератор — двигаться с ячейками, двигаться без растягивания или не двигаться вовсе. Эти правила описывает структура GraphicOptions, и в них же живёт масштаб. Отдельная тонкость: excelize не знает ни размеров листа, ни замысла макета — логотип поверх шапки означает, что шапка должна уступить место, и это тоже работа генератора. Разберём вызов по частям: якорь, масштаб, режим привязки, и кейс про логотип, который растянулся на поллиста после правки ширины колонок.
AddPicture: addpicture excelize и якорь#
Сигнатура в современных версиях: f.AddPicture принимает лист, ячейку-якорь, путь к файлу и указатель на GraphicOptions, а возвращает пару (string, error) — идентификатор вставки. Вызов f.AddPicture("Отчёт", "A1", "logo.png", opts) поставит верхний-левый угол картинки в ячейку A1: логотип встанет в угол шапки, а не по центру ячейки. Ошибка вернётся на несуществующем файле — путь проверяется при вставке, поэтому ошибка чтения диска всплывёт именно здесь, а не при SaveAs. Если картинка уже в памяти — файл из сети, из базы, из архива — вместо чтения с диска берут AddPictureFromBytes: он принимает байты и расширение и работает так же, только без промежуточного файла на диске. Список вставленного читается GetPictures: метод вернёт картинки листа с содержимым, что удобно в тестах — проверить, что логотип в файле попал, можно без открытия Excel. Запрос excelize картинка упирается в эту четвёрку: путь, ячейка, опции, идентификатор.
Логотип в шапке отчёта
GOlogoID, err := f.AddPicture("Отчёт", "A1", "logo.png", &excelize.GraphicOptions{
ScaleX: 0.4,
ScaleY: 0.4,
Positioning: excelize.PositionOneCell,
LockAspectRatio: true,
})
if err != nil {
panic(err)
}
f.SetColWidth("Отчёт", "A", "A", 12)Масштаб 0.4 ужал логотип до сорока процентов исходного размера, якорь oneCell позволит картинке двигаться с ячейкой, но не растягиваться, а LockAspectRatio сохранит пропорции. Ширина колонки A задана под логотип: ячейка-якорь отвечает за верхний-левый угол картинки.
Режим Positioning определяет поведение картинки, когда пользователь меняет ширину колонок и высоту строк: twoCell — картинка тянется вместе с ячейками и может растянуться до неузнаваемости, oneCell — картинка сдвинется вслед за ячейками, но размер сохранит, absolute — картинка не двигается вовсе и живёт на координатах листа. По умолчанию действует twoCell, и именно из-за него логотипы расползаются после правки ширины: для лого и печатей берут oneCell, для декоративных подложек — absolute.
Масштаб и размеры: ScaleX и ScaleY#
Размер картинки в GraphicOptions задаётся масштабом, а не шириной и высотой: ScaleX и ScaleY — множители исходного размера файла, единица оставляет как есть, ноль целых четыре десятых — сорок процентов. Отдельного поля «вставить шириной три сантиметра» нет, и когда размер в сантиметрах требуется, масштаб считают в Go: исходные пиксели картинки известны, целевые тоже, множитель — деление одного на другое. Полезно знать, что исходный размер — это пиксели файла, а не экранное впечатление: логотип на четыре тысячи пикселей и логотип на четыреста с одним множителем встанут по-разному, поэтому множитель считают от конкретного файла, а не от привычки. LockAspectRatio true связывает обе оси: при изменении одной эксель пропорционально подстроит вторую, и логотип не станет квадратным из прямоугольного. Смещение внутри ячейки задают OffsetX и OffsetY — пригодится, когда картинку нужно сдвинуть на пару пикселей от границ. Полезные флаги: PrintObject решает, попадёт ли картинка на печать — логотипу положено true, водяному знаку данных нет, AltText пишет альтернативный текст для доступности и поиска. Так addpicture excelize описывает картинку одним набором полей, и всё остальное — вычисление множителей и выбор якоря.
Фото товара в строке прайса
GOfor i, item := range items {
if item.Photo == "" {
continue
}
cell := fmt.Sprintf("D%d", i+2)
if _, err := f.AddPicture("Прайс", cell, item.Photo, &excelize.GraphicOptions{
ScaleX: 0.25,
ScaleY: 0.25,
Positioning: excelize.PositionOneCell,
}); err != nil {
panic(err)
}
}Якорь считается по строке прайса той же Sprintf-техникой, что в формулы и координаты. Пустые фото пропущены: AddPicture вернёт ошибку на несуществующем файле, и один битый путь уронил бы весь прайс — наличие файлов проверяют до цикла, на месте генерации.
Вес файла и медиа внутри xlsx#
Картинка переезжает в файл целиком: xlsx — это zip, и xl/media получит копию вашего PNG. Три вставки одного логотипа — три копии в медиа, и никаких дедупликаций библиотека не делает. Прайс с тридцатью фотографиями по пятьсот килобайт станет тяжелее на пятнадцать мегабайт, а Excel при открытии будет раскладывать все эти медиа — на слабых машинах это заметная задержка. Лечение генераторное: готовьте картинки заранее — ужимайте, режьте миниатюры, держите в отдельной папке версии под xlsx — и вставляйте их, а не оригиналы из фотоаппарата. Тот же подход экономит и трафик: отчёт на пятнадцать мегабайт не каждый почтовый ящик примет, и вложение урежет фильтр сервера раньше, чем его увидит получатель.
Чтение и форматы: GetPictures без Excel#
Сказанное про медиа верно и в обратную сторону: GetPictures вернёт байты вставленных картинок, и их можно вынуть из файла без Excel, что удобно для миграций и аудита. По чужому файлу видно, какие изображения в нём лежат, сколько они весят и где на листе стоят — картина полезнее, чем визуальный осмотр, потому что якоря и копии видны сразу. Расширения поддерживаются распространённые — PNG, JPEG, GIF и ещё несколько графических форматов, а вот SVG excelize в xlsx не положит: вектор придётся растеризовать заранее, и это ещё один пункт в копилку подготовки медиа до генерации. Запрос excelize картинка на проде чаще всего превращается в вопрос дисциплины: кто готовит медиа, какого веса и в какой папке они хранятся.
Поля GraphicOptions одним взглядом#
| Поле | Значение | Для чего берут |
|---|---|---|
| ScaleX, ScaleY | 0.4 — сорок процентов | масштаб от исходного размера файла |
| Positioning | oneCell, twoCell, absolute | поведение при правке строк и колонок |
| OffsetX, OffsetY | сдвиг от угла ячейки | поправить позицию логотипа в шапке |
| LockAspectRatio | true | пропорции при изменении одной из осей |
| PrintObject | true или false | включить картинку в печать или убрать |
| AltText | текст-описание | доступность и поиск по файлу |
GetPictures вернёт вставленные картинки листа с их содержимым: файл можно разобрать без Excel и вынуть логотипы или фото для миграции в другую систему. Пригодится и для тестов: проверка, что прайс получил свои медиа, не требует офисного пакета — байты сравниваются прямо в тесте генерации.
Чек-лист картинок#
- AddPicture принимает лист, якорь, путь и GraphicOptions, возвращает (string, error).
- Размер задаётся масштабом ScaleX и ScaleY от исходного файла, а не сантиметрами.
- Positioning: twoCell тянется с ячейками, oneCell двигается без растягивания, absolute стоит намертво.
- LockAspectRatio true держит пропорции; OffsetX и OffsetY сдвигают внутри якоря.
- Каждая вставка копирует файл в xl/media: вес растёт на размер картинок, дедупликации нет.
- Несуществующий путь вернёт ошибку при вставке: проверяйте наличие файлов до цикла.
AddPicture требует файла картинки на диске, поэтому в браузерной песочнице не запускается: там доступны fmt, strings, strconv, math, sort, errors и time без файлового ввода-вывода. Посчитать масштаб потренировать можно: поделите целевую ширину на исходную math'ем и напечатайте множитель с двумя знаками — файл с логотипом соберите локально.
Кейс про логотип, который съел шапку. Команда вставляла логотип компании в шапку еженедельного отчёта, и первая версия выглядела нормально ровно до первой правки: кто-то раздвинул колонку A под длинные наименования, и логотип потянулся вдвое, закрыв шапку и половину строки данных. Причина оказалась в умолчании twoCell: картинка привязана к двум ячейкам и тянется вместе с ними. Лечение заняло один вызов: Positioning oneCell с LockAspectRatio — логотип двигается вслед за ячейками, но растягиваться перестал. Вторая волна жалоб пришла от получателей на слабых машинах: файл потяжелел вдвое после того, как в прайс добавили фото товара — оригиналы по два мегабайта вставлялись тридцать штук. Собрали миниатюры на двести пикселей, вес вернулся, а к генератору добавили правило: медиа для xlsx готовятся отдельно, в оригинальном размере вставка не делается. Спорная сторона осталась с дизайнером: логотип в шапке поверх заливки требует прозрачного PNG, и часть старых файлов с белой плашкой вокруг логотипа так и живёт в архиве.
Проверка: поведение якоря
Логотип вставлен с Positioning: excelize.PositionOneCell. Что произойдёт, когда пользователь увеличит ширину колонки, к которой привязана картинка?
Проверка: куда попадает файл
После AddPicture("Отчёт", "A1", "logo.png", opts) где физически лежит картинка внутри xlsx?
Что напечатает код?
Прочитайте код и выберите, что он выведет:
opts := &excelize.GraphicOptions{ScaleX: 1, ScaleY: 1}
opts.ScaleX = 0.5
fmt.Println(opts.ScaleY)Соберите вставку логотипа
Допишите вызов вставки, второй масштаб, режим якоря и переменную ошибки.
Соберите шапку с логотипом
Расставьте строки в порядке выполнения: написать заголовок, вставить логотип, проверить ошибку, задать ширину колонки, сохранить файл, закрыть книгу.
Строки
Ваша программа
Нажимайте на строки слева, чтобы собрать программу
Карточки: картинки
Логотип стоит в шапке, якорь выбран осознанно, вес файла под контролем. Отчёт готов к последним штрихам навигации: в уроке про закрепление областей и автофильтры шапка перестанет уезжать на длинных выгрузках, а в уроке про защиту листа логотип получит соседей, которых нельзя подвинуть случайно. Ширина колонки под логотип ставится тем же SetColWidth из урока про слияние и ширину, а координаты якоря собираются техникой из урока про чтение ячеек. Логотип и фото товара встречаются в шаблоне экспорта отчёта из базы — там медиа готовятся до цикла, а не внутри него. Домашнее задание — логотип в шапку с якорем oneCell и пересчёт масштаба под свои размеры.
Песочница урока
Редактируйте код и запускайте его прямо здесь — интерпретатор работает в браузере, ничего устанавливать не нужно. За каждый запуск — +2 XP.
Запустите код, чтобы увидеть вывод.
Коротко: что запомнить
- AddPicture копирует файл в xl/media и ставит якорь на листе; возвращает (string, error).
- Размер задаётся масштабом ScaleX и ScaleY; сантиметров в опциях нет — множитель считают в Go.
- Positioning решает поведение: twoCell тянется, oneCell двигается, absolute стоит намертво.
- LockAspectRatio держит пропорции, OffsetX и OffsetY сдвигают картинку внутри ячейки.
- Каждая вставка — новая копия в медиа: миниатюры готовят до вставки, а не вместо неё.
- GetPictures читает картинки обратно — пригодится в тестах и миграциях без Excel.
Домашнее задание
Вставьте логотип своей компании в шапку отчёта: якорь A1, масштаб подберите так, чтобы картинка встала в колонку шириной двенадцать символов, режим oneCell с сохранением пропорций. Добавьте фото в первую строку прайса, проверьте GetPictures, что обе картинки в файле, затем раздвиньте колонки в Excel и убедитесь, что логотип больше не растягивается.
Личные заметкиПусто
Вопросы и ответы по уроку
Почему логотип растянулся после изменения ширины колонок?
Вставка прошла с умолчанием twoCell: картинка привязана к двум ячейкам и тянется вместе с ними. Перевставьте с Positioning: excelize.PositionOneCell и LockAspectRatio: true — логотип будет двигаться с ячейками, но размер сохранит.
Как задать картинке размер в сантиметрах?
Поля ширины и высоты в GraphicOptions нет — размер задаётся множителями ScaleX и ScaleY от исходного файла. Посчитайте масштаб в Go: целевую ширину поделите на исходные пиксели картинки и передайте результат в оба поля.
Файл с картинками стал тяжелее ожидаемого — что делать?
Каждая вставка копирует картинку целиком в xl/media без дедупликации, поэтому оригиналы по мегабайту утяжеляют файл на каждый экземпляр. Готовьте миниатюры заранее и вставляйте их; если картинка приходит из памяти, берите AddPictureFromBytes вместо временных файлов.
Термины урока
Ключевые понятия из этого урока — короткие определения в глоссарии. Наведите на термин, чтобы вспомнить, откройте карточку для подробностей и ссылки на практику.
Изучайте дальше
Следующая ступень учебного пути
Фоновые задачи в Go: планировщик на robfig/cron
Курс по cron в Go: robfig/cron v3, синтаксис выражений, пояса, wrappers, конкурентность и graceful shutdown. 25 уроков с примерами и проектом.
- Собирать планировщик на robfig/cron v3 и запускать задачи по расписанию
- Читать и писать cron-выражения: пять полей, спецсимволы, @daily
- Управлять жизненным циклом: Start, Stop, Entry, Remove
- Держать часовые пояса и секундные расписания под контролем