Java -> iText -> Верстка (n-Up) -> Пример
Я хотел бы предложить карту Starbucks тому, кто сможет помочь мне полностью понять этот код. Это важно для меня. Спасибо за ваше время!
Я начал читать замечательную книгу мистера Лоуги (iText in Action, второе издание). Это действительно хорошо написано и информативно. Из-за высокого давления со стороны моего работодателя я вынужден перейти к главе 6. Понимание примера кода n-Up для меня сейчас очень важно, и, будучи новым программистом, я постараюсь прокомментировать приведенный ниже код с моим вопросы.
Если бы вы могли, когда можете, уделите немного времени и помогите мне пройти через это, взглянув на мои вопросы ниже, это было бы здорово. Я ценю все полезные комментарии.
public void manipulatePdf(String src, String dest, int pow)
Q: Здесь переменная 'pow' указывает, например, на то, что при пау 3, результирующий n-up будет (2x2x2) 8. Полученный PDF-файл будет иметь 8 копий PDF-файла 'src'. Это правильно?
A:
throws IOException, DocumentException
{
PdfReader reader = new PdfReader(src);
Rectangle pageSize = reader.getPageSize(1);
Rectangle newSize = (pow % 2) == 0 ?
new Rectangle( pageSize.getWidth(), pageSize.getHeight()) : new Rectangle( pageSize.getHeight(), pageSize.getWidth());
Q: Выше я не уверен, что происходит. Мне кажется, что если остаток операции модуля равен нулю, то новый прямоугольник будет создан в книжной ориентации и наоборот. Это правильно? Если так, могу я спросить почему?
A:
Rectangle unitSize = new Rectangle(pageSize.getWidth(), pageSize.getHeight());
for (int i = 0; i < pow; i++)
{
unitSize = new Rectangle(
unitSize.getHeight() / 2, unitSize.getWidth());
}
Вопрос: Выше, в цикле "for", мы, я полагаю, готовим размер блока для каждого из PDF-файлов, которые будут помещены на конечную PDF-поверхность. Я не понимаю, почему getWidth() также не делится на 2?
A:
int n = (int)Math.pow(2, pow);
int r = (int)Math.pow(2, pow / 2);
int c = n / r;
Q: 'n' - это число pdfPages, которые будут перенесены на окончательную поверхность pdf. Пока все хорошо, правда?
'r' может быть числом строк, а 'c' количеством столбцов?
So, assuming a 'pow' of 3..
n = 8 which means 8 up of the pdf when you'll open up the final pdf?
r = 2 which means there'll be be two rows.
c = 4 which means there'll be four columns.
A:
Document document = new Document(newSize, 0, 0, 0, 0);
PdfWriter writer = PdfWriter.getInstance(document,
new FileOutputStream(String.format(dest, n)));
document.open();
PdfContentByte cb = writer.getDirectContent();
PdfImportedPage page;
Rectangle currentSize;
float offsetX, offsetY, factor;
int total = reader.getNumberOfPages();
for (int i = 0; i < total; )
{
if (i % n == 0)
{
document.newPage();
}
В: Вышеприведенный цикл 'for' добавляет новую страницу к окончательному pdf-файлу каждый раз, когда на текущей рабочей странице достигается заранее определенный номер nup. Так что, если у нас n = 8, то новая страница будет вызываться при i = 8, 16, 24 и т. Д. Верно?
A:
currentSize = reader.getPageSize(++i);
Q: Эта строка учитывает ситуации, когда исходный pdf имеет много страниц, и не все страницы имеют одинаковый размер страницы pdf. Правильный?
A:
factor = Math.min(unitSize.getWidth() / currentSize.getWidth(),
unitSize.getHeight() / currentSize.getHeight());
Q: Функция min возвращает наименьшее число. Почему unitSize делится на currentSize? Это где мое понимание нарушается.
A:
offsetX = unitSize.getWidth() * ((i % n) % c)
+(unitSize.getWidth()
- (currentSize.getWidth() * factor))/2f;
Q: Хорошо, offsetX и offsetY используются для позиционирования страницы PDF на большую конечную поверхность PDF. Это я понимаю. Может ли кто-нибудь объяснить расчет не программисту на английском языке? Это тот случай, когда нужно знать, что делает каждая математическая операция, но не понимать общую картину.
A:
offsetY = newSize.getHeight()
- (unitSize.getHeight() * (((i % n) / c) + 1))
+ (unitSize.getHeight()
- (currentSize.getHeight() * factor))/2f;
page = writer.getImportedPage(reader, i);
cb.addTemplate(page,factor, 0, 0, factor, offsetX, offsetY);
}
document.close();
}
Я надеюсь, что этот вопрос может помочь многим другим, новичкам в iText, и, возможно, потребуется подробное пошаговое описание кода для этого кода.
Я также надеюсь, что негативные и в целом бесполезные комментарии не будут опубликованы.
Спасибо всем за потраченное время и помощь!
1 ответ
Предположим, что у вас есть документ с 67 страницами.
Если вы хотите сделать этот документ 2-кратным, у вас будет 34 страницы: 33 страницы с 2 страницами исходного документа + 1 страница, заполненная наполовину. Чтобы разместить две страницы на одной рядом друг с другом, необходимо уменьшить исходные страницы до половины их размера и повернуть исходный размер страницы на 90 градусов.
Если вы хотите добавить этот документ в 4 раза, вы получите 17 страниц: 16 страниц с 4 страницами исходного документа + 1 страница, заполненная на три четверти. Чтобы разместить четыре страницы на одной рядом друг с другом, вам нужно уменьшить исходные страницы до четверти их размера, и вам не нужно поворачивать исходный размер страницы.
Если вы хотите увеличить этот документ до 8, вы получите 9 страниц: 8 страниц с 8 страницами оригинального документа + 1 страница, заполненная только на 3 / 8. Для размещения восьми страниц на одной странице рядом с каждой В противном случае вам нужно уменьшить исходные страницы до 1/8 их размера, а вам нужно повернуть исходный размер страницы на 90 градусов.
Если вы хотите увеличить этот документ до 16, вы получите 5 страниц: 4 страницы с 16 страницами исходного документа + 1 страница, заполненная только для 3 / 16. Для размещения 16 страниц на одной странице рядом с каждой В противном случае вам нужно уменьшить исходные страницы до 1/16 их размера, и вам не нужно поворачивать исходный размер страницы.
Если вы хотите увеличить размер этого документа до 32, вы получите 3 страницы: 2 страницы с 32 страницами оригинального документа + 1 страница, заполненная только на 3 / 32. Для размещения 32 страниц на одной странице рядом с каждой В противном случае вам нужно уменьшить исходные страницы до 1/32 их размера, а вам нужно повернуть исходный размер страницы на 90 градусов.
Если вы хотите увеличить объем этого документа до 64, вы получите 2 страницы: 1 страница с 64 страницами исходного документа + 1 страница, заполненная только на 3 / 64. Для размещения 64 страниц на одной странице рядом с каждой В противном случае вам нужно уменьшить исходные страницы до 1/64 их размера, и вам не нужно поворачивать исходный размер страницы.
2 = 2 (pow 1) => повернуть страницу
4 = 2 x 2 (pow 2) => не поворачивать страницу
8 = 2 x 2 x 2 (pow 3) => повернуть страницу
16 = 2 x 2 x 2 x 2 (pow 4) => не поворачивать страницу
32 = 2 x 2 x 2 x 2 x 2 (pow 5) => повернуть страницу
64 = 2 x 2 x 2 x 2 x 2 x 2 (pow 6) => не поворачивать страницу
Вы видите образец? Когда пау нечетное число, нужно повернуть страницу; когда это четное число, страницу не нужно поворачивать. Вот почему вам нужно проверить (pow % 2) == 0
, Определяет ориентацию новой страницы.
Цикл также легко понять, особенно если вы посмотрите на это изображение:
Большая страница A0 может быть разделена на две страницы A1. Высота этой страницы A1 равна ширине страницы A0; ширина страницы А1 равна половине высоты страницы А0. А1 можно разделить на две страницы А2. Высота этой страницы А2 равна ширине страницы А1; ширина страницы А2 равна половине высоты страницы А1. И так далее.
Вы были правы насчет n
количество страниц, которые мы попытаемся разместить на одной странице, r
будучи числом строк и c
быть количество столбцов и о том, что следует.
Теперь нам нужно определить factor
, Вы уже знаете, что width
а также height
переключаются пару раз. Например: при 2-кратном увеличении документа на страницах формата А4 исходный размер страницы составляет 210 на 297, и его необходимо изменить на unitSize
148 на 210. Другими словами, он должен быть уменьшен с коэффициентом 148 / 210 (0,705) или 210 / 297 (0,707). В этом случае мы используем коэффициент 0,705.
Мы могли бы рассчитать смещения следующим образом:
offsetX = unitSize.getWidth() * ((i % n) % c);
offsetY = newSize.getHeight() - (unitSize.getHeight() * (((i % n) / c);
В случае, если вы хотите восьмерка документа, c
равно 4. Итак, у вас есть:
(0 % 8) % 4 = 0 % 4 = 0; (0 % 8) / 4 = 0 / 4 = 0;
(1 % 8) % 4 = 1 % 4 = 1; (1 % 8) / 4 = 1 / 4 = 0;
(2 % 8) % 4 = 2 % 4 = 2; (2 % 8) / 4 = 2 / 4 = 0;
(3 % 8) % 4 = 3 % 4 = 3; (3 % 8) / 4 = 3 / 4 = 0;
(4 % 8) % 4 = 4 % 4 = 0; (4 % 8) / 4 = 4 / 4 = 1;
(5 % 8) % 4 = 5 % 4 = 1; (5 % 8) / 4 = 5 / 4 = 1;
(6 % 8) % 4 = 6 % 4 = 2; (6 % 8) / 4 = 6 / 4 = 1;
(7 % 8) % 4 = 7 % 4 = 3; (7 % 8) / 4 = 7 / 4 = 1;
(8 % 8) % 4 = 0 % 4 = 0; (8 % 8) / 4 = 0 / 4 = 0;
(9 % 8) % 4 = 1 % 4 = 1; (9 % 8) / 4 = 1 / 4 = 0;
Вы видите образец? Мы добавляем страницы в сетку, которая выглядит следующим образом: (0, 0), (1, 0), (2, 0), (3, 0), (0, 1), (1, 1), (2, 1), (3, 1). Чтобы получить реальные размеры, мы умножаем на unitSize.getWidth()
а также unitSize.getHeight()
, Очевидно, нам нужно
offsetY = newSize.getHeight() - (unitSize.getHeight() * (((i % n) / c);
из-за природы системы координат: начало системы координат находится в нижнем левом углу.
Мы корректируем offsetX
а также offsetY
с половиной разницы фактической ширины страницы вниз по размеру и доступного пространства для центрирования импортированной страницы.
Вы говорите, что не хотите никаких негативных замечаний. Позвольте мне сделать одно замечание: ваш вопрос не является вопросом iText и не является вопросом программирования. Это математический вопрос. Вам действительно нужно изучать математику, прежде чем пытаться программировать, точно так же, как ребенку нужно научиться ходить, прежде чем он научится бегать.
Одной из возможных причин путаницы может быть то, что вы не учитываете одну особенность ISO 216. Алгоритм не будет работать на нестандартных страницах. Например: если ваша страница квадратная, вы не можете разделить высоту на две части и сохранить ширину. Но это очевидно, не так ли?