00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "pdflib_core.h"
00025
00026 #include "scconfig.h"
00027
00028 #include <string>
00029 #include <QString>
00030 #include <QRect>
00031 #include <QImage>
00032 #include <QRegExp>
00033 #include <QDateTime>
00034 #include <QFileInfo>
00035 #include <QDataStream>
00036 #include <QDir>
00037 #include <QList>
00038 #include <QByteArray>
00039 #include <QPainterPath>
00040 #include <QPixmap>
00041 #include <QTextCodec>
00042 #include <cstdlib>
00043 #include <cmath>
00044 #include <QStack>
00045 #ifdef HAVE_UNISTD_H
00046 #include <unistd.h>
00047 #endif
00048 #include "rc4.h"
00049
00050
00051 #include "bookmwin.h"
00052 #include "bookmarkpalette.h"
00053 #include "cmsettings.h"
00054 #include "commonstrings.h"
00055 #include "multiprogressdialog.h"
00056 #include "page.h"
00057 #include "pageitem.h"
00058 #include "pageitem_textframe.h"
00059 #include "pdfoptions.h"
00060 #include "prefscontext.h"
00061 #include "prefsmanager.h"
00062 #include "sccolor.h"
00063 #include "sccolorengine.h"
00064 #include "scfonts.h"
00065 #include "scpaths.h"
00066 #include "scpattern.h"
00067 #include "scribus.h"
00068 #include "scribuscore.h"
00069 #include "scribusdoc.h"
00070 #include "text/nlsconfig.h"
00071 #include "util.h"
00072 #include "util_formats.h"
00073 #include "util_math.h"
00074
00075
00076 using namespace std;
00077
00078 #include <tiffio.h>
00079
00080
00081 PDFLibCore::PDFLibCore(ScribusDoc & docu)
00082 : QObject(&docu),
00083 doc(docu),
00084 ActPageP(0),
00085 Options(doc.PDF_Options),
00086 Bvie(0),
00087 ObjCounter(7),
00088 ResNam("RE"),
00089 ResCount(0),
00090 NDnam("LI"),
00091 NDnum(0),
00092 KeyGen(""),
00093 OwnerKey(""),
00094 UserKey(""),
00095 FileID(""),
00096 EncryKey(""),
00097 Encrypt(0),
00098 KeyLen(5),
00099 colorsToUse(),
00100 spotNam("Spot"),
00101 spotCount(0),
00102 progressDialog(0),
00103 abortExport(false),
00104 usingGUI(ScCore->usingGUI())
00105 {
00106 KeyGen.resize(32);
00107 OwnerKey.resize(32);
00108 UserKey.resize(32);
00109 FileID.resize(16);
00110 EncryKey.resize(5);
00111 Catalog.Outlines = 2;
00112 Catalog.PageTree = 3;
00113 Catalog.Dest = 4;
00114 PageTree.Count = 0;
00115 Outlines.First = 0;
00116 Outlines.Last = 0;
00117 Outlines.Count = 0;
00118 Seite.ObjNum = 0;
00119 Seite.Thumb = 0;
00120 int kg_array[] = {0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, 0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa,
00121 0x01, 0x08, 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80, 0x2f, 0x0c, 0xa9, 0xfe,
00122 0x64, 0x53, 0x69, 0x7a};
00123 for (int a = 0; a < 32; ++a)
00124 KeyGen[a] = kg_array[a];
00125 if (usingGUI)
00126 {
00127 progressDialog = new MultiProgressDialog( tr("Saving PDF"), CommonStrings::tr_Cancel, doc.scMW());
00128 Q_CHECK_PTR(progressDialog);
00129 QStringList barNames, barTexts;
00130 barNames << "EMP" << "EP" << "ECPI";
00131 barTexts << tr("Exporting Master Page:") << tr("Exporting Page:") << tr("Exporting Items on Current Page:");
00132 QList<bool> barsNumeric;
00133 barsNumeric << true << true << false;
00134 progressDialog->addExtraProgressBars(barNames, barTexts, barsNumeric);
00135 connect(progressDialog, SIGNAL(canceled()), this, SLOT(cancelRequested()));
00136 }
00137 }
00138
00139 PDFLibCore::~PDFLibCore()
00140 {
00141 delete progressDialog;
00142 }
00143
00144 static inline QString FToStr(double c)
00145 {
00146 return QString::number(c, 'f', 5);
00147 };
00148
00149 bool PDFLibCore::doExport(const QString& fn, const QString& nam, int Components,
00150 const std::vector<int> & pageNs, const QMap<int,QPixmap> & thumbs)
00151 {
00152 QPixmap pm;
00153 bool ret = false, error = false;
00154 int pc_exportpages=0;
00155 int pc_exportmasterpages=0;
00156 if (usingGUI)
00157 progressDialog->show();
00158 QMap<QString, QMap<uint, FPointArray> > usedFonts;
00159 usedFonts.clear();
00160 doc.getUsedFonts(usedFonts);
00161 if (PDF_Begin_Doc(fn, PrefsManager::instance()->appPrefs.AvailFonts, usedFonts, doc.scMW()->bookmarkPalette->BView))
00162 {
00163 QMap<int, int> pageNsMpa;
00164 for (uint a = 0; a < pageNs.size(); ++a)
00165 {
00166 pageNsMpa.insert(doc.MasterNames[doc.Pages->at(pageNs[a]-1)->MPageNam], 0);
00167 }
00168 if (usingGUI)
00169 {
00170 progressDialog->setOverallTotalSteps(pageNsMpa.count()+pageNs.size());
00171 progressDialog->setTotalSteps("EMP", pageNsMpa.count());
00172 progressDialog->setTotalSteps("EP", pageNs.size());
00173 progressDialog->setOverallProgress(0);
00174 progressDialog->setProgress("EMP", 0);
00175 progressDialog->setProgress("EP", 0);
00176 }
00177 for (int ap = 0; ap < doc.MasterPages.count() && !abortExport; ++ap)
00178 {
00179 if (doc.MasterItems.count() != 0)
00180 {
00181 if (pageNsMpa.contains(ap))
00182 {
00183 qApp->processEvents();
00184 if (!PDF_TemplatePage(doc.MasterPages.at(ap)))
00185 error = abortExport = true;
00186 ++pc_exportmasterpages;
00187 }
00188 }
00189 if (usingGUI)
00190 {
00191 progressDialog->setProgress("EMP", pc_exportmasterpages);
00192 progressDialog->setOverallProgress(pc_exportmasterpages+pc_exportpages);
00193 }
00194 }
00195 for (uint a = 0; a < pageNs.size() && !abortExport; ++a)
00196 {
00197 if (doc.PDF_Options.Thumbnails)
00198 pm = thumbs[pageNs[a]];
00199 qApp->processEvents();
00200 if (abortExport) break;
00201
00202 PDF_Begin_Page(doc.Pages->at(pageNs[a]-1), pm);
00203 qApp->processEvents();
00204 if (abortExport) break;
00205
00206 if (!PDF_ProcessPage(doc.Pages->at(pageNs[a]-1), pageNs[a]-1, doc.PDF_Options.doClip))
00207 error = abortExport = true;
00208 qApp->processEvents();
00209 if (abortExport) break;
00210
00211 PDF_End_Page();
00212 pc_exportpages++;
00213 if (usingGUI)
00214 {
00215 progressDialog->setProgress("EP", pc_exportpages);
00216 progressDialog->setOverallProgress(pc_exportmasterpages+pc_exportpages);
00217 }
00218 }
00219 ret = true;
00220 if (!abortExport)
00221 {
00222 if (doc.PDF_Options.Version == PDFOptions::PDFVersion_X3)
00223 PDF_End_Doc(ScCore->PrinterProfiles[doc.PDF_Options.PrintProf], nam, Components);
00224 else
00225 PDF_End_Doc();
00226 }
00227 else
00228 closeAndCleanup();
00229 }
00230 if (usingGUI)
00231 progressDialog->close();
00232 return (ret && !error);
00233 }
00234
00235 const QString& PDFLibCore::errorMessage(void) const
00236 {
00237 return ErrorMessage;
00238 }
00239
00240 bool PDFLibCore::exportAborted(void) const
00241 {
00242 return abortExport;
00243 }
00244
00245 void PDFLibCore::StartObj(int nr)
00246 {
00247 XRef.append(bytesWritten());
00248 PutDoc(QString::number(nr)+ " 0 obj\n");
00249 }
00250
00251
00252
00253 QString PDFLibCore::PDFEncode(const QString & in)
00254 {
00255 QString tmp("");
00256 for (int d = 0; d < in.length(); ++d)
00257 {
00258 QChar cc(in.at(d));
00259 if ((cc == '(') || (cc == ')') || (cc == '\\'))
00260 tmp += '\\';
00261 tmp += cc;
00262 }
00263 return tmp;
00264 }
00265
00266 QByteArray PDFLibCore::EncodeUTF16(const QString &in)
00267 {
00268 QString tmp("");
00269 for (int d = 0; d < in.length(); ++d)
00270 {
00271 QChar cc(in.at(d));
00272 if ((cc == '(') || (cc == ')') || (cc == '\\'))
00273 tmp += '\\';
00274 tmp += cc;
00275 }
00276 QTextCodec *codec = QTextCodec::codecForName("ISO-10646-UCS-2");
00277 QByteArray cres = codec->fromUnicode( tmp );
00278 #ifndef WORDS_BIGENDIAN
00279
00280 uchar sw;
00281 for(int d = 0; d < cres.size()-1; d += 2)
00282 {
00283 sw = cres[d];
00284 cres[d] = cres[d+1];
00285 cres[d+1] = sw;
00286 }
00287 #endif
00288 return cres;
00289 }
00290
00291 QString PDFLibCore::EncStream(const QString & in, int ObjNum)
00292 {
00293 if (in.length() < 1)
00294 return QString("");
00295 else if (!Options.Encrypt)
00296 return in;
00297 rc4_context_t rc4;
00298 int dlen = 0;
00299 QString tmp(in);
00300 QByteArray us(tmp.length(), ' ');
00301 QByteArray ou(tmp.length(), ' ');
00302 for (int a = 0; a < tmp.length(); ++a)
00303 us[a] = QChar(tmp.at(a)).cell();
00304 QByteArray data(10, ' ');
00305 if (KeyLen > 5)
00306 data.resize(21);
00307 for (int cd = 0; cd < KeyLen; ++cd)
00308 {
00309 data[cd] = EncryKey[cd];
00310 dlen++;
00311 }
00312 data[dlen++] = ObjNum;
00313 data[dlen++] = ObjNum >> 8;
00314 data[dlen++] = ObjNum >> 16;
00315 data[dlen++] = 0;
00316 data[dlen++] = 0;
00317 QByteArray step1(16, ' ');
00318 step1 = ComputeMD5Sum(&data);
00319 rc4_init(&rc4, reinterpret_cast<uchar*>(step1.data()), qMin(KeyLen+5, 16));
00320 rc4_encrypt(&rc4, reinterpret_cast<uchar*>(us.data()), reinterpret_cast<uchar*>(ou.data()), tmp.length());
00321 QString uk = "";
00322 for (int cl = 0; cl < tmp.length(); ++cl)
00323 uk += QChar(ou[cl]);
00324 return uk;
00325 }
00326
00327 QByteArray PDFLibCore::EncStreamArray(const QByteArray & in, int ObjNum)
00328 {
00329 if (in.size() < 1)
00330 return QByteArray();
00331 else if (!Options.Encrypt)
00332 return in;
00333 rc4_context_t rc4;
00334 int dlen = 0;
00335 QByteArray out(in.size(), ' ');
00336 QByteArray data(10, ' ');
00337 if (KeyLen > 5)
00338 data.resize(21);
00339 for (int cd = 0; cd < KeyLen; ++cd)
00340 {
00341 data[cd] = EncryKey[cd];
00342 dlen++;
00343 }
00344 data[dlen++] = ObjNum;
00345 data[dlen++] = ObjNum >> 8;
00346 data[dlen++] = ObjNum >> 16;
00347 data[dlen++] = 0;
00348 data[dlen++] = 0;
00349 QByteArray step1(16, ' ');
00350 step1 = ComputeMD5Sum(&data);
00351 rc4_init(&rc4, reinterpret_cast<uchar*>(step1.data()), qMin(KeyLen+5, 16));
00352 rc4_encrypt(&rc4, reinterpret_cast<const uchar*>(in.constData()), reinterpret_cast<uchar*>(out.data()), in.size());
00353 return out;
00354 }
00355
00356 QString PDFLibCore::EncString(const QString & in, int ObjNum)
00357 {
00358 if (!Options.Encrypt)
00359 return in;
00360 rc4_context_t rc4;
00361 QString tmp;
00362 int dlen = 0;
00363 if (in.length() < 3)
00364 return "<>";
00365 tmp = in.mid(1, in.length()-2);
00366 QByteArray us(tmp.length(), ' ');
00367 QByteArray ou(tmp.length(), ' ');
00368 for (int a = 0; a < tmp.length(); ++a)
00369 us[a] = static_cast<uchar>(QChar(tmp.at(a)).cell());
00370 QByteArray data(10, ' ');
00371 if (KeyLen > 5)
00372 data.resize(21);
00373 for (int cd = 0; cd < KeyLen; ++cd)
00374 {
00375 data[cd] = EncryKey[cd];
00376 dlen++;
00377 }
00378 data[dlen++] = ObjNum;
00379 data[dlen++] = ObjNum >> 8;
00380 data[dlen++] = ObjNum >> 16;
00381 data[dlen++] = 0;
00382 data[dlen++] = 0;
00383 QByteArray step1(16, ' ');
00384 step1 = ComputeMD5Sum(&data);
00385 rc4_init(&rc4, reinterpret_cast<uchar*>(step1.data()), qMin(KeyLen+5, 16));
00386 rc4_encrypt(&rc4, reinterpret_cast<uchar*>(us.data()), reinterpret_cast<uchar*>(ou.data()), tmp.length());
00387 QString uk = "";
00388 for (int cl = 0; cl < tmp.length(); ++cl)
00389 uk += QChar(ou[cl]);
00390 tmp = "<"+String2Hex(&uk, false)+">";
00391 return tmp;
00392 }
00393
00394 QString PDFLibCore::EncStringUTF16(const QString & in, int ObjNum)
00395 {
00396 if (in.length() < 3)
00397 return "<>";
00398 if (!Options.Encrypt)
00399 {
00400 QString tmp = in.mid(1, in.length()-2);
00401 QByteArray us = EncodeUTF16(tmp);
00402 QString uk = "";
00403 for (int cl = 0; cl < us.size(); ++cl)
00404 uk += QChar(us[cl]);
00405 return "<"+String2Hex(&uk, false)+">";
00406 }
00407 rc4_context_t rc4;
00408 QString tmp;
00409 int dlen = 0;
00410 tmp = in.mid(1, in.length()-2);
00411 QByteArray us = EncodeUTF16(tmp);
00412 QByteArray ou(us.size(), ' ');
00413 QByteArray data(10, ' ');
00414 if (KeyLen > 5)
00415 data.resize(21);
00416 for (int cd = 0; cd < KeyLen; ++cd)
00417 {
00418 data[cd] = EncryKey[cd];
00419 dlen++;
00420 }
00421 data[dlen++] = ObjNum;
00422 data[dlen++] = ObjNum >> 8;
00423 data[dlen++] = ObjNum >> 16;
00424 data[dlen++] = 0;
00425 data[dlen++] = 0;
00426 QByteArray step1(16, ' ');
00427 step1 = ComputeMD5Sum(&data);
00428 rc4_init(&rc4, reinterpret_cast<uchar*>(step1.data()), qMin(KeyLen+5, 16));
00429 rc4_encrypt(&rc4, reinterpret_cast<uchar*>(us.data()), reinterpret_cast<uchar*>(ou.data()), ou.size());
00430 QString uk = "";
00431 for (int cl = 0; cl < ou.size(); ++cl)
00432 uk += QChar(ou[cl]);
00433 tmp = "<"+String2Hex(&uk, false)+">";
00434 return tmp;
00435 }
00436
00437 bool PDFLibCore::EncodeArrayToStream(const QByteArray& in, int ObjNum)
00438 {
00439 if (in.size() < 1)
00440 return true;
00441 if (Options.Encrypt)
00442 {
00443 int dlen = 0;
00444 rc4_context_t rc4;
00445 unsigned char fallBackBuffer[1024];
00446 QByteArray buffer(65536, ' ');
00447 QByteArray data(10, ' ');
00448 if (KeyLen > 5)
00449 data.resize(21);
00450 for (int cd = 0; cd < KeyLen; ++cd)
00451 {
00452 data[cd] = EncryKey[cd];
00453 dlen++;
00454 }
00455 data[dlen++] = ObjNum;
00456 data[dlen++] = ObjNum >> 8;
00457 data[dlen++] = ObjNum >> 16;
00458 data[dlen++] = 0;
00459 data[dlen++] = 0;
00460 QByteArray step1(16, ' ');
00461 step1 = ComputeMD5Sum(&data);
00462
00463 uint writeBufferS = (buffer.size() > 0) ? buffer.size() : 1024;
00464 uchar* writeBuffer = (buffer.size() > 0) ? (unsigned char*) buffer.data() : fallBackBuffer;
00465 uint dataBufferS = in.size();
00466 const uchar* dataBuffer = (const uchar*) in.data();
00467
00468 rc4_init(&rc4, reinterpret_cast<uchar*>(step1.data()), qMin(KeyLen+5, 16));
00469 while (dataBufferS >= writeBufferS)
00470 {
00471 rc4_encrypt(&rc4, dataBuffer, writeBuffer, writeBufferS);
00472 outStream.writeRawData((const char*) writeBuffer, writeBufferS);
00473 dataBuffer += writeBufferS;
00474 dataBufferS -= writeBufferS;
00475 }
00476 if (dataBufferS > 0)
00477 {
00478 rc4_encrypt(&rc4, dataBuffer, writeBuffer, dataBufferS);
00479 outStream.writeRawData((const char*) writeBuffer, dataBufferS);
00480 }
00481 }
00482 else
00483 outStream.writeRawData(in, in.size());
00484 return (outStream.status() == QDataStream::Ok);
00485 }
00486
00487 QString PDFLibCore::FitKey(const QString & pass)
00488 {
00489 QString pw(pass);
00490 if (pw.length() < 32)
00491 {
00492 uint l = pw.length();
00493 for (uint a = 0; a < 32 - l; ++a)
00494 pw += QChar(KeyGen[a]);
00495 }
00496 else
00497 pw = pw.left(32);
00498 return pw;
00499 }
00500
00501 void PDFLibCore::CalcOwnerKey(const QString & Owner, const QString & User)
00502 {
00503 rc4_context_t rc4;
00504 QString pw(FitKey(User));
00505 QString pw2(FitKey(Owner.isEmpty() ? User : Owner));
00506 QByteArray step1(16, ' ');
00507 step1 = ComputeMD5(pw2);
00508 if (KeyLen > 5)
00509 {
00510 for (int kl = 0; kl < 50; ++kl)
00511 step1 = ComputeMD5Sum(&step1);
00512 }
00513 QByteArray us(32, ' ');
00514 QByteArray enk(16, ' ');
00515 if (KeyLen > 5)
00516 {
00517 for (uint a2 = 0; a2 < 32; ++a2)
00518 OwnerKey[a2] = QChar(pw.at(a2)).cell();
00519 for (int rl = 0; rl < 20; rl++)
00520 {
00521 for (int j = 0; j < 16; j ++)
00522 enk[j] = step1[j] ^ rl;
00523 rc4_init(&rc4, reinterpret_cast<uchar*>(enk.data()), 16);
00524 rc4_encrypt(&rc4, reinterpret_cast<uchar*>(OwnerKey.data()),
00525 reinterpret_cast<uchar*>(OwnerKey.data()), 32);
00526 }
00527 }
00528 else
00529 {
00530 for (uint a = 0; a < 32; ++a)
00531 us[a] = static_cast<uchar>(QChar(pw.at(a)).cell());
00532 rc4_init(&rc4, reinterpret_cast<uchar*>(step1.data()), 5);
00533 rc4_encrypt(&rc4, reinterpret_cast<uchar*>(us.data()),
00534 reinterpret_cast<uchar*>(OwnerKey.data()), 32);
00535 }
00536 }
00537
00538 void PDFLibCore::CalcUserKey(const QString & User, int Permission)
00539 {
00540 rc4_context_t rc4;
00541 QString pw(FitKey(User));
00542 QByteArray step1(16, ' ');
00543 QByteArray perm(4, ' ');
00544 uint perm_value = static_cast<uint>(Permission);
00545 perm[0] = perm_value;
00546 perm[1] = perm_value >> 8;
00547 perm[2] = perm_value >> 16;
00548 perm[3] = perm_value >> 24;
00549 for (uint a = 0; a < 32; ++a)
00550 pw += QChar(OwnerKey[a]);
00551 for (uint a1 = 0; a1 < 4; ++a1)
00552 pw += QChar(perm[a1]);
00553 for (uint a3 = 0; a3 < 16; ++a3)
00554 pw += QChar(FileID[a3]);
00555 step1 = ComputeMD5(pw);
00556 if (KeyLen > 5)
00557 {
00558 for (int kl = 0; kl < 50; ++kl)
00559 step1 = ComputeMD5Sum(&step1);
00560 EncryKey.resize(16);
00561 }
00562 for (int a2 = 0; a2 < KeyLen; ++a2)
00563 EncryKey[a2] = step1[a2];
00564 if (KeyLen > 5)
00565 {
00566 QString pr2("");
00567 for (int kl3 = 0; kl3 < 32; ++kl3)
00568 pr2 += QChar(KeyGen[kl3]);
00569 for (uint a4 = 0; a4 < 16; ++a4)
00570 pr2 += QChar(FileID[a4]);
00571 step1 = ComputeMD5(pr2);
00572 QByteArray enk(16, ' ');
00573 for (uint a3 = 0; a3 < 16; ++a3)
00574 UserKey[a3] = step1[a3];
00575 for (int rl = 0; rl < 20; rl++)
00576 {
00577 for (int j = 0; j < 16; j ++)
00578 enk[j] = EncryKey[j] ^ rl;
00579 rc4_init(&rc4, reinterpret_cast<uchar*>(enk.data()), 16);
00580 rc4_encrypt(&rc4, reinterpret_cast<uchar*>(UserKey.data()), reinterpret_cast<uchar*>(UserKey.data()), 16);
00581 }
00582 }
00583 else
00584 {
00585 rc4_init(&rc4, reinterpret_cast<uchar*>(step1.data()), 5);
00586 rc4_encrypt(&rc4, reinterpret_cast<uchar*>(KeyGen.data()), reinterpret_cast<uchar*>(UserKey.data()), 32);
00587 }
00588 }
00589
00590 QByteArray PDFLibCore::ComputeMD5(const QString& in)
00591 {
00592 uint inlen=in.length();
00593 QByteArray TBytes(inlen, ' ');
00594 for (uint a = 0; a < inlen; ++a)
00595 TBytes[a] = static_cast<uchar>(QChar(in.at(a)).cell());
00596 return ComputeMD5Sum(&TBytes);
00597 }
00598
00599 bool PDFLibCore::PDF_Begin_Doc(const QString& fn, SCFonts &AllFonts, QMap<QString, QMap<uint, FPointArray> > DocFonts, BookMView* vi)
00600 {
00601 Spool.setFileName(fn);
00602 if (!Spool.open(QIODevice::WriteOnly))
00603 return false;
00604 outStream.setDevice(&Spool);
00605 QString tmp;
00606 QString ok = "";
00607 QString uk = "";
00608 QFileInfo fd;
00609 QString fext;
00610 int a;
00611 inPattern = 0;
00612 Bvie = vi;
00613 BookMinUse = false;
00614 UsedFontsP.clear();
00615 UsedFontsF.clear();
00616 if ((Options.Version == 15) && (Options.useLayers))
00617 ObjCounter = 10;
00618 else
00619 ObjCounter = 9;
00620 switch (Options.Version)
00621 {
00622 case 12:
00623 case 13:
00624 PutDoc("%PDF-1.3\n");
00625 break;
00626 case 14:
00627 PutDoc("%PDF-1.4\n");
00628 break;
00629 case 15:
00630 PutDoc("%PDF-1.5\n");
00631 break;
00632 }
00633 if (Options.Version == 12)
00634 ObjCounter++;
00635 PutDoc("%\xc7\xec\x8f\xa2\n");
00636 StartObj(1);
00637 PutDoc("<<\n/Type /Catalog\n/Outlines 3 0 R\n/Pages 4 0 R\n/Dests 5 0 R\n/AcroForm 6 0 R\n/Names 7 0 R\n/Threads 8 0 R\n");
00638 if ((Options.Version == 15) && (Options.useLayers))
00639 PutDoc("/OCProperties 9 0 R\n");
00640 if (Options.Version == 12)
00641 PutDoc("/OutputIntents [ "+QString::number(ObjCounter-1)+" 0 R ]\n");
00642 PutDoc("/PageLayout ");
00643 switch (Options.PageLayout)
00644 {
00645 case PDFOptions::SinglePage:
00646 PutDoc("/SinglePage\n");
00647 break;
00648 case PDFOptions::OneColumn:
00649 PutDoc("/OneColumn\n");
00650 break;
00651 case PDFOptions::TwoColumnLeft:
00652 PutDoc("/TwoColumnLeft\n");
00653 break;
00654 case PDFOptions::TwoColumnRight:
00655 PutDoc("/TwoColumnRight\n");
00656 break;
00657 }
00658 if (Options.displayBookmarks)
00659 PutDoc("/PageMode /UseOutlines\n");
00660 else if (Options.displayFullscreen)
00661 PutDoc("/PageMode /FullScreen\n");
00662 else if (Options.displayThumbs)
00663 PutDoc("/PageMode /UseThumbs\n");
00664 else if ((Options.Version == 15) && (Options.displayLayers))
00665 PutDoc("/PageMode /UseOC\n");
00666 if (!Options.openAction.isEmpty())
00667 {
00668 PutDoc("/OpenAction << /S /JavaScript /JS (this."+Options.openAction+"\\(\\)) >>\n");
00669 }
00670 PutDoc("/ViewerPreferences\n<<\n/PageDirection ");
00671 PutDoc( Options.Binding == 0 ? "/L2R\n" : "/R2L\n");
00672 if (Options.hideToolBar)
00673 PutDoc("/HideToolbar true\n");
00674 if (Options.hideMenuBar)
00675 PutDoc("/HideMenubar true\n");
00676 if (Options.fitWindow)
00677 PutDoc("/FitWindow true\n");
00678 PutDoc(" >>\n>>\nendobj\n");
00679 QString IDg(Datum);
00680 IDg += Options.Datei;
00681 IDg += "Scribus "+QString(VERSION);
00682 IDg += "Scribus PDF Library "+QString(VERSION);
00683 IDg += doc.documentInfo.getTitle();
00684 IDg += doc.documentInfo.getAuthor();
00685 IDg += "/False";
00686 FileID = ComputeMD5(IDg);
00687 if (Options.Encrypt)
00688 {
00689 if ((Options.Version == 14) || (Options.Version == 15))
00690 KeyLen = 16;
00691 else
00692 KeyLen = 5;
00693 CalcOwnerKey(Options.PassOwner, Options.PassUser);
00694 CalcUserKey(Options.PassUser, Options.Permissions);
00695 for (uint cl2 = 0; cl2 < 32; ++cl2)
00696 ok += QChar(OwnerKey[cl2]);
00697 if (KeyLen > 5)
00698 {
00699 for (uint cl3 = 0; cl3 < 16; ++cl3)
00700 uk += QChar(UserKey[cl3]);
00701 for (uint cl3r = 0; cl3r < 16; ++cl3r)
00702 uk += QChar(KeyGen[cl3r]);
00703 }
00704 else
00705 {
00706 for (uint cl = 0; cl < 32; ++cl)
00707 uk += QChar(UserKey[cl]);
00708 }
00709 }
00710 QDate d = QDate::currentDate();
00711 Datum = "D:";
00712 tmp.sprintf("%4d", d.year());
00713 tmp.replace(QRegExp(" "), "0");
00714 Datum += tmp;
00715 tmp.sprintf("%2d", d.month());
00716 tmp.replace(QRegExp(" "), "0");
00717 Datum += tmp;
00718 tmp.sprintf("%2d", d.day());
00719 tmp.replace(QRegExp(" "), "0");
00720 Datum += tmp;
00721 tmp = QTime::currentTime().toString();
00722 tmp.replace(QRegExp(":"), "");
00723 Datum += tmp;
00724 StartObj(2);
00725 PutDoc("<<\n/Creator "+EncString("(Scribus "+QString(VERSION)+")",2)+"\n");
00726 PutDoc("/Producer "+EncString("(Scribus PDF Library "+QString(VERSION)+")",2)+"\n");
00727 QString docTitle = doc.documentInfo.getTitle();
00728 if ((Options.Version == 12) && (docTitle.isEmpty()))
00729 PutDoc("/Title "+EncStringUTF16("("+doc.DocName+")",2)+"\n");
00730 else
00731 PutDoc("/Title "+EncStringUTF16("("+doc.documentInfo.getTitle()+")",2)+"\n");
00732 PutDoc("/Author "+EncStringUTF16("("+doc.documentInfo.getAuthor()+")",2)+"\n");
00733 PutDoc("/Keywords "+EncStringUTF16("("+doc.documentInfo.getKeywords()+")",2)+"\n");
00734 PutDoc("/CreationDate "+EncString("("+Datum+")",2)+"\n");
00735 PutDoc("/ModDate "+EncString("("+Datum+")",2)+"\n");
00736 if (Options.Version == 12)
00737 PutDoc("/GTS_PDFXVersion (PDF/X-3:2002)\n");
00738 PutDoc("/Trapped /False\n>>\nendobj\n");
00739 for (int t = 0; t < 6; ++t)
00740 XRef.append(bytesWritten());
00741 if ((Options.Version == 15) && (Options.useLayers))
00742 XRef.append(bytesWritten());
00743 if (Options.Version == 12)
00744 XRef.append(bytesWritten());
00745 if (Options.Encrypt)
00746 {
00747 StartObj(ObjCounter);
00748 Encrypt = ObjCounter;
00749 ObjCounter++;
00750 PutDoc("<<\n/Filter /Standard\n");
00751 PutDoc( KeyLen > 5 ? "/R 3\n/V 2\n/Length 128\n" : "/R 2\n/V 1\n");
00752 PutDoc("/O <"+String2Hex(&ok)+">\n");
00753 PutDoc("/U <"+String2Hex(&uk)+">\n");
00754 PutDoc("/P "+QString::number(Options.Permissions)+"\n>>\nendobj\n");
00755 }
00756 QMap<QString, QMap<uint, FPointArray> > ReallyUsed;
00757 ReallyUsed.clear();
00758 PageItem* pgit;
00759 QMap<int, QString> ind2PDFabr;
00760 const QString tmpf[] = {"/Courier", "/Courier-Bold", "/Courier-Oblique", "/Courier-BoldOblique",
00761 "/Helvetica", "/Helvetica-Bold", "/Helvetica-Oblique", "/Helvetica-BoldOblique",
00762 "/Times-Roman", "/Times-Bold", "/Times-Italic", "/Times-BoldItalic",
00763 "/ZapfDingbats", "/Symbol"};
00764 size_t ar = sizeof(tmpf) / sizeof(*tmpf);
00765 for (uint ax = 0; ax < ar; ++ax)
00766 ind2PDFabr[ax] = tmpf[ax];
00767 for (int c = 0; c < doc.FrameItems.count(); ++c)
00768 {
00769 pgit = doc.FrameItems.at(c);
00770 if ((pgit->itemType() == PageItem::TextFrame) || (pgit->itemType() == PageItem::PathText))
00771 {
00772 if (pgit->isAnnotation())
00773 {
00774 if (pgit->annotation().Type() == 4)
00775 StdFonts.insert("/ZapfDingbats", "");
00776 StdFonts.insert(ind2PDFabr[pgit->annotation().Font()], "");
00777 ReallyUsed.insert(pgit->itemText.defaultStyle().charStyle().font().replacementName(), DocFonts[pgit->itemText.defaultStyle().charStyle().font().replacementName()]);
00778 }
00779 for (uint e = 0; e < static_cast<uint>(pgit->itemText.length()); ++e)
00780 {
00781 ReallyUsed.insert(pgit->itemText.charStyle(e).font().replacementName(), DocFonts[pgit->itemText.charStyle(e).font().replacementName()]);
00782 }
00783 }
00784 }
00785 for (int c = 0; c < doc.MasterItems.count(); ++c)
00786 {
00787 pgit = doc.MasterItems.at(c);
00788 if ((pgit->itemType() == PageItem::TextFrame) || (pgit->itemType() == PageItem::PathText))
00789 {
00790 if (pgit->isAnnotation())
00791 {
00792 if (pgit->annotation().Type() == 4)
00793 StdFonts.insert("/ZapfDingbats", "");
00794 StdFonts.insert(ind2PDFabr[pgit->annotation().Font()], "");
00795 ReallyUsed.insert(pgit->itemText.defaultStyle().charStyle().font().replacementName(), DocFonts[pgit->itemText.defaultStyle().charStyle().font().replacementName()]);
00796 }
00797 for (uint e = 0; e < static_cast<uint>(pgit->itemText.length()); ++e)
00798 {
00799 ReallyUsed.insert(pgit->itemText.charStyle(e).font().replacementName(), DocFonts[pgit->itemText.charStyle(e).font().replacementName()]);
00800 }
00801 }
00802 }
00803 for (int d = 0; d < doc.Items->count(); ++d)
00804 {
00805 pgit = doc.Items->at(d);
00806 if ((pgit->itemType() == PageItem::TextFrame) || (pgit->itemType() == PageItem::PathText))
00807 {
00808 if (pgit->isAnnotation())
00809 {
00810 if (pgit->annotation().Type() == 4)
00811 StdFonts.insert("/ZapfDingbats", "");
00812 StdFonts.insert(ind2PDFabr[pgit->annotation().Font()], "");
00813 ReallyUsed.insert(pgit->itemText.defaultStyle().charStyle().font().replacementName(), DocFonts[pgit->itemText.defaultStyle().charStyle().font().replacementName()]);
00814 }
00815 for (uint e = 0; e < static_cast<uint>(pgit->itemText.length()); ++e)
00816 {
00817 ReallyUsed.insert(pgit->itemText.charStyle(e).font().replacementName(), DocFonts[pgit->itemText.charStyle(e).font().replacementName()]);
00818 }
00819 }
00820 }
00821
00822
00823
00824
00825 QStringList patterns = doc.getUsedPatterns();
00826 for (int c = 0; c < patterns.count(); ++c)
00827 {
00828 ScPattern pa = doc.docPatterns[patterns[c]];
00829 for (int o = 0; o < pa.items.count(); o++)
00830 {
00831 pgit = pa.items.at(o);
00832 if ((pgit->itemType() == PageItem::TextFrame) || (pgit->itemType() == PageItem::PathText))
00833 {
00834 if (pgit->isAnnotation())
00835 {
00836 if (pgit->annotation().Type() == 4)
00837 StdFonts.insert("/ZapfDingbats", "");
00838 StdFonts.insert(ind2PDFabr[pgit->annotation().Font()], "");
00839 ReallyUsed.insert(pgit->itemText.defaultStyle().charStyle().font().replacementName(), DocFonts[pgit->itemText.defaultStyle().charStyle().font().replacementName()]);
00840 }
00841 for (uint e = 0; e < static_cast<uint>(pgit->itemText.length()); ++e)
00842 {
00843 ReallyUsed.insert(pgit->itemText.charStyle(e).font().replacementName(), DocFonts[pgit->itemText.charStyle(e).font().replacementName()]);
00844 }
00845 }
00846 }
00847 }
00848 a = 0;
00849 QMap<QString, QString>::Iterator itStd;
00850 for (itStd = StdFonts.begin(); itStd != StdFonts.end(); ++itStd)
00851 {
00852 StartObj(ObjCounter);
00853 PutDoc("<<\n/Type /Font\n/Subtype /Type1\n");
00854 PutDoc("/Name /FoStd"+QString::number(a)+"\n");
00855 PutDoc("/BaseFont "+itStd.key()+"\n");
00856 if (itStd.key() != "/ZapfDingbats")
00857 {
00858 PutDoc("/Encoding << \n");
00859 PutDoc("/Differences [ \n");
00860 PutDoc("24 /breve /caron /circumflex /dotaccent /hungarumlaut /ogonek /ring /tilde\n");
00861 PutDoc("39 /quotesingle 96 /grave 128 /bullet /dagger /daggerdbl /ellipsis /emdash /endash /florin /fraction /guilsinglleft /guilsinglright\n");
00862 PutDoc("/minus /perthousand /quotedblbase /quotedblleft /quotedblright /quoteleft /quoteright /quotesinglbase /trademark /fi /fl /Lslash /OE /Scaron\n");
00863 PutDoc("/Ydieresis /Zcaron /dotlessi /lslash /oe /scaron /zcaron 164 /currency 166 /brokenbar 168 /dieresis /copyright /ordfeminine 172 /logicalnot\n");
00864 PutDoc("/.notdef /registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu 183 /periodcentered /cedilla /onesuperior /ordmasculine\n");
00865 PutDoc("188 /onequarter /onehalf /threequarters 192 /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex\n");
00866 PutDoc("/Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash\n");
00867 PutDoc("/Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla\n");
00868 PutDoc("/egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis\n");
00869 PutDoc("/divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis\n");
00870 PutDoc("] >>\n");
00871 }
00872 PutDoc(">>\nendobj\n");
00873 Seite.FObjects["FoStd"+QString::number(a)] = ObjCounter;
00874 itStd.value() = "FoStd"+QString::number(a);
00875 ObjCounter++;
00876 a++;
00877 }
00878 QMap<QString,QMap<uint, FPointArray> >::Iterator it;
00879 a = 0;
00880 for (it = ReallyUsed.begin(); it != ReallyUsed.end(); ++it)
00881 {
00882 ScFace::FontFormat fformat = AllFonts[it.key()].format();
00883 if ((!AllFonts[it.key()].hasNames()) || (Options.SubsetList.contains(it.key())))
00884 {
00885 if (AllFonts[it.key()].hasNames())
00886 {
00887 UsedFontsP.insert(it.key(), "/Fo"+QString::number(a));
00888 uint SubFonts = 0;
00889 int glyphCount = 0;
00890 double minx = 99999.9;
00891 double miny = 99999.9;
00892 double maxx = -99999.9;
00893 double maxy = -99999.9;
00894 QList<uint> glyphWidths;
00895 QStringList charProcs;
00896 QString encoding = "<< /Type /Encoding\n/Differences [ 0\n";
00897 QString fon("");
00898 QM