← All posts tagged графика

Закончил обрабатывать сканы: #2891873 То, что я загружал, — это Generic raw book zip

Практически все страницы повёрнуты и спозиционированы автоматически в МатКАДе, кроме трёх в начале и одной в конце, где нет нумерации, по которой как по самому выступающему элементу можно позиционировать страницу. Позиционирование заключалось в том, чтобы найти, где на повёрнутом скане полезная часть страницы, откадрировать скан и обратно добавить поля абсолютно белого цвета, чтоб без теней или неправильного кадрирования, которое сделал тот, кто сканировал.

Линейкой мерил отступы на реальной книге и добивался, чтоб в обработанных сканах были примерно такие же расстояния. Вообще ширина книги 190мм, но если взять 180мм, то левые и правые страницы, расположенные друг по другом, получается, будут иметь отступы в одних и тех же местах. Так что сделал 180мм. Обложку пришлось немного аффинно сжать, ведь она-то напечатана на все честные 190мм. Но в остальном удалось воспроизвести достаточно достоверно. Правда, вот смотрю я PDF и вижу, что он считается 90мм в ширину, хотя я в PNG проставлял 300dpi pnmtopng'ом при конвертации из BMP от МатКАДа. То есть, Интернет Архив в любом случае ждёт 600 dpi.

Ещё заметил, что конвертация из чисел с плавающей точкой в 0…255 делается не всегда верно. Если брать Floor (X 255.0), то, чтобы получить 255, Х должен быть строго 1.0, а 0.999 — это уже 254. Если брать Round (X 255.0), то, чтобы получить 255, X должен быть в интервале от 509/510 до 510/510 в то время как, чтобы получить 254, X может быть во вдвое более широком интервале от 507/510 до 509/510. Чтобы сделать честную конвертацию, надо взять Min (255, Floor (X * 256.0)). Но так мало, кто делает.

Вообще говоря, остаются нечестно поделённые инфинитезимали. Они, конечно, инфинитезимали, но получить их вручную как коэффициент в формуле проще простого.

Для них можно написать такое:
if X <= 0.5 then
return Floor (X * 256.0);
else
return Ceiling (X * 256.0) — 1;
end if;

3/4, например. Для честности ему бы следовало быть 191, а не 192. Только 1/2 нельзя сконвертировать честно.

Неправильная и правильная обработка изображений
До вчерашнего дня не знал, что RGB, который на мониторе, в CSS веба и вообще везде — официально нелинейный. Думал, что подстройка гаммы — это не более, чем настройка на мониторе. Но нет, у стандартного RGB (sRGB) приблизительно степенной закон 2.2. И половина между 0 и 255 — это 187. Так что без конвертации в/из линейный RGB ничего почти нельзя корректно сделать. Даже в градации серого нельзя корректно свести. И нас таких, не в курсе про нелинейность, похоже, очень много.

Альфа-канал такой конвертации не подлежит, во всяком случае, в PNG. Но тогда стандартных 8 бит не хватит по разрядности, чтобы иметь возможность получать при наложении полупрозрачного белого на чёрный или наоборот все оттенки серого в sRGB. По крайней мере, для альфа-канала высокая разрядность — это не блажь, а необходимость.

И, как показывают тесты, правильно наложение в софте мало, где сделано. Вот в браузере если наложить чёрный с варьирующимся альфа-каналом поверх белого фона, результат будет неправильный. Всё (почти), что было мне привычно, оказывается, работает неправильно. Технически наиболее подходящее решение проблемы — это scRGB, у которого есть представление в виде линейных 16-битных чисел.

По сравнению с sRGB, диапазон расширен в восемь раз, от -0,5sRGB до 7,5sRGB, что позволяет представить в этом формате весь диапазон доступных восприятию цветов типа суперзелёного. И, начиная с Windows Seven, эти цвета по HDMI с соотвествующими HDMI мониторами и видеокартами можно даже отобразить на оверлее или на полном экране средствами DirectX.

