Представете си документ от 3000 KB с десет страници и следните обекти:
- четири поднабора шрифтове, използвани на всяка страница, всеки около 50 KB
- десет изображения, които фигурират на една страница, всяко около 200 KB (едно изображение на страница)
- четири изображения, които фигурират на всяка страница, всяко около 50 KB
- десет страници с потоци от съдържание от около 25 KB всяка
- около 350 KB за обекти като каталога, информационния речник, дървото на страниците, таблицата за кръстосани препратки и т.н.
Една страница ще се нуждае от поне: - четирите поднабора шрифтове: 4 пъти по 50 KB - единичното изображение: 1 път 200 KB - четирите изображения: 4 пъти 50 KB - единичен поток от съдържание: 1 път 50 KB - леко намален таблица с препратки, леко намалено дърво на страниците, почти идентичен каталог, информационен речник с идентичен размер,... 200 KB
Заедно това е 850 KB. Това означава, че в крайна сметка получавате 8500 KB (10 пъти по 850 KB), ако разделите PDF документ от 10 страници от 3000 KB на 10 отделни страници.
Този пример е резултат от предположения (въз основа на опит) и предполага, че PDF файлът е предвидим. Повечето PDF файлове не са:
- някои страници ще изискват изображения с висока разделителна способност (може би дори мегабайта), други страници няма да имат изображения,
- някои страници ще се нуждаят от много различни шрифтове и подмножества шрифтове (много килобайтове), други страници ще се състоят само от някои векторни рисунки (малък поток от съдържание, ако е компресиран).
- различни страници могат да споделят голямо количество ресурси (XObjects на Form, XObjects на изображения,...), други страници няма да споделят никакви ресурси.
- и така нататък...
Вие сами сте забелязали това, докато пишете: Мога да разделя този документ на страници. Но това също не е добро решение, тъй като размерът на страницата също не е равномерно разпределен между страниците.
Точно затова вашият въпрос не може да има друг отговор освен: ще трябва да направите проба и грешка. Никой софтуер не може да предвиди колко място е необходимо на дадена страница, преди да погледнете какво е необходимо за нея страница.
Актуализация:
Както Дейвид посочва в коментарите, възможно е да се изчислят всички ресурси, необходими за една страница, и да се провери дали текущите ресурси плюс необходимите ресурси надвишават максималния размер на файла.
Написах малък пример:
public void manipulatePdf(String src, String dest)
throws IOException, DocumentException {
Document document = new Document();
PdfCopy copy = new PdfSmartCopy(document, new FileOutputStream(dest));
document.open();
PdfReader reader = new PdfReader(src);
for (int i = 1; i <= reader.getNumberOfPages(); i++) {
// check resources needed for reader.getPageN(i);
copy.addPage(copy.getImportedPage(reader, i));
System.out.println("After adding page: " + copy.getOs().getCounter());
}
document.close();
System.out.println("After closing document: " + copy.getOs().getCounter());
reader.close();
}
Изпълних примера на PDF пример с 18 страници и това беше резултатът:
After adding page: 56165
After adding page: 111398
After adding page: 162691
After adding page: 210035
After adding page: 253419
After adding page: 273429
After adding page: 330696
After adding page: 351564
After adding page: 400351
After adding page: 456545
After adding page: 495321
After adding page: 523640
After adding page: 576468
After adding page: 633525
After adding page: 751504
After adding page: 907490
After adding page: 957164
After adding page: 999140
After closing document: 1002509
Виждате как размерът на файла на копието постепенно нараства с всяка добавена страница. След като всички страници са добавени, размерът е 999140 байта и след това дървото на страницата и потокът от кръстосани препратки се записват, като се добавят още 3369 байта.
Там, където пише // check resources needed for reader.getPageN(i);
, можете да направите предположение за размера, който ще бъде добавен за страницата, и да излезете от цикъла, ако надвиши максималната стойност.
Защо това би било предположение:
- Може да броите обекти, които вече са добавени. Ако следите обектите (не е толкова трудно), вашето предположение ще бъде по-точно.
- Използвам
PdfSmartCopy
. Да предположим, че във вашия PDF има два еднакви обекта. Лошият PDF софтуер често причинява подобни проблеми. Например: едни и същи байтове на изображението се добавят два пъти към файла. PdfSmartCopy
може да открие това и ще използва повторно първия обект, който срещне, вместо да добавя излишните байтове на допълнителния обект.
В момента нямаме reader.getTotalPageBytes()
в PdfReader
, защото PdfReader
се опитва да използва възможно най-малко памет. Той няма да зареди никакви обекти в паметта, докато тези обекти не са необходими. Следователно той не знае размера на всеки обект, преди страницата да бъде импортирана.
Въпреки това ще се погрижа такъв метод да бъде добавен в следващото издание.
Актуализация:
В следващата версия ще намерите инструмент с име SmartPdfSplitter
, който зависи от нов клас с име PdfResourceCounter
. Можете да го използвате по следния начин:
PdfReader reader = new PdfReader(src);
SmartPdfSplitter splitter = new SmartPdfSplitter(reader);
int part = 1;
while (splitter.hasMorePages()) {
splitter.split(new FileOutputStream("results/merge/part_" + part + ".pdf"), 200000);
part++;
}
reader.close();
Обърнете внимание, че това може да доведе до PDF от една страница, който надвишава ограничението (което е зададено на 200000
байта в примерния код), в случай че една страница не може да бъде намалена до по-малко байтове. В такъв случай splitter.isOverSized()
ще върне true
и ще трябва да намерите друг начин за намаляване на PDF файла.
person
Bruno Lowagie
schedule
19.02.2015