Под лицензией MIT опубликована кросс-платформенная библиотека декодирования изображений SAIL. SAIL - это переписанный на С ребрендинг кодеков из давно не поддерживаемой программы просмотра изображений KSquirrel, но с наличием высокоуровнего абстрактного API и многочисленными улучшениями. Целевая аудитория: просмотрщики изображений, разработка игр, загрузка изображений в память для иных целей. Библиотека находится в стадии разработки, но уже пригодна для использования. Бинарная совместимость и совместимость исходного кода на данном этапе разработки не гарантируется...Подробнее: https://www.opennet.dev/opennews/art.shtml?num=53354
Единственная нормальная новость, от которой веет здоровым юниксом.
А кто сказал, что юникс-подход здоров?
Практика показала, что отход от него порождает раздутые переусложнённые решения.
чья практика? кто сказал, что она что-то показали или показала то, о чем ты говоришь? пока что в твоих словака очередной бурчание ретрограда-хейтера, не более
Моя личная и тех анонимов, которые согласились, поставив плюс.
Практика Дельфи и Виндовс экосистем.
> А кто сказал, что юникс-подход здоров?Те кто посмотрел что получается если на него забить - убер-монстры делаюшие дофига всего, одинаково хреново ну совсем не рулят :)
> Поддерживаемые на данный момент форматы: APNG (чтение, только на Windows)Что?
Animated PNG. SAIL (ранее - ksquirrel-libs) была одна из первых библиотек в мире поддержавших его. Поддержка на иных платформах затруднительна, т.к. требует патчить libpng.
Т.е. оно ещё один биндинг к libpng. Я уж понадеялся что здесь будет хоть одна монолитная библиотека. С линуксом-то норм всё, а вот под винду когда собираешь проект с sdl_image - там ещё с десяток dll тащить
Под виндой библиотеки типа libpng вкомпилируются статически прямо в кодеки. Посмотри инсталлер на странице релизов.
> Под виндой библиотеки типа libpng вкомпилируются статически прямо в кодеки. Посмотри инсталлер
> на странице релизов.А потом когда в какойнить либе оказывается дыра - проще сразу застрелиться нафиг. Потому что систему потом в принципе от дыр не запатчишь. Линуксы пришли к такой модели распостранения либ не просто так же для красоты.
Декодер изображений общего назначения в 2020-м году без поддердки цветоаых профилей - это бред сивой кобылы
> Функции управления цветом (применение ICC профилей и т.д.)А если чуть внимательнее читать?
upd. Извиняюсь за наезд, я сам косоглазый, это как раз то что НЕ поддерживается )
Вот да, это это уже вишенка на торте, если изначально было не ясно.
С другой стороны, этим должен заниматься http://www.littlecms.com/ -- альтернатив у нас нет. Т.е. притащи в код стрёмных легаси либ, сам позаботься о корректном отображении написав кода больше чем в тех либах было, сам реализуй поддержку форматов (уже проходили с pil, но сегодня то вроде 2020 на дворе). Не похоже на включил в проект и теперь работаешь с любыми изображениями. Поспешили-с.
Волбще-то есть argyll как минимум. Который, насколько я помню, поприличнее, кстати
> Волбще-то есть argyll как минимум. Который, насколько я помню, поприличнее, кстатиНе используется ни одной программой. Ну такое. К тому же оно в 50 раз монструознее (btw что это за дичь у него в зависимостях http://freetype.sourceforge.net/jam/index.html *?). Но спасибо за инфу. Мне не понравился сайт (от этот http://www.argyllcms.com/).
Ну да, он монстр потому что умеет всё, что связано с цветом, а не просто профиль применить. И AGPL к тому же (что с моей точки зрения только плюс). Используется - в основном в составе DisplayCAL, которую многие считают лучшим софтом для калибровки и профилирования. В чисто рисовайках - это да, не прижился.Ещё darktable что-то своё для профилей применяет, насколько я помню.
Претензий к билдтулу не понял - сейчас их один чёрт зоопарк. К сайту - и подавно, совершенно обычный простой текстовый сайт, без модной фигни, только информация. ну да ладно, это вкусовщина уже
> Претензий к билдтулу не понял - сейчас их один чёрт зоопарк.Не, вот знаете что! Тут вот хорошая аккуратная либа - и не надо ее скатывать в гомно. А зоопарк пусть у гугловых вебмакак будет, им по статусу положено.
>Декодер изображений общего назначения в 2020-м году без поддердки цветоаых профилей - это бред сивой кобылыЦветовые профили вынимаются и предоставляются клиентскому приложению. В задачи декодера не входит т.н. "применение" цветовых профилей. Если необходимо, приложение с помощью lcms "применит" полученный профиль.
Пожалуй согласен
Как создать свой формат изображений, что почитать, посмотреть?🤔 Подскажите please🥺
http://www.compression.ru/compression.ru/book/
а поновее есть? хочу почитать про x264,x265, vp1 итд
Ну так берите спеки, и вперёд. Там по 500 и более страниц, хватит надолго.
> Как создать свой формат изображений, что почитать, посмотреть?Форумы по сжатию. Например encode.su - соотв. топики. Там есть пара довольно любопытных кодеков/идей, но до ума не доведены.
Может кто в курсе, оно хоть чем-то лучше stb_image для загрузки PNG/JPEG/BMP? Бегло посмотрел пример C/SDL - API выглядит странноватым и избыточным, как по мне. Так же, увидел пример Qt/C++, зачем оно там, когда все уже есть в Qt? Оно умеет что-то, чего не умеет Qt?
>API выглядит странноватым и избыточнымнапиши почему именно, это можно обсудить.
Это все мое субъективное мнение, возможно, все нормально и хорошо, но:Вот это `struct sail_context *context; SAIL_TRY(sail_init(&context));` Оно явно делает аллокации внутри себя. Как мне переопределить malloc с системного на свой? Что мне делать если я не хочу зависеть от crt? (Стоит добавить возможность «всунуть» свою реализацию alloc/free?).
`struct sail_context` Контекст нужен чтобы хранить метаинформацию о плагинах (скорее всего, исходники я не смотрел), но я знаю какие форматы изображений мне нужны, зачем мне загружать что-то в runtime -> Зачем мне плагины и этот «очередной» контекст? (Стоит добавить возможность статической линковки?).
Меня смущает SAIL_TRY, возникают вьетнамские флешбеки с SUCCEEDED и прочим win32 счастьем. Мне не нравится, когда в примерах демонстрируют обработку ошибок при помощи «внутренних» макросов, которые хз что делают, пока не посмотришь в исходники. Так же мне это говорит о том, что есть некий внутренний код ошибок. В итоге в проекте у тебя появляются sail_error_t, vata_error_t, SomeOtherErrorType, blah_error_t и они все работают по-разному.`struct sail_image *image; unsigned char *image_pixels;` почему оно отдельно? Может стоило назвать sail_image_meta? Это вызывает у меня дискомфорт какой-то.
Дельные мысли, спасибо
>>Так же мне это говорит о том, что есть некий внутренний код ошибок.И ничего страшного в этом нет. Для каждой библятеки заводи отдельый cpp-файл, там обрабатывай ошибки, а весь проект делай по-своему. Никто не заставляет же sail_error_t использовать повсюду.
Обычные сишные имена. Я бы назвал как-нить типа g_pszImagePixels, но это уже пахнет плюсами )
А я сказал что это страшно или плохо? Мне не нравится этот подход. Если можно что-то сделать не вводя на каждый чих новые сущноности или типы, то почему этого не сделать?
Я хочу от подобных библиотек получить следующий интерфейс.На чтение:
size_t sail_read_image(const char* path, char** buffer, plugins_list* /*Опционально: список или NULL*/);Возвращает количество прочитанных байт, если 0 - ошибка, текст/код которой которой можно узнать вызвав условный sail_last_error();
На запись:
size_t sail_write_image(const char* path, const char* buffer, size_t buf_size, const sail_write_options* opt, plugins_list* /*Опционально: список или NULL*/);Возвращает количество записанных байт в сжатом виде, если 0 - ошибка, текст/код которой которой можно узнать вызвав тот же sail_last_error();
И хотелось бы получить внятный контроль над аллокациями внутри библиотеки. Все. Это мои хотелки, пожелания, но пусть автор сам решает что он хочет от своего проекта.
> Для каждой библятеки заводи отдельый cpp-файл...
Спасибо, конечно, за ценный совет, а то я не знал как организовывать свои проекты (НЕТ!). Откуда такая мания давать советы, когда не просят на ровном месте.
Я согласен со всем. То что можно сделать быстро, так это- опциональный context для функций sail_read/sail_write. Эта идея уже витала, вы только её озвучили. Контекст хранит метаинформацию о плагинах, это верно! Нужен он например для получения списка поддерживаемых файловых расширений, например, чтобы сделать фильтр в диалоге выбора файлов
- функции sail_read_mem/sail_write_mem для уровня "Новичок"
- объединение sail_image и пиксельных данных - более чем очевидно что это нужноТо что сделать пока не знаю как:
- свой аллокатор - тоже очевидно что рано или поздно всплывёт опять
Что касается техники обработки ошибок, то я работал наверное с десятком из них. Такие TRY() макросы мне нравятся потому что:
- весь SAIL код, который может вернуть ошибку, выглядит унифицировано. Иначе разные функции начнут возвращать что попало как индикатор ошибки. Кто-то 0, кто-то NULL, и т.д. кто в лес, кто по дрова
- SAIL заботится об очистке памяти внутри себя при возникновении ошибки, опять же унифицировано. Макрос для этого просто называется по-другому, но код опять же выглядит унифицировано, хоть и слегка избыточно
- Макросы можно как хочешь тюнинговать. Например, чтобы проводить локальное деструктивное тестирование сделав так, чтобы макрос возвращал рандомные ошибки. Или печатать полотна бэктрейсов
- Клиентскому коду РЕКОМЕНДОВАНО использовать TRY() макросы, но вы же можете их и не использовать. Обрабатывайте результаты вызовов сами. 0 - успех, или код ошибки. Всё предельно просто.
> - свой аллокатор - тоже очевидно что рано или поздно всплывёт опятьИменно свой аллокатор? А не возможность дать юзеру оверрайднуть на свой, типа как в https://github.com/Dridi/cashpack/blob/master/lib/hpack.c сделано? В идеале иногда еще хочется либу совсем без динамической аллокации, но это специфичная хотелка и не для такой либы походу.
Да, это и имел ввиду. Свой аллокатор с точки зрения пользователя библиотеки.
> Да, это и имел ввиду. Свой аллокатор с точки зрения пользователя библиотеки.Ну вон там выше пример, прямо в том файле.
Покажи пожалуйста если есть пример как ты используешь собственный аллокатор совместно с какой-то либоц. Можно в псевдокоде
Эх… Мне откровенно лень делать полноценные примеры.Просто скажу, как могло бы быть на мой взгляд.
Для С:Некий внутренний макрос к alloc/free/realloc (https://github.com/nothings/stb/blob/b42009b3b9d4ca35bc703f5...)
Структура со стабами для пользовательских alloc/free/realloc. Судя по примерам, есть что-то подобное для seek/tell/flush/sync и т.д.
У себя я использую что-то вроде:
#define PUSH_TYPE(mem_arena, type, ...) (type *)push_mem__(mem_arena, sizeof(type), ## __VA_ARGS__)#define PUSH_ARRAY(mem_arena, size, type, ...) (type *) push_mem__(mem_arena, (size)*sizeof(type), ## __VA_ARGS__)
И т.д.Для C++ мне нравится подход eastl (https://github.com/electronicarts/EASTL).
С С++ конечно возникает проблема, т.к. почти все объекты вызывают С функции. То есть аллокаторов нужно указывать два - для аллокаций, которые делают С++ объекты сами внутри себя, и для сишных функций, которые этими объектами дёргаются.Да-с, ничего путного в голову не приходит чтобы решить эту проблему. Идеи? 😀
Большинство известных мне реализаций new в С++ вызывают внутри себя malloc (GCC/Clang/MSVC). В случае MSVC malloc вызывает HeapAlloc или VirtualAlloc из kernel32. Чтобы избавиться от вызова «стандартного» malloc я компиляю (вернее линкую, но не суть) с nodefaultlib/nostdlib/nolibc и делаю свою реализацю malloc/free, как правило из заранее выделенного буфера на старте программы. Это имеет свои недостатки, например приходится самому изобретать termination handler при вызове pure virtual функции-члена или изобретать каст из float/double в int (зачем-то подобные вещи впихнуты в crt и чтобы от него избавиться приходится изобретать велосипеды, хотя самописный каст из float в int работает бысрее).eastl внутри себя вызывает «собственную» реализацию глобального оператора new [], т.е. ты условно всегда должен определить при использовании что-то подобное:
void* operator new[](size_t size, const char* name, int flags, unsigned debug_flags, const char* file, int line)
{
return ::operator new[](size);
}void* operator new[](size_t size, size_t alignment, size_t alignment_offset, const char* name, int flags, unsigned debug_flags, const char* file, int line)
{
return ::operator new[](size);
}Т.е. если ты внутри своей библиотеки используешь new, ты можешь пользоваться своей реализацией оператора, и поставлять что-то подобное при компиляции по «умолчанию» при соответствующем флаге в CMake. Если пользователь захочет заменить, флаг ему в руки, пусть только переопределит твой глобальный new. Если ты не используешь нигде new, то черт с ним, макросов/стабов для alloc/free вполне хватит.
> g_pszImagePixels ... уже пахнет плюсамиЭто... (g_)Global (p)Pointer to (s)String with (z)Zero terminator ImagePixels? Это пахнет венгерской нотацией, win api и кокой-то дичью...
Jpeg, png (windows-only). Не вкатился что-то. Сегодня нужны webp, heif, и немного png -- жопегом никого не удивить. Тем более в играх жопеги совершенно не упали.>KSquirrel
Выглядит как рипоф faststone image viewer. Тот немного специфичный. Он на паскале, быстрый и удобный, не пестрит багами. Жаль только не поддерживает современные форматы. Но сегодня у нас есть относительно приличный gwenview (код не очень хороший, правда), и нужды в таких стрёмных просмотрщиках нет. Алсо, gwenview что-то тормозноват, если сравнивать с тем же fsiv. Но это видимо претензия тоже к кутям, как и ограниченное число поддерживаемых форматов (libraw и ещё что-то там конечно вкорячены сбоку, грязно, но остальное от кутей зависит).
>Сегодня нужны webp, heif, и немного png -- жопегом никого не удивить. Тем более в играх жопеги совершенно не упали.на всё нужно время, всё есть в планах. HEIF насколько я помню покрывается патентами, и его использование без роялти невозможно.
Но отсутствие tga совершенно непростительно, это основной универсальный формат. И при этом простой (в отличие от tiff и производных). Heif емнип открытый формат, это пакуемые в него данные могут быть продуктом "платного" кодека. А могут быть и роялти фри (нет такой вещи как непокрытые патентами кодеки: есть современные, есть устаревшие, и есть бесплатные для использования на определённых основаниях).
>Но отсутствие tga совершенно непростительноСогласен полностью. Последние 4 месяца я был занят больше архитектурой. После стабилизации API, которое я думаю уже близиться, я буду заниматься исключительно кодеками.
>Жаль только не поддерживает современные форматыИменно современные форматы и стоят в приоритете. WEBP, AVIF, JPEG-XR, возможно BGP и FLIF.
Хочу чтобы оно могло BMP.
Без вопросов, все популярные форматы будут сделаны. Tiff, bmp, gif, tga и т.п.
spr, wad :)
Wad это вообще контейнер, а не формат.
Наверное dds кроме шуток обязательно должен быть, а если ориентироваться на мультиплатформу, то и мобильные варианты. Но это всё немного вторично. А вот jpg only это проблема. Если мне нужна сеть, я беру curl и openssl. Если мне нужны картиночки, я беру костыли либо подгоняю требования под результат. Всё-таки удобный универсальный интерфейс взаимодействия с графическими файлами должен существовать, а его нет.
> Всё-таки удобный универсальный интерфейс взаимодействия с графическими
> файлами должен существовать, а его нет.В libsdl слегка есть, но... но дальше BMP оно на любителя.
Поделка-самоделка. Как будто мало развитых и проверенных временем библиотек такого толка.
Строго говоря, возраст SAIL - 17 лет. Просто она переживает ребрендинг.
Так в том то и проблема, что развитых. Везде добавлены рисование, обработка, шрифты и прочие лишние зависимости, а я хочу просто ввод/вывод.
кто то действительно использует сабж (вместо тех же указанных "прямых конкурентов"), или автор новости == автор проекта?
автор
Кому надо просто грузить картинки для OpenGL - есть великолепная libSOIL.
Заходим в "src/sail-plugins/src/jpeg/jpeg.c"
Видим: #include <jpeglib.h>Заходим в "src/sail-plugins/src/png/png.c"
Видим: #include <png.h>> Простая, компактная и быстрая библиотека, написанная на С без сторонних зависимостей (кроме кодеков);
Вот это уточнение "кроме кодеков" - полностью ломает всю якобы "независимость", кому она нужна без кодеков?
Как насчёт независимости приложения от вот таких "библиотек", не лучше ли читать изображения напрямую через libjpeg и libpng?
Это функция что влезет в один экран, примеры легко гуглятся.А кому нужно много возможностей - можно использовать OpenCV.
Можно использовать libjpeg и напрямую, если нужно грузить исключительно жипеги.Давай посмотрим с другой стороны. Размер клиентской библиотеки sail под windows - порядка 150 Kb. Плюс 500 Kb на один кодек jpeg, остальные можно просто удалить.
Получаем оверхед в 150 Kb размера, и микроскопический api из пяти строк конкретно для этой задачи.
Неплохо, я считаю. Какие есть мысли?
Какие мысли? Я считаю что плохо. Библиотека libjpeg-6b занимает 150кб. А только для чтения будет еще меньше. Сам когда-то уместил в 10кб бинарного кода, выбросив лишний функционал (и то даже поддержку прогрессивных JPEG оставил).
Для чтения PNG же есть lodepng и libspng без зависимостей от zlib, но тут именно libpng, что будет толще.
Здесь важно соблюсти баланс. Sail - библиотека общего назначения, но стремящаяся к минимализму. Можно конечно использовать libspng, но тут пострадает скорость в угоду размеру как мне кажется. Zlib, например, можно скомпилировать с amd64 инструкциями, что даст прирост скорости декодирования.
> можно скомпилировать с amd64 инструкциями, что даст прирост скорости декодирования.Или не даст. Если алгоритм правильный, как с LZ4, то там никаких специальных инструкций даром не надо, оно в память упирается. И для zlib, кстати, есть здорово ускоренная реализация. На zlib просто все подзабили - он работает и ладно. Да и смысл его улучшать? Кто хотел именно улучшений - накодили zstd, он жмет лучше и декодируется быстрее, и это на уровне алгоритмов сразу :D
Годно, пусть будет.
> Прямые конкуренты из этой же областиИнтересно почему ImageMagick (MagickCore, MagickWand и Magick++) не попала в список?
Потому что она тормозная и глючная блотварь с кривым API?
Нет, скорее потому, что im не отдельная либа, а "вещь в себе". А по поводу кривого апи… В любом случае, другого софта, подобного im, нет. Наверное, ни одна программа, кроме этой, не сможет тебе даже корректно ресайзнуть изображение. Там надо ресайзить через колорспейс luv (да, я сравнивал с lab, luv много корректней), чтобы не запороть файл. Особенно бросается в глаза, когда ты ресайзишь 600dpi в ~90dpi. Ну и потом, distort resize тоже выглядит значительно лучше топорного в лоб ресайза. Насчёт глюков не скажу, насчёт тормозов, я бы хотел чтобы cuda или opencl что-нибудь ускоряли там, но они ничего не ускоряют и только добавляют артефактов. Так что уж как есть, альтернатив просто не существует в природе (да, я в курсе про форки, они ни в какое сравнение не идут).
> APNG (чтение, только на WindowsКак они этого добились? Чтение apng на других платформах чем-то принципиально отличается? Wtf?!
Чтение Animated PNG требует патченой версии libpng. Это ловушка этого формата. Официальная libpng не может поддерживать APNG, т.к. APNG - это расширение, а libpng - reference PNG implementation. Поэтому поддержка APNG делается только через распространение своей собственной патченой libpng. Распространение своей собственной libpng выглядит натурально только на Windows.
Может тогда послать libpng курить бамбук? Достаточно дурацкая либа. Насколько я вижу, половина прог для работы с apng вообще libpng не пользуются. Не мешает им работать с форматом...
Это всё замечательно, но у меня в системе libpng с поддержкой apng (как и во многих дистрибутивах, я думаю), а анимации работают только в браузере. Браузер использует всё ту же системную libpng с apng, это значит, проблема исключительно в криво написанном софте,
>это значит, проблема исключительно в криво написанном софте,совершенно верно.
Есть такая штука как libvips
>It has around 300 operations covering arithmetic, histograms, convolution, morphological operations, frequency filtering, colour, resampling, statistics and othersЭЭ?
Неоценимой помощью проекту будет звёздочка (star) на Github. Спасибо за отзывы и предложения, друзья.