Scribus Developer Documentation - API
logo-pen

Scribus Developer Documentation - API

pdflib_core.cpp

Go to the documentation of this file.
00001 /*
00002 For general Scribus (>=1.3.2) copyright and licensing information please refer
00003 to the COPYING file provided with the program. Following this notice may exist
00004 a copyright and/or license notice that predates the release of Scribus 1.3.2
00005 for which a new license (GPL+exception) is in place.
00006 */
00007 /***************************************************************************
00008                           pdflib_core.cpp  -  description
00009                              -------------------
00010     begin                : Sat Jan 19 2002
00011     copyright            : (C) 2002 by Franz Schmid
00012     email                : Franz.Schmid@altmuehlnet.de
00013  ***************************************************************************/
00014 
00015 /***************************************************************************
00016  *                                                                         *
00017  *   This program is free software; you can redistribute it and/or modify  *
00018  *   it under the terms of the GNU General Public License as published by  *
00019  *   the Free Software Foundation; either version 2 of the License, or     *
00020  *   (at your option) any later version.                                   *
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;//Even when aborting we return true. Dont want that "couldnt write msg"
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 // Encode a string for inclusion in a
00252 // PDF (literal) .
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     // on little endian systems we ned to swap bytes:
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 /*  if (Options.docInfoMarks)
00822     {
00823         StdFonts.insert("/Helvetica", "");
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