Это восходит к ранним разработкам ЦП. Самый быстрый способ прорезать биты растрового изображения - это читать их по 32 бита за раз, начиная с начала строки сканирования. Это работает лучше всего, когда первый байт строки сканирования выровнен по границе 32-битного адреса. Другими словами, адрес, кратный 4. На ранних процессорах наличие первого байта, выровненного неправильно, стоило бы дополнительных циклов ЦП, чтобы прочитать два 32-разрядных слова из ОЗУ и перемешать байты для создания 32-разрядного значения. Обеспечение того, чтобы каждая строка сканирования начиналась с выровненного адреса (автоматически, если шаг кратен 4), позволяет избежать этого.
На современных процессорах это больше не беспокоит, теперь выравнивание по границе строки кэша гораздо важнее. Тем не менее, требование по кратности 4 для шага по компромиссу не изменилось.
Кстати, вы можете легко рассчитать шаг по формату и ширине с помощью этого:
int bitsPerPixel = ((int)format & 0xff00) >> 8;
int bytesPerPixel = (bitsPerPixel + 7) / 8;
int stride = 4 * ((width * bytesPerPixel + 3) / 4);
Я думаю, что лучше всего использовать стороннюю библиотеку PDF. Например, собственный SDK PDF-библиотеки Adobe или другой менее известный поставщик.
Существует библиотека с открытым исходным кодом на основе webkit: WKHTMLTOPDF
Он генерирует PDF из шаблона HTML.
А вот небольшой учебник о том, как мы используем его с серверной частью Erlang.