Поворачиваю в МатКАДе сканы страниц оптимальным способом. Оптимальность определил так: если взять горизонтальные линии и наклонить под выбранным углом, а потом усреднить пикселы на каждой линии, то такие усреднения вдоль вертикального направления должны образовать картину, как можно более похожую на прямоугольный импульс. Похожесть на прямоугольный импульс определяется как сумма квадратов разности усреднённых значений на соседних линиях. Чтоб из-за разного кадрирования не возникали добавки, на всех углах берутся только такие линии, которые проходят через общий для всех вертикальный отрезок, расположенный посередине скана и отстоящий от верхнего и нижнего краёв так, чтобы в заданном диапазоне углов через него всегда можно было провести семейство наклонных линий, не выходящих за край. Поворот линий, вообще говоря, не используется, а вместо него аффинный сдвиг. Искать максимум начинаю с 0° и ±0,6°, потом рядом с максимальным из них проверяю ±0,25°, потом ±0,1°, потом ±0,5°. Дельты углов подобраны так, чтобы быть чуть внахлёст, больше, чем треть от предъидущего, но меньше половины, кроме последнего, который строго половина. Максимальный угол по модулю, таким образом, 1°, но такого реально не было, попадался максимум 0,8°. Результаты удивительно хорошо совпадают с тем, что можно циркулем намерить в ГИМПе.

Обнаружил, что в GIMP, если увеличить изображение сильно, под 64x, когда водишь по одному и тому же пикселу мышкой, координаты в статусе меняются. Они там координаты ближайшей границы между пикселами показывают. А я понавыписывал, и поди пойми теперь, в левой или правой половине пиксела был курсор, когда я записывал. Эх, теперь полсотни картинок ещё раз промерить надо перед тем, как забить обрабатываться в МатКАД.

На протяжении где-то полугода вынашиваю идею сделать логотип с шестернями. Одна поменьше справа вокруг двух последних букв, а кадрированный контур второй служит вместо подчёркивания на логотипе. Ставят на логотипы черты под буквы: прямые, чуть наискосок, дугой. Вот вторая шестерня должна служить как раз такой дугой под буквами. Всё осложняется тем, что если шестерни на логотипе не могут вертеться (если изготовить их как реальный объект), это будет провал. Поэтому надо как-то попытаться сделать профиль зуба по правилам. И поэтому логотип так и не сделал.

Нашёл сегодня онлайн дизайнер и поэтому поводу даже сделал по-быстрому там шестерни. Но выгрузка только в DXF. А для веба-то нужен SVG. Думал снять SVG с окна предпросмотра, а там не SVG, а canvas, который можно сохранить только как PNG. Если открывать DXF в InkScape, там зияющая пустота. В редакторе XML видны контуры, но все пустые. LibreOffice Draw сказал, что такой формат не понимает, хотя там тупо текстом координаты заданы. Если пересохранить в NanoCAD, то LOD открывает DXF, но там один прозрачный прямоугольный объект. Если ему проставить заливку, получается цветной прямоугольник. Никаких форм. Пробовал перекинуть через буфер обмена вектор. Выделил всё в NanoCAD, скопировал, вставил в новый документ в InkScape. Вставился прямоугольник с растром. Никакого экспорта в SVG в NanoCAD не нашёл. Пробовал печатать в PDFCreator из NanoCAD. Потом можно PDF открыть в InkScape и пересохранить в SVG.

Попробовал. Во-первых, что не понравилось, линии даже нулевой толщины приобретают толщину после печати. С обводкой такая проблема, что ширина линии, распирающая контур шестерни в обе стороны, меняет контур так, что шестерни не смогут вращаться. Надо, чтоб толщина шла только внутрь, а это значит заливка без обводки. Во-вторых, заливка делается кучей мелких треугольников. В-третьих, хорошо, конечно, что широкие линии не стали залитыми прямоугольными контурами, а именно широкими линиями, но каждая из тысяч линий — сама по себе. И я не могу понять, как их автоматом соединить концами с совпадающими координатами, чтоб убрать толщину и поставить заливку. В-четвёртых, при увеличении, хоть линий и было много, но смотрится уродливо. Надо бы дуги и сплайны.

Вот уж не думал, что между двумя векторными форматами лежит такая пропасть. Пока что мысли на эту тему такие:

1. Дорисовывать в CAD. В частности, для контура большой шестерни я сделал операцию «Подобие», чтобы придать толщину исключительно вовнутрь. А потом сохранить в DXF и самому написать нормальную программу, которая преобразует в SVG как надо.
2. Обрисовать в импортированном PDF профиль каждого зуба сплайнами, размножить и заменить.