Subversion Repositories Scribus

Rev

Rev 21744 | Rev 21775 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4430 cbradney 1
/*
2
For general Scribus (>=1.3.2) copyright and licensing information please refer
3
to the COPYING file provided with the program. Following this notice may exist
4
a copyright and/or license notice that predates the release of Scribus 1.3.2
5
for which a new license (GPL+exception) is in place.
6
*/
3133 fschmid 7
/***************************************************************************
14043 jghali 8
                                                  pdflib_core.cpp  -  description
9
                                                         -------------------
10
        begin                : Sat Jan 19 2002
11
        copyright            : (C) 2002 by Franz Schmid
12
        email                : Franz.Schmid@altmuehlnet.de
3133 fschmid 13
 ***************************************************************************/
14
 
15
/***************************************************************************
16
 *                                                                         *
17
 *   This program is free software; you can redistribute it and/or modify  *
18
 *   it under the terms of the GNU General Public License as published by  *
19
 *   the Free Software Foundation; either version 2 of the License, or     *
20
 *   (at your option) any later version.                                   *
21
 *                                                                         *
22
 ***************************************************************************/
23
 
10054 craig 24
#include "pdflib_core.h"
3133 fschmid 25
 
26
#include "scconfig.h"
27
 
17539 jghali 28
#if defined(_MSC_VER) && !defined(_USE_MATH_DEFINES)
14170 jghali 29
#define _USE_MATH_DEFINES
30
#endif
12080 avox 31
#include <cmath>
32
#include <cstdlib>
4229 craig 33
#include <string>
12080 avox 34
#ifdef HAVE_UNISTD_H
35
#include <unistd.h>
36
#endif
37
 
38
#include "rc4.h"
39
 
40
#include <QByteArray>
19914 craig 41
#include <QCryptographicHash>
10223 cbradney 42
#include <QDateTime>
10004 fschmid 43
#include <QDataStream>
12080 avox 44
#include <QDebug>
10223 cbradney 45
#include <QDir>
12080 avox 46
#include <QFileInfo>
47
#include <QImage>
9803 fschmid 48
#include <QList>
11453 fschmid 49
#include <QPainterPath>
8501 cbradney 50
#include <QPixmap>
12080 avox 51
#include <QRect>
52
#include <QRegExp>
19671 jghali 53
#include <QScopedPointer>
12080 avox 54
#include <QStack>
55
#include <QString>
13839 fschmid 56
#include <QTemporaryFile>
10614 cbradney 57
#include <QTextCodec>
14043 jghali 58
#include <QtXml>
59
#include <QUuid>
3133 fschmid 60
 
10601 mrdocs 61
#include "cmsettings.h"
4028 cbradney 62
#include "commonstrings.h"
3133 fschmid 63
#include "pageitem.h"
10601 mrdocs 64
#include "pageitem_textframe.h"
16258 fschmid 65
#include "pageitem_group.h"
17312 fschmid 66
#include "pageitem_table.h"
10212 cbradney 67
#include "pdfoptions.h"
68
#include "prefscontext.h"
69
#include "prefsmanager.h"
70
#include "sccolor.h"
71
#include "sccolorengine.h"
72
#include "scfonts.h"
21107 craig 73
#include "text/textlayoutpainter.h"
20103 avox 74
#include "fonts/cff.h"
75
#include "fonts/sfnt.h"
16736 jghali 76
#include "scpage.h"
5917 jghali 77
#include "scpaths.h"
10212 cbradney 78
#include "scpattern.h"
19115 avox 79
 
5243 cbradney 80
#include "scribuscore.h"
3699 cbradney 81
#include "scribusdoc.h"
11599 jghali 82
#include "scstreamfilter_flate.h"
83
#include "scstreamfilter_rc4.h"
17312 fschmid 84
#include "tableutils.h"
3133 fschmid 85
#include "util.h"
11605 jghali 86
#include "util_file.h"
10212 cbradney 87
#include "util_formats.h"
10203 cbradney 88
#include "util_math.h"
12517 fschmid 89
#include "util_ghostscript.h"
21107 craig 90
#include "text/boxes.h"
16736 jghali 91
 
13839 fschmid 92
#ifdef HAVE_OSG
14930 fschmid 93
        #include "third_party/prc/exportPRC.h"
13839 fschmid 94
#endif
3133 fschmid 95
 
16736 jghali 96
#include "ui/bookmwin.h"
97
#include "ui/bookmarkpalette.h"
98
#include "ui/multiprogressdialog.h"
99
 
3133 fschmid 100
using namespace std;
17312 fschmid 101
using namespace TableUtils;
3133 fschmid 102
 
12096 jghali 103
#if defined(_WIN32)
104
#undef GetObject
105
#endif
3133 fschmid 106
 
21107 craig 107
static inline QByteArray FToStr(double c)
108
{
109
        double v = c;
110
        if (fabs(c) < 0.0000001)
111
                v = 0.0;
112
        return QByteArray::number(v, 'f', 5);
113
}
6562 fschmid 114
 
21107 craig 115
class PdfPainter: public TextLayoutPainter
116
{
117
        QByteArray m_glyphBuffer;
118
        QByteArray m_pathBuffer;
119
        PageItem* m_item;
120
        QMap<QString, PdfFont>  m_UsedFontsP;
121
        PDFLibCore *m_pdf;
122
        uint m_PNr;
123
        const ScPage* m_page;
124
 
125
        QByteArray transformToStr(QTransform tr)
126
        {
127
                return FToStr(tr.m11()) + " " + FToStr(-tr.m12()) + " " + FToStr(-tr.m21()) + " " + FToStr(tr.m22()) + " " + FToStr(tr.dx()) + " " + FToStr(-tr.dy());
128
        }
129
 
130
public:
131
        PdfPainter(PageItem *ite, PDFLibCore *pdf, uint num, const ScPage* pag) :
132
                m_glyphBuffer(),
133
                m_pathBuffer(),
134
                m_item(ite),
135
                m_pdf(pdf),
136
                m_PNr(num),
137
                m_page(pag)
138
        {}
139
 
140
        ~PdfPainter() {}
141
 
21563 jghali 142
        void drawGlyph(const GlyphCluster& gc)
21107 craig 143
        {
21563 jghali 144
                if (gc.isControlGlyphs() || gc.isEmpty())
21107 craig 145
                        return;
21563 jghali 146
 
147
                double current_x = 0.0;
148
                foreach (const GlyphLayout& gl, gc.glyphs()) {
149
                        PdfFont pdfFont = m_pdf->UsedFontsP[font().replacementName()];
150
                        QByteArray StrokeColor;
151
                        QByteArray FillColor;
21107 craig 152
 
21563 jghali 153
                        if (strokeColor().color != CommonStrings::None)
154
                                StrokeColor = m_pdf->putColor(strokeColor().color, strokeColor().shade, false);
155
                        if (fillColor().color != CommonStrings::None)
156
                                FillColor = m_pdf->putColor(fillColor().color, fillColor().shade, true);
21107 craig 157
 
21563 jghali 158
                        QTransform transform = matrix();
159
                        if (pdfFont.method == Use_XForm)
160
                        {
161
                                if (!FillColor.isEmpty())
162
                                        m_pathBuffer += FillColor;
21107 craig 163
 
21563 jghali 164
                                m_pathBuffer += "q\n";
165
                                m_pathBuffer += transformToStr(transform) + " cm\n";
166
                                m_pathBuffer += FToStr(fontSize()) + " 0 0 " + FToStr(fontSize()) + " " + FToStr(x() + gl.xoffset + current_x) + " " + FToStr((y() - fontSize() + gl.yoffset) * -1) + " cm\n";
21107 craig 167
 
21563 jghali 168
                                if (gl.scaleV != 1.0)
169
                                        m_pathBuffer += "1 0 0 1 0 " + FToStr(((fontSize() - fontSize() * gl.scaleV) / fontSize()) * -1) + " cm\n";
170
                                m_pathBuffer += FToStr(qMax(gl.scaleH, 0.1)) + " 0 0 " + FToStr(qMax(gl.scaleV, 0.1)) + " 0 0 cm\n";
21107 craig 171
 
21563 jghali 172
                                if (!FillColor.isEmpty())
173
                                        m_pathBuffer += pdfFont.name + Pdf::toPdf(gl.glyph) + " Do\n";
174
                                m_pathBuffer += "Q\n";
21107 craig 175
                        }
176
                        else
21563 jghali 177
                        {
178
                                uint gid = gl.glyph;
179
                                uint fontNr = 65535;
21107 craig 180
 
181
                                switch (pdfFont.encoding)
182
                                {
21563 jghali 183
                                case  Encode_256:
184
                                        gid = pdfFont.glyphmap[gid];
185
                                        fontNr = gid / 256;
186
                                        gid = gid % 256;
187
                                        break;
21107 craig 188
                                case Encode_224:
21563 jghali 189
                                        fontNr = gid / 224;
190
                                        gid = gid % 224 + 32;
21107 craig 191
                                        break;
21563 jghali 192
                                case Encode_Subset:
193
                                        gid = pdfFont.glyphmap[gid];
194
                                        break;
21107 craig 195
                                case Encode_IdentityH:
196
                                        break;
197
                                }
198
 
21563 jghali 199
                                if (fontNr == 65535)
200
                                        m_glyphBuffer += pdfFont.name + " " + FToStr(fontSize()) + " Tf\n";
201
                                else
202
                                        m_glyphBuffer += pdfFont.name + "S" + Pdf::toPdf(fontNr) + " " + FToStr(fontSize()) + " Tf\n";
21107 craig 203
 
21563 jghali 204
                                if (!StrokeColor.isEmpty())
205
                                        m_glyphBuffer += StrokeColor;
21107 craig 206
 
21563 jghali 207
                                if (!FillColor.isEmpty())
208
                                        m_glyphBuffer += FillColor;
21107 craig 209
 
21563 jghali 210
                                m_glyphBuffer += "0 Tr\n";
21107 craig 211
 
21563 jghali 212
                                transform.translate(x() + gl.xoffset + current_x , y() + gl.yoffset);
213
                                transform.scale(qMax(gl.scaleH, 0.1), qMax(gl.scaleV, 0.1));
214
                                m_glyphBuffer += transformToStr(transform) + " Tm\n";
21107 craig 215
 
216
 
21563 jghali 217
                                if (pdfFont.method != Use_Type3 || !FillColor.isEmpty())
21107 craig 218
                                {
21563 jghali 219
                                        switch (pdfFont.encoding)
21107 craig 220
                                        {
21563 jghali 221
                                        case Encode_224:
222
                                        case Encode_256:
223
                                                m_glyphBuffer += Pdf::toHexString8(gid) + " Tj\n";
224
                                                break;
225
                                        case Encode_IdentityH:
226
                                        default:
227
                                                m_glyphBuffer += Pdf::toHexString16(gid) + " Tj\n";
228
                                                break;
21107 craig 229
                                        }
230
                                }
231
                        }
21563 jghali 232
                        current_x += gl.xadvance;
21107 craig 233
                }
21563 jghali 234
        }
21107 craig 235
 
21563 jghali 236
        void drawGlyphOutline(const GlyphCluster& gc, bool fill)
237
        {
238
                if (gc.isControlGlyphs() || gc.isEmpty())
239
                        return;
21107 craig 240
 
21563 jghali 241
                double current_x = 0.0;
242
                foreach (const GlyphLayout& gl, gc.glyphs()) {
243
                        PdfFont pdfFont = m_pdf->UsedFontsP[font().replacementName()];
244
                        QByteArray StrokeColor;
245
                        QByteArray FillColor;
246
                        QTransform transform = matrix();
21107 craig 247
 
21563 jghali 248
                        if (strokeColor().color != CommonStrings::None)
249
                                StrokeColor = m_pdf->putColor(strokeColor().color, strokeColor().shade, false);
250
                        if (fill && fillColor().color != CommonStrings::None)
251
                                FillColor = m_pdf->putColor(fillColor().color, fillColor().shade, true);
21107 craig 252
 
21563 jghali 253
                        if (pdfFont.method == Use_XForm)
254
                        {
255
                                if (!StrokeColor.isEmpty())
256
                                {
257
                                        m_pathBuffer += FToStr(strokeWidth() / fontSize()) + " w\n[] 0 d\n0 J\n0 j\n";
258
                                        m_pathBuffer += StrokeColor;
259
                                }
21107 craig 260
 
21563 jghali 261
                                if (!FillColor.isEmpty())
262
                                        m_pathBuffer += FillColor;
263
 
21107 craig 264
                                m_pathBuffer += "q\n";
265
                                m_pathBuffer += transformToStr(transform) + " cm\n";
21563 jghali 266
                                m_pathBuffer += FToStr(fontSize()) + " 0 0 " + FToStr(fontSize()) + " " + FToStr(x() + gl.xoffset) + " " + FToStr((y() - fontSize() + gl.yoffset) * -1) + " cm\n";
21107 craig 267
 
21563 jghali 268
                                if (gc.scaleV() != 1.0)
269
                                        m_pathBuffer += "1 0 0 1 0 " + FToStr(((fontSize() - fontSize() * (gc.scaleV())) / fontSize()) * -1) + " cm\n";
270
 
271
                                m_pathBuffer += FToStr(qMax(gc.scaleH(), 0.1)) + " 0 0 " + FToStr(qMax(gc.scaleV(), 0.1)) + " 0 0 cm\n";
272
 
273
                                if (!FillColor.isEmpty())
274
                                        m_pathBuffer += pdfFont.name + Pdf::toPdf(gl.glyph) + " Do\n";
275
 
21107 craig 276
                                FPointArray outline = font().glyphOutline(gl.glyph);
277
                                QTransform mat;
278
                                mat.scale(0.1, 0.1);
279
                                outline.map(mat);
280
                                bool nPath = true;
281
                                FPoint np;
282
                                if (outline.size() > 3)
283
                                {
284
                                        for (int poi = 0; poi < outline.size() - 3; poi += 4)
285
                                        {
286
                                                if (outline.isMarker(poi))
287
                                                {
288
                                                        m_pathBuffer += "h\n";
289
                                                        nPath = true;
290
                                                        continue;
291
                                                }
292
 
293
                                                if (nPath)
294
                                                {
295
                                                        np = outline.point(poi);
296
                                                        m_pathBuffer += FToStr(np.x()) + " " + FToStr(-np.y()) + " m\n";
297
                                                        nPath = false;
298
                                                }
299
 
300
                                                np = outline.point(poi + 1);
301
                                                m_pathBuffer += FToStr(np.x()) + " " + FToStr(-np.y()) + " ";
302
                                                np = outline.point(poi + 3);
303
                                                m_pathBuffer += FToStr(np.x()) + " " + FToStr(-np.y()) + " ";
304
                                                np = outline.point(poi + 2);
305
                                                m_pathBuffer += FToStr(np.x()) + " " + FToStr(-np.y()) + " c\n";
306
                                        }
307
                                }
308
                                m_pathBuffer += "h s\n";
309
                                m_pathBuffer += "Q\n";
310
                        }
311
                        else
312
                        {
21563 jghali 313
                                if (!StrokeColor.isEmpty())
314
                                        m_pathBuffer += StrokeColor;
21107 craig 315
 
21563 jghali 316
                                uint gid = gl.glyph;
317
                                uint fontNr = 65535;
21107 craig 318
                                switch (pdfFont.encoding)
319
                                {
21563 jghali 320
                                case  Encode_256:
321
                                        gid = pdfFont.glyphmap[gid];
322
                                        fontNr = gid / 256;
323
                                        gid = gid % 256;
324
                                        break;
21107 craig 325
                                case Encode_224:
21563 jghali 326
                                        fontNr = gid / 224;
327
                                        gid = gid % 224 + 32;
21107 craig 328
                                        break;
21563 jghali 329
                                case Encode_Subset:
330
                                        gid = pdfFont.glyphmap[gid];
331
                                        break;
21107 craig 332
                                case Encode_IdentityH:
333
                                        break;
334
                                }
21563 jghali 335
 
336
                                if (fontNr == 65535)
337
                                        m_glyphBuffer += pdfFont.name + " " + FToStr(fontSize()) + " Tf\n";
338
                                else
339
                                        m_glyphBuffer += pdfFont.name + "S" + Pdf::toPdf(fontNr) + " " + FToStr(fontSize()) + " Tf\n";
340
 
341
                                if (!StrokeColor.isEmpty())
342
                                        m_glyphBuffer += StrokeColor;
343
 
344
                                if (!FillColor.isEmpty())
345
                                        m_glyphBuffer += FillColor;
346
 
347
                                if (pdfFont.method == Use_Type3 && !StrokeColor.isEmpty())
348
                                {
349
                                        m_pathBuffer += "q\n";
350
                                        m_pathBuffer += FToStr(strokeWidth()) + " w\n[] 0 d\n0 J\n0 j\n";
351
 
352
                                        transform.scale(fontSize(), fontSize());
353
                                        transform.translate(x() + gl.xoffset + current_x, y() + gl.yoffset);
354
                                        if (gc.scaleV() != 1.0)
355
                                                transform.translate(0, ((fontSize() - fontSize() * gc.scaleV()) / fontSize()) * -1);
356
                                        transform.scale(qMax(gc.scaleH(), 0.1), qMax(gc.scaleV(), 0.1));
357
                                        m_pathBuffer += transformToStr(transform) + " cm\n";
358
 
359
                                        /* paint outline */
360
                                        FPointArray outline = font().glyphOutline(gl.glyph);
361
                                        QTransform mat;
362
                                        mat.scale(0.1, 0.1);
363
                                        outline.map(mat);
364
                                        bool nPath = true;
365
                                        FPoint np;
366
                                        if (outline.size() > 3)
367
                                        {
368
                                                for (int poi = 0; poi < outline.size() - 3; poi += 4)
369
                                                {
370
                                                        if (outline.isMarker(poi))
371
                                                        {
372
                                                                m_pathBuffer += "h\n";
373
                                                                nPath = true;
374
                                                                continue;
375
                                                        }
376
 
377
                                                        if (nPath)
378
                                                        {
379
                                                                np = outline.point(poi);
380
                                                                m_pathBuffer += FToStr(np.x()) + " " + FToStr(-np.y()) + " m\n";
381
                                                                nPath = false;
382
                                                        }
383
 
384
                                                        np = outline.point(poi + 1);
385
                                                        m_pathBuffer += FToStr(np.x()) + " " + FToStr(-np.y()) + " ";
386
                                                        np = outline.point(poi + 3);
387
                                                        m_pathBuffer += FToStr(np.x()) + " " + FToStr(-np.y()) + " ";
388
                                                        np = outline.point(poi + 2);
389
                                                        m_pathBuffer += FToStr(np.x()) + " " + FToStr(-np.y()) + " c\n";
390
                                                }
391
                                        }
392
                                        m_pathBuffer += "h s\n";
393
                                        m_pathBuffer += "Q\n";
394
                                }
395
                                else
396
                                {
397
                                        m_glyphBuffer += FToStr(strokeWidth()) + " w ";
398
                                        if (fill)
399
                                                m_glyphBuffer += "2 Tr\n";
400
                                        else
401
                                                m_glyphBuffer += "1 Tr\n";
402
                                }
403
 
404
                                transform.translate(x() + gl.xoffset + current_x, y() + gl.yoffset);
405
                                transform.scale(qMax(gc.scaleH(), 0.1), qMax(gc.scaleV(), 0.1));
406
                                m_glyphBuffer += transformToStr(transform) + " Tm\n";
407
 
408
                                if (pdfFont.method != Use_Type3 || !FillColor.isEmpty())
409
                                {
410
                                        switch (pdfFont.encoding)
411
                                        {
412
                                        case Encode_224:
413
                                        case Encode_256:
414
                                                m_glyphBuffer += Pdf::toHexString8(gid) + " Tj\n";
415
                                                break;
416
                                        case Encode_IdentityH:
417
                                        default:
418
                                                m_glyphBuffer += Pdf::toHexString16(gid) + " Tj\n";
419
                                                break;
420
                                        }
421
                                }
21107 craig 422
                        }
21563 jghali 423
                        current_x += gl.xadvance;
21107 craig 424
                }
425
        }
426
 
427
        void drawLine(QPointF start, QPointF end)
428
        {
429
                QTransform transform = matrix();
430
                transform.translate(x(), y());
431
                m_pathBuffer += "q\n";
432
                m_pathBuffer += transformToStr(transform) + " cm\n";
433
                m_pathBuffer += m_pdf->putColor(strokeColor().color, strokeColor().shade, false);
434
                m_pathBuffer += FToStr(strokeWidth())+" w\n";
435
                m_pathBuffer += FToStr(start.x()) + " " + FToStr(-start.y()) + " m\n";
436
                m_pathBuffer += FToStr(end.x()) + " " + FToStr(-end.y()) + " l\n";
437
                m_pathBuffer += "S\n";
438
                m_pathBuffer += "Q\n";
439
        }
440
 
441
        QByteArray getBuffer()
442
        {
443
                return "BT\n" + m_glyphBuffer + "ET\n" + m_pathBuffer;
444
        }
445
 
446
        void drawRect(QRectF rect)
447
        {
448
                QTransform transform = matrix();
449
//              transform.translate(x(), y());
450
                double rectX = x() + rect.x();
451
                double rectY = -y() - rect.y();
452
                m_glyphBuffer += "q\n";
453
                m_glyphBuffer += transformToStr(transform) + " cm\n";
454
                m_glyphBuffer += "n\n";
455
                m_glyphBuffer += m_pdf->putColor(fillColor().color, fillColor().shade, true);
456
                m_glyphBuffer += m_pdf->putColor(strokeColor().color, strokeColor().shade, false);
457
                m_glyphBuffer += FToStr(rectX) + " " + FToStr(rectY) + " m\n";
458
                m_glyphBuffer += FToStr(rectX + rect.width()) + " " + FToStr(rectY) + " l\n";
459
                m_glyphBuffer += FToStr(rectX + rect.width()) + " " + FToStr(rectY - rect.height()) + " l\n";
460
                m_glyphBuffer += FToStr(rectX) + " " + FToStr(rectY - rect.height()) + " l\n";
461
                m_glyphBuffer += "h\nf\n";
462
                m_glyphBuffer += "Q\n";
463
        }
464
 
465
        void drawObject(PageItem* embedded)
466
        {
467
                m_glyphBuffer += "ET\n"+m_pathBuffer;
468
                m_pathBuffer = "";
469
 
470
                m_pathBuffer += "q\n";
21301 fschmid 471
                m_pathBuffer += FToStr(scaleH()) + " 0 0 " + FToStr(scaleV()) + " " + FToStr(x() + embedded->gXpos) + " " + FToStr(-(y() + embedded->gYpos)) + " cm\n";
21107 craig 472
 
473
                QByteArray output;
474
                if (!m_pdf->PDF_ProcessItem(output, embedded, m_page, m_PNr, true))
475
                        return;
476
                m_pathBuffer += output;
477
                m_pathBuffer += "Q\n";
478
                m_glyphBuffer += m_pathBuffer+"\n";
479
                m_pathBuffer = "";
480
 
481
                m_glyphBuffer += "BT\n";
482
        }
483
};
484
 
10054 craig 485
PDFLibCore::PDFLibCore(ScribusDoc & docu)
4264 craig 486
        : QObject(&docu),
4223 craig 487
        doc(docu),
488
        ActPageP(0),
14925 cbradney 489
        Options(doc.pdfOptions()),
4223 craig 490
        Bvie(0),
19114 avox 491
        ucs2Codec(0),
20103 avox 492
//      ObjCounter(7),
4223 craig 493
        ResNam("RE"),
494
        ResCount(0),
495
        NDnam("LI"),
496
        NDnum(0),
20103 avox 497
//      KeyGen(""),
498
//      OwnerKey(""),
499
//      UserKey(""),
500
//      FileID(""),
501
//      EncryKey(""),
502
//      Encrypt(0),
503
//      KeyLen(5),
4223 craig 504
        colorsToUse(),
505
        spotNam("Spot"),
506
        spotCount(0),
4225 craig 507
        progressDialog(0),
4223 craig 508
        abortExport(false),
20089 jghali 509
        usingGUI(ScCore->usingGUI()),
510
        bleedDisplacementX(0),
511
        bleedDisplacementY(0)
3133 fschmid 512
{
20103 avox 513
//      KeyGen.resize(32);
514
//      OwnerKey.resize(32);
515
//      UserKey.resize(32);
516
//      FileID.resize(16);
517
//      EncryKey.resize(5);
3133 fschmid 518
        Catalog.Outlines = 2;
519
        Catalog.PageTree = 3;
520
        Catalog.Dest = 4;
521
        PageTree.Count = 0;
522
        Outlines.First = 0;
523
        Outlines.Last = 0;
524
        Outlines.Count = 0;
20103 avox 525
        pageData.ObjNum = 0;
526
        pageData.Thumb = 0;
527
//      int kg_array[] = {0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, 0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa,
528
//                        0x01, 0x08, 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80, 0x2f, 0x0c, 0xa9, 0xfe,
529
//                        0x64, 0x53, 0x69, 0x7a};
530
//      for (int a = 0; a < 32; ++a)
531
//              KeyGen[a] = kg_array[a];
4028 cbradney 532
        if (usingGUI)
533
        {
10508 cbradney 534
                progressDialog = new MultiProgressDialog( tr("Saving PDF"), CommonStrings::tr_Cancel, doc.scMW());
4224 craig 535
                Q_CHECK_PTR(progressDialog);
536
                QStringList barNames, barTexts;
537
                barNames << "EMP" << "EP" << "ECPI";
5370 cbradney 538
                barTexts << tr("Exporting Master Page:") << tr("Exporting Page:") << tr("Exporting Items on Current Page:");
9803 fschmid 539
                QList<bool> barsNumeric;
5370 cbradney 540
                barsNumeric << true << true << false;
541
                progressDialog->addExtraProgressBars(barNames, barTexts, barsNumeric);
8559 subik 542
                connect(progressDialog, SIGNAL(canceled()), this, SLOT(cancelRequested()));
4028 cbradney 543
        }
3133 fschmid 544
}
545
 
10054 craig 546
PDFLibCore::~PDFLibCore()
4224 craig 547
{
548
        delete progressDialog;
549
}
550
 
4229 craig 551
 
19115 avox 552
bool PDFLibCore::PDF_IsPDFX()
553
{
554
        if (Options.Version == PDFOptions::PDFVersion_X1a)
555
                return true;
556
        if (Options.Version == PDFOptions::PDFVersion_X3)
557
                return true;
558
        if (Options.Version == PDFOptions::PDFVersion_X4)
559
                return true;
560
        return false;
561
}
562
 
563
bool PDFLibCore::PDF_IsPDFX(PDFOptions::PDFVersion ver)
564
{
565
        if (ver == PDFOptions::PDFVersion_X1a)
566
                return true;
567
        if (ver == PDFOptions::PDFVersion_X3)
568
                return true;
569
        if (ver == PDFOptions::PDFVersion_X4)
570
                return true;
571
        return false;
572
}
573
 
10054 craig 574
bool PDFLibCore::doExport(const QString& fn, const QString& nam, int Components,
4264 craig 575
                                          const std::vector<int> & pageNs, const QMap<int,QPixmap> & thumbs)
3133 fschmid 576
{
577
        QPixmap pm;
11060 jghali 578
        bool ret = false, error = false;
579
        int  pc_exportpages=0;
580
        int  pc_exportmasterpages=0;
4224 craig 581
        if (usingGUI)
582
                progressDialog->show();
5387 avox 583
        QMap<QString, QMap<uint, FPointArray> > usedFonts;
584
        usedFonts.clear();
585
        doc.getUsedFonts(usedFonts);
19114 avox 586
        ucs2Codec = QTextCodec::codecForName("ISO-10646-UCS-2");
17758 jghali 587
        if (!ucs2Codec)
19114 avox 588
                ucs2Codec = QTextCodec::codecForName("UTF-16");
589
        if (!ucs2Codec)
13764 jghali 590
        {
13791 pierre 591
                PDF_Error( tr("Qt build miss both \"UTF-16\" and \"ISO-10646-UCS-2\" text codecs, pdf export is not possible") );
13764 jghali 592
                return false;
593
        }
13955 cbradney 594
        if (PDF_Begin_Doc(fn, PrefsManager::instance()->appPrefs.fontPrefs.AvailFonts, usedFonts, doc.scMW()->bookmarkPalette->BView))
3133 fschmid 595
        {
596
                QMap<int, int> pageNsMpa;
597
                for (uint a = 0; a < pageNs.size(); ++a)
598
                {
14653 jghali 599
                        pageNsMpa.insert(doc.MasterNames[doc.DocPages.at(pageNs[a]-1)->MPageNam], 0);
3133 fschmid 600
                }
4028 cbradney 601
                if (usingGUI)
3133 fschmid 602
                {
4028 cbradney 603
                        progressDialog->setOverallTotalSteps(pageNsMpa.count()+pageNs.size());
604
                        progressDialog->setTotalSteps("EMP", pageNsMpa.count());
605
                        progressDialog->setTotalSteps("EP", pageNs.size());
606
                        progressDialog->setOverallProgress(0);
607
                        progressDialog->setProgress("EMP", 0);
608
                        progressDialog->setProgress("EP", 0);
609
                }
10018 fschmid 610
                for (int ap = 0; ap < doc.MasterPages.count() && !abortExport; ++ap)
4028 cbradney 611
                {
4264 craig 612
                        if (doc.MasterItems.count() != 0)
3133 fschmid 613
                        {
614
                                if (pageNsMpa.contains(ap))
615
                                {
5243 cbradney 616
                                        qApp->processEvents();
11060 jghali 617
                                        if (!PDF_TemplatePage(doc.MasterPages.at(ap)))
618
                                                error = abortExport = true;
4028 cbradney 619
                                        ++pc_exportmasterpages;
3133 fschmid 620
                                }
621
                        }
4546 subik 622
                        if (usingGUI)
623
                        {
4028 cbradney 624
                                progressDialog->setProgress("EMP", pc_exportmasterpages);
625
                                progressDialog->setOverallProgress(pc_exportmasterpages+pc_exportpages);
626
                        }
3133 fschmid 627
                }
4028 cbradney 628
                for (uint a = 0; a < pageNs.size() && !abortExport; ++a)
3133 fschmid 629
                {
14925 cbradney 630
                        if (doc.pdfOptions().Thumbnails)
3133 fschmid 631
                                pm = thumbs[pageNs[a]];
5243 cbradney 632
                        qApp->processEvents();
4028 cbradney 633
                        if (abortExport) break;
11060 jghali 634
 
14653 jghali 635
                        PDF_Begin_Page(doc.DocPages.at(pageNs[a]-1), pm);
5243 cbradney 636
                        qApp->processEvents();
4028 cbradney 637
                        if (abortExport) break;
11060 jghali 638
 
14925 cbradney 639
                        if (!PDF_ProcessPage(doc.DocPages.at(pageNs[a]-1), pageNs[a]-1, doc.pdfOptions().doClip))
11060 jghali 640
                                error = abortExport = true;
5243 cbradney 641
                        qApp->processEvents();
4028 cbradney 642
                        if (abortExport) break;
11060 jghali 643
 
15444 craig 644
                        PDF_End_Page(a);
4028 cbradney 645
                        pc_exportpages++;
646
                        if (usingGUI)
647
                        {
648
                                progressDialog->setProgress("EP", pc_exportpages);
649
                                progressDialog->setOverallProgress(pc_exportmasterpages+pc_exportpages);
650
                        }
3133 fschmid 651
                }
20681 craig 652
                ret = true;//Even when aborting we return true. Don't want that "couldnt write msg"
4028 cbradney 653
                if (!abortExport)
654
                {
19115 avox 655
                        if (PDF_IsPDFX(doc.pdfOptions().Version))
14925 cbradney 656
                                ret = PDF_End_Doc(ScCore->PrinterProfiles[doc.pdfOptions().PrintProf], nam, Components);
4028 cbradney 657
                        else
12387 jghali 658
                                ret = PDF_End_Doc();
4028 cbradney 659
                }
3133 fschmid 660
                else
4028 cbradney 661
                        closeAndCleanup();
3133 fschmid 662
        }
4029 cbradney 663
        if (usingGUI)
664
                progressDialog->close();
11060 jghali 665
        return (ret && !error);
3133 fschmid 666
}
667
 
11060 jghali 668
const QString& PDFLibCore::errorMessage(void) const
669
{
670
        return ErrorMessage;
671
}
672
 
11441 jghali 673
bool PDFLibCore::exportAborted(void) const
674
{
675
        return abortExport;
676
}
677
 
20103 avox 678
//#define StartObj(n) writer.startObj((n))
679
#define PutDoc(s) writer.write(s)
680
//#define newObject() writer.newObject()
3133 fschmid 681
 
682
 
20103 avox 683
//void PDFLibCore::StartObj(PdfId nr)
684
//{
685
//      for (int i=XRef.size(); i < nr; ++i)
686
//              XRef.append(0);
687
//      XRef[nr-1] = bytesWritten();
688
//      PutDoc(Pdf::toPdf(nr)+ " 0 obj\n");
689
//}
690
 
691
//// Encode a string for inclusion in a
692
//// PDF (literal) .
693
//static QByteArray PDFEncode(const QString & in)
694
//{
695
//      QByteArray tmp("");
696
//      for (int d = 0; d < in.length(); ++d)
697
//      {
698
//              QChar cc(in.at(d));
699
//              if ((cc == '(') || (cc == ')') || (cc == '\\'))
700
//                      tmp += '\\';
701
//              else if ((cc == '\r') || (cc == '\n'))
702
//              {
703
//                      tmp += (cc == '\r') ? "\\r" : "\\n";
704
//                      continue;
705
//              }
706
//              tmp += cc;
707
//      }
708
//      return tmp;
709
//}
710
 
711
static QByteArray blendMode(int code)
12080 avox 712
{
713
        switch (code)
714
        {
715
                case 0:
716
                        return("Normal");
717
                        break;
718
                case 1:
719
                        return("Darken");
720
                        break;
721
                case 2:
722
                        return("Lighten");
723
                        break;
724
                case 3:
725
                        return("Multiply");
726
                        break;
727
                case 4:
728
                        return("Screen");
729
                        break;
730
                case 5:
731
                        return("Overlay");
732
                        break;
733
                case 6:
734
                        return("HardLight");
735
                        break;
736
                case 7:
737
                        return("SoftLight");
738
                        break;
739
                case 8:
740
                        return("Difference");
741
                        break;
742
                case 9:
743
                        return("Exclusion");
744
                        break;
745
                case 10:
746
                        return("ColorDodge");
747
                        break;
748
                case 11:
749
                        return("ColorBurn");
750
                        break;
751
                case 12:
752
                        return("Hue");
753
                        break;
754
                case 13:
755
                        return("Saturation");
756
                        break;
757
                case 14:
758
                        return("Color");
759
                        break;
760
                case 15:
761
                        return("Luminosity");
762
                        break;
763
                default:
764
                        return "";
765
        }
14043 jghali 766
}
20103 avox 767
//
768
//QByteArray PDFLibCore::EncodeUTF16(const QString &in)
769
//{
770
//      QString tmp = in;
771
//      QByteArray cres = ucs2Codec->fromUnicode( tmp );
772
//#ifndef WORDS_BIGENDIAN
773
//      // on little endian systems we need to swap bytes:
774
//      uchar sw;
775
//      for(int d = 0; d < cres.size()-1; d += 2)
776
//      {
777
//              sw = cres[d];
778
//              cres[d] = cres[d+1];
779
//              cres[d+1] = sw;
780
//      }
781
//#endif
782
//      return cres;
783
//}
12080 avox 784
 
20103 avox 785
QByteArray PDFLibCore::EncStream(const QByteArray & in, PdfId ObjNum)
19114 avox 786
{
787
        if (in.length() < 1)
20103 avox 788
                return QByteArray();
19114 avox 789
        else if (!Options.Encrypt)
790
                return in;
20112 jghali 791
        else
792
                return writer.encryptBytes(in, ObjNum);
20103 avox 793
//      rc4_context_t rc4;
794
//      QByteArray tmp(in);
795
//      QByteArray us(tmp.length(), ' ');
796
//      QByteArray ou(tmp.length(), ' ');
797
//      for (int a = 0; a < tmp.length(); ++a)
20112 jghali 798
//              us[a] = (tmp.at(a));
799
//      QByteArray step1 = writer.ComputeRC4Key(ObjNum);
20103 avox 800
//      rc4_init(&rc4, reinterpret_cast<uchar*>(step1.data()), qMin(KeyLen+5, 16));
801
//      rc4_encrypt(&rc4, reinterpret_cast<uchar*>(us.data()), reinterpret_cast<uchar*>(ou.data()), tmp.length());
802
//      QString uk = "";
803
//      for (int cl = 0; cl < tmp.length(); ++cl)
804
//              uk += QChar(ou[cl]);
805
//      return ou;
19114 avox 806
}
807
 
20103 avox 808
QByteArray PDFLibCore::EncString(const QByteArray & in, PdfId ObjNum)
19114 avox 809
{
20103 avox 810
        QByteArray tmp;
19114 avox 811
        if (in.length() < 1)
812
                return "<>";
813
        if (!Options.Encrypt)
814
        {
20103 avox 815
                //tmp = "(" + PDFEncode(in) + ")";
20112 jghali 816
                return Pdf::toLiteralString(in);
19114 avox 817
        }
20112 jghali 818
 
20103 avox 819
//      rc4_context_t rc4;
820
//      QByteArray us(in.length(), ' ');
821
//      QByteArray ou(in.length(), ' ');
822
//      for (int a = 0; a < in.length(); ++a)
823
//              us[a] = static_cast<uchar>(QChar(in.at(a)).cell());
824
//      QByteArray step1 = writer.ComputeRC4Key(ObjNum);
825
//      rc4_init(&rc4, reinterpret_cast<uchar*>(step1.data()), qMin(KeyLen+5, 16));
826
//      rc4_encrypt(&rc4, reinterpret_cast<uchar*>(us.data()), reinterpret_cast<uchar*>(ou.data()), in.length());
827
//      QString uk = "";
828
//      for (int cl = 0; cl < in.length(); ++cl)
829
//              uk += QChar(ou[cl]);
20112 jghali 830
 
831
        return Pdf::toHexString(writer.encryptBytes(in, ObjNum));
19114 avox 832
}
833
 
20103 avox 834
QByteArray PDFLibCore::EncStringUTF16(const QString & in, PdfId ObjNum)
19114 avox 835
{
836
        if (in.length() < 1)
837
                return "<>";
838
        if (!Options.Encrypt)
839
        {
20112 jghali 840
                QByteArray us = Pdf::toUTF16(in);
20103 avox 841
//              QString uk = "";
842
//              for (int cl = 0; cl < us.size(); ++cl)
843
//                      uk += QChar(us[cl]);
844
                return Pdf::toHexString(us);
19114 avox 845
        }
20103 avox 846
//      rc4_context_t rc4;
20112 jghali 847
        QByteArray us = Pdf::toUTF16(in);
20103 avox 848
//      QByteArray ou(us.size(), ' ');
849
//      QByteArray step1 = writer.ComputeRC4Key(ObjNum);
850
//      rc4_init(&rc4, reinterpret_cast<uchar*>(step1.data()), qMin(KeyLen+5, 16));
851
//      rc4_encrypt(&rc4, reinterpret_cast<uchar*>(us.data()), reinterpret_cast<uchar*>(ou.data()), ou.size());
852
//      QString uk = "";
853
//      for (int cl = 0; cl < ou.size(); ++cl)
854
//              uk += QChar(ou[cl]);
855
        QByteArray tmp = Pdf::toHexString(writer.encryptBytes(us, ObjNum));
19114 avox 856
        return tmp;
857
}
858
 
20103 avox 859
bool PDFLibCore::EncodeArrayToStream(const QByteArray& in, PdfId ObjNum)
19114 avox 860
{
861
        if (in.size() < 1)
862
                return true;
863
        bool succeed = false;
864
        if (Options.Encrypt)
865
        {
20103 avox 866
                ScStreamFilter* rc4Encode = writer.openStreamFilter(true, ObjNum);
867
                if (rc4Encode->openFilter())
19114 avox 868
                {
20103 avox 869
                        succeed  = rc4Encode->writeData(in.data(), in.size());
870
                        succeed &= rc4Encode->closeFilter();
19114 avox 871
                }
20112 jghali 872
                delete rc4Encode;
19114 avox 873
        }
874
        else
20103 avox 875
                writer.write(in);
876
        return (writer.getOutStream().status() == QDataStream::Ok);
19114 avox 877
}
878
 
20103 avox 879
int PDFLibCore::WriteImageToStream(ScImage& image, PdfId ObjNum, ColorSpaceEnum format, bool precal)
11599 jghali 880
{
17758 jghali 881
        bool fromCmyk, succeed = false;
11599 jghali 882
        int  bytesWritten = 0;
20103 avox 883
 
20112 jghali 884
        ScStreamFilter* rc4Encode = writer.openStreamFilter(Options.Encrypt, ObjNum);
885
        if (rc4Encode->openFilter())
886
        {
887
                switch (format)
888
                {
889
                        case ColorSpaceMonochrome :
890
                                fromCmyk = !Options.UseRGB && !Options.isGrayscale && !(doc.HasCMS && Options.UseProfiles2);
891
                                succeed = image.writeMonochromeDataToFilter(rc4Encode, fromCmyk); break;
892
                        case ColorSpaceGray :
893
                                succeed = image.writeGrayDataToFilter(rc4Encode, precal); break;
894
                        case ColorSpaceCMYK :
895
                                succeed = image.writeCMYKDataToFilter(rc4Encode); break;
896
                        default :
897
                                succeed = image.writeRGBDataToFilter(rc4Encode); break;
898
                }
899
                succeed &= rc4Encode->closeFilter();
900
                bytesWritten = rc4Encode->writtenToStream();
901
                delete rc4Encode;
902
        }
11599 jghali 903
        return (succeed ? bytesWritten : 0);
904
}
905
 
20103 avox 906
int PDFLibCore::WriteJPEGImageToStream(ScImage& image, const QString& fn, PdfId ObjNum, int quality, ColorSpaceEnum format,
17758 jghali 907
                                                                                 bool sameFile, bool precal)
11599 jghali 908
{
909
        bool succeed = true;
910
        int  bytesWritten = 0;
911
        QFileInfo fInfo(fn);
912
        QString   ext = fInfo.suffix().toLower();
913
        QString   jpgFileName, tmpFile;
914
        if (extensionIndicatesJPEG(ext) && sameFile)
915
                jpgFileName = fn;
11445 jghali 916
        else
11599 jghali 917
        {
21526 craig 918
                tmpFile  = QDir::toNativeSeparators(ScPaths::tempFileDir() + "sc.jpg");
17758 jghali 919
                if (format == ColorSpaceGray && (!precal))
11599 jghali 920
                        image.convertToGray();
17758 jghali 921
                if (image.convert2JPG(tmpFile, quality, format == ColorSpaceCMYK, format == ColorSpaceGray))
11599 jghali 922
                        jpgFileName = tmpFile;
923
        }
924
        if (jpgFileName.isEmpty())
11792 fschmid 925
                return 0;
11599 jghali 926
        if (Options.Encrypt)
927
        {
928
                succeed = false;
20112 jghali 929
                ScStreamFilter* rc4Encode = writer.openStreamFilter(true, ObjNum);
930
                if (rc4Encode->openFilter())
11599 jghali 931
                {
20103 avox 932
                        succeed  = copyFileToFilter(jpgFileName, *rc4Encode);
933
                        succeed &= rc4Encode->closeFilter();
934
                        bytesWritten = rc4Encode->writtenToStream();
11599 jghali 935
                }
20112 jghali 936
                delete rc4Encode;
11599 jghali 937
        }
938
        else
939
        {
20103 avox 940
                succeed &= copyFileToStream(jpgFileName, writer.getOutStream());
11599 jghali 941
                QFileInfo jpgInfo(jpgFileName);
942
                bytesWritten = jpgInfo.size();
943
        }
944
        if (!tmpFile.isEmpty() && QFile::exists(tmpFile))
945
                QFile::remove(tmpFile);
946
        return (succeed ? bytesWritten : 0);
11445 jghali 947
}
948
 
20103 avox 949
int PDFLibCore::WriteFlateImageToStream(ScImage& image, PdfId ObjNum, ColorSpaceEnum format, bool precal)
11599 jghali 950
{
20112 jghali 951
        bool fromCmyk, succeed = false;
952
        int  bytesWritten = 0;
953
        ScStreamFilter* rc4Encode = writer.openStreamFilter(Options.Encrypt, ObjNum);
954
        ScFlateEncodeFilter flateEncode(rc4Encode);
955
        if (flateEncode.openFilter())
956
        {
957
                switch (format)
958
                {
959
                        case ColorSpaceMonochrome :
960
                                fromCmyk = !Options.UseRGB && !Options.isGrayscale && !(doc.HasCMS && Options.UseProfiles2);
961
                                succeed = image.writeMonochromeDataToFilter(&flateEncode, fromCmyk); break;
962
                        case ColorSpaceGray :
963
                                succeed = image.writeGrayDataToFilter(&flateEncode, precal); break;
964
                        case ColorSpaceCMYK :
965
                                succeed = image.writeCMYKDataToFilter(&flateEncode); break;
966
                        default :
967
                                succeed = image.writeRGBDataToFilter(&flateEncode); break;
968
                }
969
                succeed &= flateEncode.closeFilter();
970
                bytesWritten = flateEncode.writtenToStream();
971
        }
972
        delete rc4Encode;
973
        return (succeed ? bytesWritten : 0);
11599 jghali 974
}
975
 
3133 fschmid 976
 
19114 avox 977
 
20103 avox 978
bool PDFLibCore::PDF_Begin_Doc(const QString& fn, SCFonts &AllFonts, const QMap<QString, QMap<uint, FPointArray> >& DocFonts, BookMView* vi)
19114 avox 979
{
20112 jghali 980
        if (!writer.open(fn))
981
                return false;
982
 
983
        QFileInfo fiBase(fn);
984
        QString baseDir = fiBase.absolutePath();
19114 avox 985
 
20103 avox 986
//      QString tmp;
987
//      QFileInfo fd;
988
//      QString fext;
6407 fschmid 989
        inPattern = 0;
3133 fschmid 990
        Bvie = vi;
991
        BookMinUse = false;
992
        UsedFontsP.clear();
8454 fschmid 993
        UsedFontsF.clear();
20112 jghali 994
 
995
        writer.writeHeader(Options.Version);
996
 
20103 avox 997
//      if (((Options.Version == PDFOptions::PDFVersion_15) || (Options.Version == PDFOptions::PDFVersion_X4)) && (Options.useLayers))
998
//              ObjCounter = 10;
999
//      else
1000
//              ObjCounter = 9;
1001
//      switch (Options.Version)
1002
//      {
1003
//              case PDFOptions::PDFVersion_X1a:
1004
//              case PDFOptions::PDFVersion_X3:
1005
//              case PDFOptions::PDFVersion_13:
1006
//                      PutDoc("%PDF-1.3\n");
1007
//                      break;
1008
//              case PDFOptions::PDFVersion_14:
1009
//                      PutDoc("%PDF-1.4\n");
1010
//                      break;
1011
//              case PDFOptions::PDFVersion_X4:
1012
//              case PDFOptions::PDFVersion_15:
1013
//                      PutDoc("%PDF-1.5\n");
1014
//                      break;
1015
//      }
1016
//      if (PDF_IsPDFX())
1017
//              ObjCounter++;
1018
//      PutDoc("%\xc7\xec\x8f\xa2\n");
1019
 
20112 jghali 1020
        PDF_Begin_Catalog();
1021
        PDF_Begin_MetadataAndEncrypt();
1022
        PDF_Begin_WriteUsedFonts(AllFonts, PDF_Begin_FindUsedFonts(AllFonts, DocFonts));
1023
        PDF_Begin_Colors();
1024
        PDF_Begin_Layers();
1025
 
1026
        return true;
20103 avox 1027
}
1028
 
1029
void PDFLibCore::PDF_Begin_Catalog()
1030
{
20112 jghali 1031
        writer.startObj(writer.CatalogObj);
1032
        PutDoc("<<\n/Type /Catalog");
1033
        PutDoc("\n/Outlines " + Pdf::toObjRef(writer.OutlinesObj) +
1034
                   "\n/Pages " + Pdf::toObjRef(writer.PagesObj) +
1035
                   "\n/Dests " + Pdf::toObjRef(writer.DestsObj) +
1036
                   "\n/AcroForm " + Pdf::toObjRef(writer.AcroFormObj) +
1037
                   "\n/Names "+ Pdf::toObjRef(writer.NamesObj) +
1038
                   "\n/Threads " +  Pdf::toObjRef(writer.ThreadsObj) +
1039
                   "\n");
19114 avox 1040
        if (((Options.Version == PDFOptions::PDFVersion_15) || (Options.Version == PDFOptions::PDFVersion_X4)) && (Options.useLayers))
20112 jghali 1041
        {
1042
                writer.OCPropertiesObj = writer.newObject();
20103 avox 1043
                PutDoc("/OCProperties " + Pdf::toObjRef(writer.OCPropertiesObj) + "\n");
20112 jghali 1044
        }
1045
        if (PDF_IsPDFX())
19114 avox 1046
        {
20112 jghali 1047
                writer.OutputIntentObj = writer.newObject();
1048
                PutDoc("/OutputIntents [ " +  Pdf::toObjRef(writer.OutputIntentObj) + " ]\n");
1049
        }
1050
        if ((Options.Version == PDFOptions::PDFVersion_X4))
1051
        {
1052
                writer.MetaDataObj = writer.newObject();
20103 avox 1053
                PutDoc("/Metadata "+ Pdf::toObjRef(writer.MetaDataObj) + "\n");
19114 avox 1054
        }
1055
        PutDoc("/PageLayout ");
1056
        switch (Options.PageLayout)
1057
        {
1058
                case PDFOptions::SinglePage:
1059
                        PutDoc("/SinglePage\n");
1060
                        break;
1061
                case PDFOptions::OneColumn:
1062
                        PutDoc("/OneColumn\n");
1063
                        break;
1064
                case PDFOptions::TwoColumnLeft:
1065
                        PutDoc("/TwoColumnLeft\n");
1066
                        break;
1067
                case PDFOptions::TwoColumnRight:
1068
                        PutDoc("/TwoColumnRight\n");
1069
                        break;
1070
        }
1071
        if (Options.displayBookmarks)
1072
                PutDoc("/PageMode /UseOutlines\n");
1073
        else if (Options.displayFullscreen)
1074
                PutDoc("/PageMode /FullScreen\n");
1075
        else if (Options.displayThumbs)
1076
                PutDoc("/PageMode /UseThumbs\n");
1077
        else if ((Options.Version == PDFOptions::PDFVersion_15) && (Options.displayLayers))
1078
                        PutDoc("/PageMode /UseOC\n");
1079
        if (!Options.openAction.isEmpty())
1080
        {
20112 jghali 1081
                PutDoc("/OpenAction << /S /JavaScript /JS (this."+Pdf::toPdfDocEncoding(Options.openAction)+"\\(\\)) >>\n");
19114 avox 1082
        }
20112 jghali 1083
        QString tmp;
19114 avox 1084
        QDateTime dt = QDateTime::currentDateTime().toUTC();
20112 jghali 1085
        Datum = Pdf::toDateString(dt);
20103 avox 1086
//    "D:";
1087
//      tmp.sprintf("%4d", d.year());
1088
//      tmp.replace(QRegExp(" "), "0");
1089
//      Datum += tmp;
1090
//      tmp.sprintf("%2d", d.month());
1091
//      tmp.replace(QRegExp(" "), "0");
1092
//      Datum += tmp;
1093
//      tmp.sprintf("%2d", d.day());
1094
//      tmp.replace(QRegExp(" "), "0");
1095
//      Datum += tmp;
1096
//      tmp = dt.time().toString();
1097
//      tmp.replace(QRegExp(":"), "");
1098
//      Datum += tmp;
1099
//      Datum += "Z";
12429 fschmid 1100
 
19114 avox 1101
        // only include XMP to PDF/X-4 at the moment, could easily be extended to include it to any PDF
1102
        if (Options.Version == PDFOptions::PDFVersion_X4)
1103
                generateXMP(dt.toString("yyyy-MM-ddThh:mm:ssZ"));
1104
 
1105
/* The following code makes the resulting PDF "Reader enabled" in Acrobat Reader 8
1106
   but sadly it doesn't work with newer version, because its based on a bug in AR 8
1107
        PutDoc("/Perms\n");
1108
        PutDoc("<<\n");
1109
        PutDoc("/UR3\n");
1110
        PutDoc("<<\n");
1111
        PutDoc("/M ("+Datum+")\n");
1112
        PutDoc("/Name (Scribus "+QString(VERSION)+")\n");
1113
        PutDoc("/Reference [\n");
1114
        PutDoc("<<\n");
1115
        PutDoc("/TransformParams\n");
1116
        PutDoc("<<\n");
1117
        PutDoc("/Type /TransformParams\n");
1118
        PutDoc("/V /2.2\n");
1119
        PutDoc("/Document [/FullSave]\n");
1120
        PutDoc("/Annots [/Create/Delete/Modify/Copy/Import/Export]\n");
1121
        PutDoc("/Form [/Add/Delete/FillIn/Import/Export/SubmitStandalone/SpawnTemplate]\n");
1122
        PutDoc("/Signature [/Modify]\n");
1123
        PutDoc(">>\n");
1124
        PutDoc("/TransformMethod /UR3\n");
1125
        PutDoc("/Type /SigRef\n");
1126
        PutDoc(">>\n");
1127
        PutDoc("]\n");
1128
        PutDoc("/Type /Sig\n");
1129
        PutDoc(">>\n");
1130
        PutDoc(">>\n");
1131
*/
1132
 
1133
        PutDoc("/ViewerPreferences\n<<\n/PageDirection ");
1134
        PutDoc( Options.Binding == 0 ? "/L2R\n" : "/R2L\n");
1135
        if (Options.hideToolBar)
1136
                PutDoc("/HideToolbar true\n");
1137
        if (Options.hideMenuBar)
1138
                PutDoc("/HideMenubar true\n");
1139
        if (Options.fitWindow)
1140
                PutDoc("/FitWindow true\n");
20112 jghali 1141
        PutDoc(" >>\n>>");
1142
        writer.endObj(writer.CatalogObj);
20103 avox 1143
}
1144
 
1145
void PDFLibCore::PDF_Begin_MetadataAndEncrypt()
1146
{
19114 avox 1147
        QString IDg(Datum);
1148
        IDg += Options.fileName;
1149
        IDg += "Scribus "+QString(VERSION);
1150
        IDg += "Scribus PDF Library "+QString(VERSION);
1151
        IDg += doc.documentInfo().title();
1152
        IDg += doc.documentInfo().author();
1153
        IDg += "/False";
20112 jghali 1154
        writer.setFileId(Pdf::toPdfDocEncoding(IDg));
19114 avox 1155
        if (Options.Encrypt)
1156
        {
20112 jghali 1157
                writer.setEncryption((Options.Version == PDFOptions::PDFVersion_14) || (Options.Version == PDFOptions::PDFVersion_15), Pdf::toPdfDocEncoding(Options.PassOwner), Pdf::toPdfDocEncoding(Options.PassUser), Options.Permissions);
19114 avox 1158
        }
20103 avox 1159
        writer.startObj(writer.InfoObj);
20112 jghali 1160
        PutDoc("<<\n/Creator " + EncString(QByteArray("Scribus ") + VERSION, writer.InfoObj) + "\n");
20103 avox 1161
        PutDoc("/Producer " + EncString(QByteArray("Scribus PDF Library ") + VERSION, writer.InfoObj) + "\n");
19114 avox 1162
        QString docTitle = doc.documentInfo().title();
19115 avox 1163
        if ((PDF_IsPDFX()) && (docTitle.isEmpty()))
20103 avox 1164
                PutDoc("/Title " + EncStringUTF16(doc.DocName, writer.InfoObj) + "\n");
19114 avox 1165
        else
20103 avox 1166
                PutDoc("/Title " + EncStringUTF16(doc.documentInfo().title(), writer.InfoObj) + "\n");
1167
        PutDoc("/Author " + EncStringUTF16(doc.documentInfo().author(), writer.InfoObj) + "\n");
1168
        PutDoc("/Subject " + EncStringUTF16(doc.documentInfo().subject(), writer.InfoObj) + "\n");
1169
        PutDoc("/Keywords " + EncStringUTF16(doc.documentInfo().keywords(), writer.InfoObj) + "\n");
1170
        PutDoc("/CreationDate " + EncString(Datum, writer.InfoObj) + "\n");
1171
        PutDoc("/ModDate " + EncString(Datum, writer.InfoObj) + "\n");
19114 avox 1172
        if (Options.Version == PDFOptions::PDFVersion_X1a)
1173
        {
1174
                PutDoc("/GTS_PDFXVersion (PDF/X-1:2001)\n");
1175
                PutDoc("/GTS_PDFXConformance (PDF/X-1a:2001)\n");
1176
        }
19115 avox 1177
        if (Options.Version == PDFOptions::PDFVersion_X3)
1178
                PutDoc("/GTS_PDFXVersion (PDF/X-3:2002)\n");
19114 avox 1179
        if (Options.Version == PDFOptions::PDFVersion_X4)
1180
                PutDoc("/GTS_PDFXVersion (PDF/X-4)\n");
20112 jghali 1181
        PutDoc("/Trapped /False\n>>");
1182
        writer.endObj(writer.InfoObj);
20103 avox 1183
 
20112 jghali 1184
        // Encrypt
1185
 
1186
//      for (int t = 0; t < 6; ++t)
20103 avox 1187
//              XRef.append(bytesWritten());
1188
//      if (((Options.Version == PDFOptions::PDFVersion_15) || (Options.Version == PDFOptions::PDFVersion_X4)) && (Options.useLayers))
1189
//              XRef.append(bytesWritten());
1190
//      if (PDF_IsPDFX())
1191
//              XRef.append(bytesWritten());
1192
//      if (Options.Version == PDFOptions::PDFVersion_X4)
1193
//              XRef.append(bytesWritten());
19114 avox 1194
        if (Options.Encrypt)
20103 avox 1195
        { // now done in writer.setEncrption():
1196
//              writer.EncryptObj = writer.newObject();
1197
//              writer.startObj(writer.EncryptObj);
1198
//              PutDoc("<<\n/Filter /Standard\n");
1199
//              PutDoc( KeyLen > 5 ? "/R 3\n/V 2\n/Length 128\n" : "/R 2\n/V 1\n");
1200
//              PutDoc("/O "+Pdf::toHexString(ok)+"\n");
1201
//              PutDoc("/U "+Pdf::toHexString(uk)+"\n");
20112 jghali 1202
//              PutDoc("/P "+Pdf::toPdf(Options.Permissions)+"\n>>");
1203
//              writer.endObj(writer.EncryptObj);
19114 avox 1204
        }
20103 avox 1205
}
1206
 
1207
QMap<QString, QMap<uint, FPointArray> >
1208
PDFLibCore::PDF_Begin_FindUsedFonts(SCFonts &AllFonts, const QMap<QString, QMap<uint, FPointArray> >& DocFonts)
1209
{
5387 avox 1210
        QMap<QString, QMap<uint, FPointArray> > ReallyUsed;
3133 fschmid 1211
        ReallyUsed.clear();
1212
        PageItem* pgit;
20103 avox 1213
        QMap<int, QByteArray> ind2PDFabr;
1214
        const QByteArray tmpf[] = {"/Courier", "/Courier-Bold", "/Courier-Oblique", "/Courier-BoldOblique",
4017 fschmid 1215
                                                                                                "/Helvetica", "/Helvetica-Bold", "/Helvetica-Oblique", "/Helvetica-BoldOblique",
4546 subik 1216
                                                                                                "/Times-Roman", "/Times-Bold", "/Times-Italic", "/Times-BoldItalic",
4017 fschmid 1217
                                                                                                "/ZapfDingbats", "/Symbol"};
1218
        size_t ar = sizeof(tmpf) / sizeof(*tmpf);
1219
        for (uint ax = 0; ax < ar; ++ax)
1220
                ind2PDFabr[ax] = tmpf[ax];
21709 jghali 1221
 
1222
        QList<PageItem*> allItems = doc.FrameItems.values();
1223
        while (allItems.count() > 0)
3133 fschmid 1224
        {
21709 jghali 1225
                pgit = allItems.takeFirst();
1226
                if (pgit->isGroup() || pgit->isTable())
3133 fschmid 1227
                {
21709 jghali 1228
                        allItems = pgit->getItemList() + allItems;
1229
                        continue;
1230
                }
1231
                if ((pgit->itemType() == PageItem::TextFrame) || (pgit->itemType() == PageItem::PathText))
1232
                {
1233
                        if (pgit->isAnnotation())
17312 fschmid 1234
                        {
21709 jghali 1235
                                int annotType  = pgit->annotation().Type();
1236
                                bool mustEmbed = ((annotType >= Annotation::Button) && (annotType <= Annotation::Listbox) && (annotType != Annotation::Checkbox));
1237
                                if ((pgit->annotation().Type() == Annotation::Checkbox) || (pgit->annotation().Type() == Annotation::RadioButton))
1238
                                        StdFonts.insert("/ZapfDingbats", "");
1239
                                if (pgit->itemText.length() > 0 || mustEmbed)
17312 fschmid 1240
                                {
21709 jghali 1241
                                        if (Options.Version < PDFOptions::PDFVersion_14)
1242
                                                StdFonts.insert(ind2PDFabr[pgit->annotation().Font()], "");
21744 jghali 1243
                                        QString replacementName = pgit->itemText.defaultStyle().charStyle().font().replacementName();
1244
                                        ReallyUsed.insert(replacementName, DocFonts[replacementName]);
17312 fschmid 1245
                                }
1246
                        }
21709 jghali 1247
                        uint start = pgit->isTextFrame() ? (uint) pgit->firstInFrame() : 0;
1248
                        uint stop  = pgit->isTextFrame() ? (uint) pgit->lastInFrame() + 1 : (uint) pgit->itemText.length();
1249
                        for (uint e = start; e < stop; ++e)
8092 fschmid 1250
                        {
21709 jghali 1251
                                QString replacementName = pgit->itemText.charStyle(e).font().replacementName();
1252
                                ReallyUsed.insert(replacementName, DocFonts[replacementName]);
8092 fschmid 1253
                        }
3133 fschmid 1254
                }
1255
        }
21709 jghali 1256
 
1257
        allItems = doc.MasterItems;
1258
        while (allItems.count() > 0)
3133 fschmid 1259
        {
21709 jghali 1260
                pgit = allItems.takeFirst();
1261
                if (pgit->isGroup() || pgit->isTable())
3133 fschmid 1262
                {
21709 jghali 1263
                        allItems = pgit->getItemList() + allItems;
1264
                        continue;
1265
                }
1266
                if ((pgit->itemType() == PageItem::TextFrame) || (pgit->itemType() == PageItem::PathText))
1267
                {
1268
                        if (pgit->isAnnotation())
17312 fschmid 1269
                        {
21709 jghali 1270
                                int annotType  = pgit->annotation().Type();
1271
                                bool mustEmbed = ((annotType >= Annotation::Button) && (annotType <= Annotation::Listbox) && (annotType != Annotation::Checkbox));
1272
                                if ((pgit->annotation().Type() == Annotation::Checkbox) || (pgit->annotation().Type() == Annotation::RadioButton))
1273
                                        StdFonts.insert("/ZapfDingbats", "");
1274
                                if (pgit->itemText.length() > 0 || mustEmbed)
17312 fschmid 1275
                                {
21709 jghali 1276
                                        if (Options.Version < PDFOptions::PDFVersion_14)
1277
                                                StdFonts.insert(ind2PDFabr[pgit->annotation().Font()], "");
1278
                                        QString replacementName = pgit->itemText.defaultStyle().charStyle().font().replacementName();
1279
                                        ReallyUsed.insert(replacementName, DocFonts[replacementName]);
17312 fschmid 1280
                                }
1281
                        }
21709 jghali 1282
                        uint start = pgit->isTextFrame() ? (uint) pgit->firstInFrame() : 0;
1283
                        uint stop  = pgit->isTextFrame() ? (uint) pgit->lastInFrame() + 1 : (uint) pgit->itemText.length();
1284
                        for (uint e = start; e < stop; ++e)
8092 fschmid 1285
                        {
21709 jghali 1286
                                QString replacementName = pgit->itemText.charStyle(e).font().replacementName();
1287
                                ReallyUsed.insert(replacementName, DocFonts[replacementName]);
1288
                        }
1289
                }
1290
        }
1291
 
1292
        allItems = *(doc.Items);
1293
        while (allItems.count() > 0)
1294
        {
1295
                pgit = allItems.takeFirst();
1296
                if (pgit->isGroup() || pgit->isTable())
1297
                {
1298
                        allItems = pgit->getItemList() + allItems;
1299
                        continue;
1300
                }
1301
                if ((pgit->itemType() == PageItem::TextFrame) || (pgit->itemType() == PageItem::PathText))
1302
                {
1303
                        if (pgit->isAnnotation())
1304
                        {
1305
                                int annotType  = pgit->annotation().Type();
1306
                                bool mustEmbed = ((annotType >= Annotation::Button) && (annotType <= Annotation::Listbox) && (annotType != Annotation::Checkbox));
1307
                                if ((pgit->annotation().Type() == Annotation::Checkbox) || (pgit->annotation().Type() == Annotation::RadioButton))
1308
                                        StdFonts.insert("/ZapfDingbats", "");
1309
                                if (pgit->itemText.length() > 0 || mustEmbed)
12763 fschmid 1310
                                {
21709 jghali 1311
                                        if (Options.Version < PDFOptions::PDFVersion_14)
1312
                                                StdFonts.insert(ind2PDFabr[pgit->annotation().Font()], "");
1313
                                        QString replacementName = pgit->itemText.defaultStyle().charStyle().font().replacementName();
21707 jghali 1314
                                        ReallyUsed.insert(replacementName, DocFonts[replacementName]);
16953 fschmid 1315
                                }
8092 fschmid 1316
                        }
21709 jghali 1317
                        uint start = pgit->isTextFrame() ? (uint) pgit->firstInFrame() : 0;
1318
                        uint stop  = pgit->isTextFrame() ? (uint) pgit->lastInFrame() + 1 : (uint) pgit->itemText.length();
1319
                        for (uint e = start; e < stop; ++e)
1320
                        {
1321
                                QString replacementName = pgit->itemText.charStyle(e).font().replacementName();
1322
                                ReallyUsed.insert(replacementName, DocFonts[replacementName]);
1323
                        }
3133 fschmid 1324
                }
1325
        }
21709 jghali 1326
/*      if (Options.docInfoMarks)
3133 fschmid 1327
        {
21709 jghali 1328
                StdFonts.insert("/Helvetica", "");
1329
        } */
1330
        QStringList patterns = doc.getPatternDependencyList(doc.getUsedPatterns());
1331
        for (int c = 0; c < patterns.count(); ++c)
1332
        {
1333
                ScPattern pa = doc.docPatterns[patterns[c]];
1334
                allItems = pa.items;
1335
                while (allItems.count() > 0)
3133 fschmid 1336
                {
21709 jghali 1337
                        pgit = allItems.takeFirst();
1338
                        if (pgit->isGroup() || pgit->isTable())
17312 fschmid 1339
                        {
21709 jghali 1340
                                allItems = pgit->getItemList() + allItems;
1341
                                continue;
17312 fschmid 1342
                        }
16953 fschmid 1343
                        if ((pgit->itemType() == PageItem::TextFrame) || (pgit->itemType() == PageItem::PathText))
8092 fschmid 1344
                        {
16953 fschmid 1345
                                if (pgit->isAnnotation())
12763 fschmid 1346
                                {
17952 fschmid 1347
                                        if ((pgit->annotation().Type() == Annotation::Checkbox) || (pgit->annotation().Type() == Annotation::RadioButton))
16953 fschmid 1348
                                                StdFonts.insert("/ZapfDingbats", "");
21709 jghali 1349
                                        if (pgit->itemText.length() > 0)
16953 fschmid 1350
                                        {
1351
                                                if (Options.Version < PDFOptions::PDFVersion_14)
1352
                                                        StdFonts.insert(ind2PDFabr[pgit->annotation().Font()], "");
21707 jghali 1353
                                                QString replacementName = pgit->itemText.defaultStyle().charStyle().font().replacementName();
1354
                                                ReallyUsed.insert(replacementName, DocFonts[replacementName]);
16953 fschmid 1355
                                        }
12763 fschmid 1356
                                }
17751 jghali 1357
                                uint start = pgit->isTextFrame() ? (uint) pgit->firstInFrame() : 0;
1358
                                uint stop  = pgit->isTextFrame() ? (uint) pgit->lastInFrame() + 1 : (uint) pgit->itemText.length();
1359
                                for (uint e = start; e < stop; ++e)
16953 fschmid 1360
                                {
21707 jghali 1361
                                        QString replacementName = pgit->itemText.charStyle(e).font().replacementName();
1362
                                        ReallyUsed.insert(replacementName, DocFonts[replacementName]);
16953 fschmid 1363
                                }
8092 fschmid 1364
                        }
3133 fschmid 1365
                }
1366
        }
20112 jghali 1367
        return ReallyUsed;
20103 avox 1368
}
17628 jghali 1369
 
20103 avox 1370
static QByteArray sanitizeFontName(QString fn)
1371
{
20112 jghali 1372
        return Pdf::toPdfDocEncoding(fn.replace( QRegExp("[\\s\\/\\{\\[\\]\\}\\<\\>\\(\\)\\%]"), "_" ));
20103 avox 1373
}
17628 jghali 1374
 
20103 avox 1375
static QList<Pdf::Resource> asColorSpace(QList<PdfICCD> iccCSlist)
1376
{
20112 jghali 1377
        QList<Pdf::Resource> result;
1378
        foreach (Pdf::Resource r, iccCSlist)
1379
        {
1380
                result.append(r);
1381
        }
1382
        return result;
20103 avox 1383
}
1384
 
1385
static QList<Pdf::Resource> asColorSpace(QList<PdfSpotC> spotMapValues)
1386
{
20112 jghali 1387
        QList<Pdf::Resource> result;
1388
        foreach (Pdf::Resource r, spotMapValues)
1389
        {
1390
                result.append(r);
1391
        }
1392
        return result;
20103 avox 1393
}
1394
 
1395
 
1396
void PDFLibCore::PDF_WriteStandardFonts()
1397
{
20112 jghali 1398
        int a = 0;
1399
        QMap<QString, QString>::Iterator itStd;
1400
        for (itStd = StdFonts.begin(); itStd != StdFonts.end(); ++itStd)
1401
        {
1402
                PdfId fontObject = writer.newObject();
1403
                writer.startObj(fontObject);
1404
                PutDoc("<<\n/Type /Font\n/Subtype /Type1\n");
1405
                PutDoc("/Name /FoStd"+Pdf::toPdf(a)+"\n");
1406
                PutDoc("/BaseFont "+Pdf::toPdfDocEncoding(itStd.key())+"\n");
1407
                if (itStd.key() != "/ZapfDingbats")
1408
                {
1409
                        PutDoc("/Encoding << \n");
1410
                        PutDoc("/Differences [ \n");
1411
                        PutDoc("24 /breve /caron /circumflex /dotaccent /hungarumlaut /ogonek /ring /tilde\n");
1412
                        PutDoc("39 /quotesingle 96 /grave 128 /bullet /dagger /daggerdbl /ellipsis /emdash /endash /florin /fraction /guilsinglleft /guilsinglright\n");
1413
                        PutDoc("/minus /perthousand /quotedblbase /quotedblleft /quotedblright /quoteleft /quoteright /quotesinglbase /trademark /fi /fl /Lslash /OE /Scaron\n");
21744 jghali 1414
                        PutDoc("/Ydieresis /Zcaron /dotlessi /lslash /oe /scaron /zcaron 160 /Euro 164 /currency 166 /brokenbar 168 /dieresis /copyright /ordfeminine 172 /logicalnot\n");
20112 jghali 1415
                        PutDoc("/.notdef /registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu 183 /periodcentered /cedilla /onesuperior /ordmasculine\n");
1416
                        PutDoc("188 /onequarter /onehalf /threequarters 192 /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex\n");
1417
                        PutDoc("/Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash\n");
1418
                        PutDoc("/Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla\n");
1419
                        PutDoc("/egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis\n");
1420
                        PutDoc("/divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis\n");
1421
                        PutDoc("] >>\n");
1422
                }
1423
                PutDoc(">>");
1424
                writer.endObj(fontObject);
1425
                pageData.FObjects["FoStd"+Pdf::toPdf(a)] = fontObject;
1426
                itStd.value() = "FoStd"+Pdf::toPdf(a);
1427
                a++;
1428
        }
20103 avox 1429
}
1430
 
1431
 
1432
PdfFont PDFLibCore::PDF_WriteType3Font(const QByteArray& name, ScFace& face, const QMap<uint,FPointArray>& RealGlyphs)
1433
{
20112 jghali 1434
        PdfFont result;
1435
        result.name = Pdf::toName(name);
1436
        result.method = Use_Type3;
1437
        result.encoding = Encode_256;
20103 avox 1438
 
20112 jghali 1439
        uint SubFonts = 0;
1440
        int glyphCount = 0;
1441
        double minx =  std::numeric_limits<double>::max();
1442
        double miny =  std::numeric_limits<double>::max();
1443
        double maxx = -std::numeric_limits<double>::max();
1444
        double maxy = -std::numeric_limits<double>::max();
1445
        QList<uint> glyphWidths;
1446
        QList<QByteArray> charProcs;
1447
        QByteArray encoding = "<< /Type /Encoding\n/Differences [ 0\n";
1448
        QByteArray fon;
1449
        QMap<uint, uint> glyphMapping;
1450
        ScFace::FaceEncoding gl;
1451
        face.glyphNames(gl);
1452
        QMap<uint,FPointArray>::ConstIterator ig;
1453
        for (ig = RealGlyphs.cbegin(); ig != RealGlyphs.cend(); ++ig)
1454
        {
1455
                FPoint np, np1, np2;
1456
                bool nPath = true;
1457
                fon.resize(0);
1458
                if (ig.value().size() > 3)
1459
                {
1460
                        FPointArray gly = ig.value();
1461
                        QTransform mat;
1462
                        mat.scale(100.0, -100.0);
1463
                        gly.map(mat);
1464
                        gly.translate(0, 1000);
1465
                        for (int poi = 0; poi < gly.size()-3; poi += 4)
1466
                        {
1467
                                if (gly.isMarker(poi))
1468
                                {
1469
                                        fon += "h\n";
1470
                                        nPath = true;
1471
                                        continue;
1472
                                }
1473
                                if (nPath)
1474
                                {
1475
                                        np = gly.point(poi);
1476
                                        fon += FToStr(np.x())+" "+FToStr(np.y())+" m\n";
1477
                                        nPath = false;
1478
                                }
1479
                                np = gly.point(poi+1);
1480
                                np1 = gly.point(poi+3);
1481
                                np2 = gly.point(poi+2);
1482
                                fon += FToStr(np.x()) + " " + FToStr(np.y()) + " " + FToStr(np1.x()) + " " + FToStr(np1.y()) + " " + FToStr(np2.x()) + " " + FToStr(np2.y()) + " c\n";
1483
                        }
1484
                        fon += "h f*\n";
1485
                        np = getMinClipF(&gly);
1486
                        np1 = getMaxClipF(&gly);
1487
                }
1488
                else
1489
                {
20684 jghali 1490
                        // 13654: make evince emit warning about "Syntax Error: No current point in closepath"
1491
                        // PDF specification is not quite clear about that, but a single "h" operator might not
1492
                        // be a valid way to make an empty path
1493
                        // fon = "h";
20112 jghali 1494
                        np = FPoint(0, 0);
1495
                        np1 = FPoint(0, 0);
1496
                }
1497
                fon.prepend(Pdf::toPdf(qRound(np1.x())) + " 0 "+Pdf::toPdf(qRound(np.x()))+" "+Pdf::toPdf(qRound(np.y()))+" "+Pdf::toPdf(qRound(np1.x()))+ " "+Pdf::toPdf(qRound(np1.y()))+" d1\n");
1498
                minx = qMin(minx, np.x());
1499
                miny = qMin(miny, np.y());
1500
                maxx = qMax(maxx, np1.x());
1501
                maxy = qMax(maxy, np1.y());
1502
                glyphWidths.append(qRound(np1.x()));
1503
                PdfId charProcObject = writer.newObject();
1504
                charProcs.append(Pdf::toName(gl[ig.key()].second)+" "+Pdf::toPdf(charProcObject)+" 0 R\n");
1505
                encoding += Pdf::toName(gl[ig.key()].second)+" ";
1506
                glyphMapping.insert(ig.key(), glyphCount + SubFonts * 256);
1507
                writer.startObj(charProcObject);
1508
                if (Options.Compress)
1509
                        fon = CompressArray(fon);
1510
                PutDoc("<< /Length "+Pdf::toPdf(fon.length()+1));
1511
                if (Options.Compress)
1512
                        PutDoc("\n/Filter /FlateDecode");
1513
                PutDoc("\n>>\nstream\n"+EncStream(fon, charProcObject)+"\nendstream");
1514
                writer.endObj(charProcObject);
1515
                glyphCount++;
1516
                int glyphsLeft = RealGlyphs.count() - SubFonts * 256;
1517
                if ((glyphCount > 255) || (glyphCount == glyphsLeft))
1518
                {
1519
                        PdfId fontWidths = writer.newObject();
1520
                        writer.startObj(fontWidths);
1521
                        PutDoc("[ ");
1522
                        for (int ww = 0; ww < glyphWidths.count(); ++ww)
1523
                        {
1524
                                PutDoc(Pdf::toPdf(glyphWidths[ww])+" ");
1525
                        }
1526
                        PutDoc("]");
1527
                        writer.endObj(fontWidths);
1528
                        PdfId fontCharProcs = writer.newObject();
1529
                        writer.startObj(fontCharProcs);
1530
                        PutDoc("<<\n");
1531
                        for (int ww = 0; ww < charProcs.count(); ++ww)
1532
                        {
1533
                                PutDoc(charProcs[ww]);
1534
                        }
1535
                        PutDoc(">>");
1536
                        writer.endObj(fontCharProcs);
1537
                        PdfId fontEncoding = writer.newObject();
1538
                        writer.startObj(fontEncoding);
1539
                        PutDoc(encoding);
1540
                        PutDoc("]\n");
1541
                        PutDoc(">>");
1542
                        writer.endObj(fontEncoding);
1543
                        PdfId font3Object = writer.newObject();
1544
                        writer.startObj(font3Object);
1545
                        PutDoc("<<\n/Type /Font\n/Subtype /Type3\n");
1546
                        PutDoc("/Name /"+name+"S"+Pdf::toPdf(SubFonts)+"\n");
1547
                        PutDoc("/FirstChar 0\n");
1548
                        PutDoc("/LastChar "+Pdf::toPdf(glyphCount-1)+"\n");
1549
                        PutDoc("/Widths "+Pdf::toPdf(fontWidths)+" 0 R\n");
1550
                        PutDoc("/CharProcs "+Pdf::toPdf(fontCharProcs)+" 0 R\n");
1551
                        PutDoc("/FontBBox ["+Pdf::toPdf(qRound(minx))+" "+Pdf::toPdf(qRound(miny))+" "+Pdf::toPdf(qRound(maxx))+ " "+Pdf::toPdf(qRound(maxy))+"]\n");
1552
                        PutDoc("/FontMatrix [0.001 0 0 0.001 0 0]\n");
1553
                        PutDoc("/Encoding "+Pdf::toPdf(fontEncoding)+" 0 R\n");
1554
                        PutDoc(">>");
1555
                        writer.endObj(font3Object);
1556
                        pageData.FObjects[name+"S"+Pdf::toPdf(SubFonts)] = font3Object;
1557
                        charProcs.clear();
1558
                        glyphWidths.clear();
1559
                        //                                              glyphMapping.clear();
1560
                        glyphCount = 0;
1561
                        ++SubFonts;
1562
                        minx =  std::numeric_limits<double>::max();
1563
                        miny =  std::numeric_limits<double>::max();
1564
                        maxx = -std::numeric_limits<double>::max();
1565
                        maxy = -std::numeric_limits<double>::max();
1566
                        encoding = "<< /Type /Encoding\n/Differences [ 0\n";
1567
                }
1568
        }
1569
        result.glyphmap = glyphMapping;
1570
        return result;
20103 avox 1571
}
1572
 
1573
 
1574
PdfFont PDFLibCore::PDF_WriteGlyphsAsXForms(const QByteArray& fontName, ScFace& face, const QMap<uint,FPointArray>& RealGlyphs)
1575
{
20112 jghali 1576
        PdfFont result;
1577
        result.name = Pdf::toName(fontName);
1578
        result.method = Use_XForm;
1579
        result.encoding = Encode_224;
20103 avox 1580
 
20112 jghali 1581
        QByteArray fon;
1582
        QMap<uint,FPointArray>::ConstIterator ig;
1583
        for (ig = RealGlyphs.cbegin(); ig != RealGlyphs.cend(); ++ig)
1584
        {
1585
                FPoint np, np1, np2;
1586
                bool nPath = true;
1587
                fon.resize(0);
1588
                if (ig.value().size() > 3)
1589
                {
1590
                        FPointArray gly = ig.value();
1591
                        QTransform mat;
1592
                        mat.scale(0.1, 0.1);
1593
                        gly.map(mat);
1594
                        for (int poi = 0; poi < gly.size()-3; poi += 4)
1595
                        {
1596
                                if (gly.isMarker(poi))
1597
                                {
1598
                                        fon += "h\n";
1599
                                        nPath = true;
1600
                                        continue;
1601
                                }
1602
                                if (nPath)
1603
                                {
1604
                                        np = gly.point(poi);
1605
                                        fon += FToStr(np.x())+" "+FToStr(-np.y())+" m\n";
1606
                                        nPath = false;
1607
                                }
1608
                                np = gly.point(poi+1);
1609
                                np1 = gly.point(poi+3);
1610
                                np2 = gly.point(poi+2);
1611
                                fon += FToStr(np.x()) + " " + FToStr(-np.y()) + " " +
1612
                                FToStr(np1.x()) + " " + FToStr(-np1.y()) + " " +
1613
                                FToStr(np2.x()) + " " + FToStr(-np2.y()) + " c\n";
1614
                        }
1615
                        fon += "h f*\n";
1616
                        np = getMinClipF(&gly);
1617
                        np1 = getMaxClipF(&gly);
1618
                }
1619
                else
1620
                {
20684 jghali 1621
                        // 13654: make evince emit warning about "Syntax Error: No current point in closepath"
1622
                        // PDF specification is not quite clear about that, but a single "h" operator might not
1623
                        // be a valid way to make an empty path
1624
                        fon = " " /*"h"*/;
20112 jghali 1625
                        np = FPoint(0, 0);
1626
                        np1 = FPoint(0, 0);
1627
                }
1628
                PdfId fontGlyphXForm = writer.newObject();
1629
                writer.startObj(fontGlyphXForm);
1630
                PutDoc("<<\n/Type /XObject\n/Subtype /Form\n/FormType 1\n");
1631
                PutDoc("/BBox [ "+FToStr(np.x())+" "+FToStr(-np.y())+" "+FToStr(np1.x())+ " "+FToStr(-np1.y())+" ]\n");
1632
                PutDoc("/Resources << /ProcSet [/PDF /Text /ImageB /ImageC /ImageI]\n");
1633
                PutDoc(">>\n");
1634
                if (Options.Compress)
1635
                        fon = CompressArray(fon);
1636
                PutDoc("/Length "+Pdf::toPdf(fon.length()+1));
1637
                if (Options.Compress)
1638
                        PutDoc("\n/Filter /FlateDecode");
1639
                PutDoc(" >>\nstream\n"+EncStream(fon, fontGlyphXForm)+"\nendstream");
1640
                writer.endObj(fontGlyphXForm);
1641
                pageData.XObjects[fontName + Pdf::toPdf(ig.key())] = fontGlyphXForm;
1642
        }
1643
        return result;
20103 avox 1644
}
1645
 
1646
PdfId PDFLibCore::PDF_EmbedFontObject(const QByteArray& font, const QByteArray& subtype)
1647
 
1648
{
20112 jghali 1649
        PdfId embeddedFontObject = writer.newObject();
1650
        writer.startObj(embeddedFontObject);
1651
        int len = font.length();
1652
        QByteArray ttf = (Options.Compress? CompressArray(font) : font);
1653
        //qDebug() << QString("sfnt data: size=%1 compressed=%2").arg(len).arg(bb.length());
1654
        PutDoc("<<\n/Length " + Pdf::toPdf(ttf.length() + 1) + "\n");
1655
        PutDoc("/Length1 " + Pdf::toPdf(len) + "\n");
1656
        if (subtype.size() > 0)
1657
                PutDoc("/Subtype " + subtype);
1658
        if (Options.Compress)
1659
                PutDoc("/Filter /FlateDecode\n");
1660
        PutDoc(">>\nstream\n");
1661
        EncodeArrayToStream(ttf, embeddedFontObject);
1662
        PutDoc("\nendstream");
1663
        writer.endObj(embeddedFontObject);
1664
        return embeddedFontObject;
20103 avox 1665
}
1666
 
1667
PdfId PDFLibCore::PDF_WriteFontDescriptor(const QByteArray& fontName, ScFace& face, ScFace::FontFormat fformat, PdfId embeddedFontObject)
1668
{
20112 jghali 1669
        PdfId fontDescriptor = writer.newObject();
1670
        writer.startObj(fontDescriptor);
1671
        // TODO: think about QByteArray ScFace::getFontDescriptor() -- AV
1672
        PutDoc("<<\n/Type /FontDescriptor\n");
1673
        PutDoc("/FontName "  + Pdf::toName(fontName) + "\n");
1674
        PutDoc("/FontBBox [ " + Pdf::toAscii(face.pdfFontBBoxAsString()) + " ]\n");
1675
        PutDoc("/Flags ");
1676
        //FIXME: isItalic() should be queried from ScFace, not from Qt -- AV
1677
        //QFontInfo fo = QFontInfo(it.data());
1678
        int pfl = 0;
1679
        if (face.isFixedPitch())
1680
                pfl = pfl ^ 1;
1681
        //if (fo.italic())
1682
        if (face.italicAngleAsString() != "0")
1683
                pfl = pfl ^ 64;
1684
        //                      pfl = pfl ^ 4;
1685
        pfl = pfl ^ 32;
1686
        PutDoc(Pdf::toPdf(pfl)+"\n");
1687
        PutDoc("/Ascent "      + Pdf::toAscii(face.pdfAscentAsString())+"\n");
1688
        PutDoc("/Descent "     + Pdf::toAscii(face.pdfDescentAsString())+"\n");
1689
        PutDoc("/CapHeight "   + Pdf::toAscii(face.pdfCapHeightAsString())+"\n");
1690
        PutDoc("/ItalicAngle " + Pdf::toAscii(face.italicAngleAsString())+"\n");
1691
        PutDoc("/StemV 1\n");
1692
        if (embeddedFontObject != 0)
1693
        {
1694
                if (fformat == ScFace::SFNT || fformat == ScFace::TTCF)
1695
                {
1696
                        if (face.type() == ScFace::OTF)
1697
                        {
1698
                                PutDoc("/FontFile3 "+Pdf::toPdf(embeddedFontObject)+" 0 R\n");
1699
                        }
1700
                        else
1701
                        {
1702
                                PutDoc("/FontFile2 "+Pdf::toPdf(embeddedFontObject)+" 0 R\n");
1703
                        }
1704
                }
1705
                else if (fformat == ScFace::PFB)
1706
                        PutDoc("/FontFile "+Pdf::toPdf(embeddedFontObject)+" 0 R\n");
1707
                else if (fformat == ScFace::PFA)
1708
                        PutDoc("/FontFile "+Pdf::toPdf(embeddedFontObject)+" 0 R\n");
1709
        }
1710
        PutDoc(">>");
1711
        writer.endObj(fontDescriptor);
1712
        return fontDescriptor;
20103 avox 1713
}
1714
 
1715
PdfFont PDFLibCore::PDF_EncodeCidFont(const QByteArray& fontName, ScFace& face, const QByteArray& baseFont, PdfId fontDes, const ScFace::FaceEncoding& gl, const QMap<uint,uint> glyphmap  )
1716
{
20112 jghali 1717
        PdfFont result;
1718
        result.name = Pdf::toName(fontName);
1719
        result.method = glyphmap.isEmpty()? Use_Embedded : Use_Subset;
1720
        result.encoding = glyphmap.isEmpty()? Encode_IdentityH : Encode_Subset;
1721
        result.glyphmap = glyphmap;
1722
 
1723
        PdfId fontWidths2 = writer.newObject();
1724
        writer.startObj(fontWidths2);
1725
        QList<QByteArray> toUnicodeMaps;
1726
        QList<int> toUnicodeMapsCount;
1727
        QByteArray toUnicodeMap = "";
1728
        int toUnicodeMapCounter = 0;
1729
 
1730
        PutDoc("[ ");
1731
        QList<uint> keys = gl.uniqueKeys();
1732
        QList<uint>::iterator git;
1733
        bool seenNotDef = false;
1734
        for (git = keys.begin(); git != keys.end(); ++git)
1735
        {
1736
                uint gid = result.encoding == Encode_Subset? glyphmap[*git] : *git;
1737
                if (gid > 0 || !seenNotDef)
1738
                {
1739
                        seenNotDef |= (gid == 0);
1740
                        PutDoc(Pdf::toPdf(gid)+" ["+Pdf::toPdf(static_cast<int>(face.glyphWidth(*git)* 1000))+"] " );
1741
                        QString tmp, tmp2;
1742
                        tmp.sprintf("%04X", gid);
1743
                        tmp2.sprintf("%04X", gl.value(*git).first);
1744
                        toUnicodeMap += "<" + Pdf::toAscii(tmp)+ "> <" + Pdf::toAscii(tmp2) + ">\n";
1745
                        toUnicodeMapCounter++;
1746
                        if (toUnicodeMapCounter == 100)
1747
                        {
1748
                                toUnicodeMaps.append(toUnicodeMap);
1749
                                toUnicodeMapsCount.append(toUnicodeMapCounter);
1750
                                toUnicodeMap = "";
1751
                                toUnicodeMapCounter = 0;
1752
                        }
1753
                }
1754
        }
1755
        PutDoc("]");
1756
        writer.endObj(fontWidths2);
1757
        if (toUnicodeMapCounter != 0)
1758
        {
1759
                toUnicodeMaps.append(toUnicodeMap);
1760
                toUnicodeMapsCount.append(toUnicodeMapCounter);
1761
        }
1762
        QByteArray toUnicodeMapStream = "";
1763
        toUnicodeMapStream += "/CIDInit /ProcSet findresource begin\n";
1764
        toUnicodeMapStream += "12 dict begin\n";
1765
        toUnicodeMapStream += "begincmap\n";
1766
        toUnicodeMapStream += "/CIDSystemInfo <<\n";
1767
        toUnicodeMapStream += "/Registry (Adobe)\n";
1768
        toUnicodeMapStream += "/Ordering (UCS)\n";
1769
        toUnicodeMapStream += "/Supplement 0\n";
1770
        toUnicodeMapStream += ">> def\n";
1771
        toUnicodeMapStream += "/CMapName /Adobe-Identity-UCS def\n";
1772
        toUnicodeMapStream += "/CMapType 2 def\n";
1773
        toUnicodeMapStream += "1 begincodespacerange\n";
1774
        toUnicodeMapStream += "<0000> <FFFF>\n";
1775
        toUnicodeMapStream += "endcodespacerange\n";
1776
        for (int uniC = 0; uniC < toUnicodeMaps.count(); uniC++)
1777
        {
1778
                toUnicodeMapStream += Pdf::toPdf(toUnicodeMapsCount[uniC]);
1779
                toUnicodeMapStream += " beginbfchar\n";
1780
                toUnicodeMapStream += toUnicodeMaps[uniC];
1781
                toUnicodeMapStream += "endbfchar\n";
1782
        }
1783
        toUnicodeMapStream += "endcmap\n";
1784
        toUnicodeMapStream += "CMapName currentdict /CMap defineresource pop\n";
1785
        toUnicodeMapStream += "end\n";
1786
        toUnicodeMapStream += "end\n";
1787
        PdfId fontToUnicode2 = WritePDFStream(toUnicodeMapStream);
1788
        PdfId fontObject2 = writer.newObject();
1789
        writer.startObj(fontObject2);
1790
        PutDoc("<<\n/Type /Font\n/Subtype /Type0\n");
1791
        PutDoc("/Name " + Pdf::toName(fontName) + "\n");
21759 jghali 1792
        PutDoc("/BaseFont "+ Pdf::toName(baseFont) +"\n");
20112 jghali 1793
        PutDoc("/Encoding /Identity-H\n");
1794
        PutDoc("/ToUnicode "+Pdf::toPdf(fontToUnicode2)+" 0 R\n");
1795
        PutDoc("/DescendantFonts [");
1796
        PutDoc("<</Type /Font");
1797
        if (face.type() == ScFace::OTF)
1798
                PutDoc("/Subtype /CIDFontType0");
1799
        else
1800
                PutDoc("/Subtype /CIDFontType2");
21759 jghali 1801
        PutDoc("/BaseFont " + Pdf::toName(baseFont));
20112 jghali 1802
        PutDoc("/FontDescriptor " + Pdf::toPdf(fontDes)+ " 0 R");
1803
        PutDoc("/CIDSystemInfo <</Ordering(Identity)/Registry(Adobe)/Supplement 0>>");
1804
        PutDoc("/DW 1000");
1805
        PutDoc("/W "+Pdf::toPdf(fontWidths2)+" 0 R");
1806
        PutDoc("/CIDToGIDMap /Identity");
1807
        PutDoc(">>"); // close CIDFont dictionary
1808
        PutDoc("]\n"); // close DescendantFonts array
1809
        PutDoc(">>");
1810
        writer.endObj(fontObject2);
1811
        pageData.FObjects[fontName] = fontObject2;
1812
        return result;
20103 avox 1813
}
1814
 
1815
 
1816
PdfFont PDFLibCore::PDF_EncodeSimpleFont(const QByteArray& fontName, ScFace& face, const QByteArray& baseFont, const QByteArray& subtype, bool isEmbedded, PdfId fontDes, const ScFace::FaceEncoding& gl)
1817
{
20112 jghali 1818
        PdfFont result;
1819
        result.name = Pdf::toName(fontName);
1820
        result.method = isEmbedded? Use_Embedded : Use_System;
1821
        result.encoding = Encode_224;
1822
 
1823
        int nglyphs = 0;
1824
        ScFace::FaceEncoding::ConstIterator gli;
1825
        for (gli = gl.cbegin(); gli != gl.cend(); ++gli)
1826
        {
1827
                if (gli.key() > static_cast<uint>(nglyphs))
1828
                        nglyphs = gli.key();
1829
        }
1830
        ++nglyphs;
1831
        //                      qDebug() << QString("pdflib: nglyphs %1 max %2").arg(nglyphs).arg(face.maxGlyph());
1832
 
1833
        uint Fcc = nglyphs / 224;
1834
        if ((nglyphs % 224) != 0)
1835
                Fcc += 1;
1836
        for (uint Fc = 0; Fc < Fcc; ++Fc)
1837
        {
1838
                PdfId fontWidths2 = writer.newObject();
1839
                writer.startObj(fontWidths2);
1840
                int chCount = 32;
1841
                PutDoc("[ 0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 ");
1842
                for (int ww = 32; ww < 256; ++ww)
1843
                {
1844
                        uint glyph = 224 * Fc + ww - 32;
1845
                        if (gl.contains(glyph))
1846
                                PutDoc(Pdf::toPdf(static_cast<int>(face.glyphWidth(glyph)* 1000))+" ");
1847
                        else
1848
                                PutDoc("0 ");
1849
                        chCount++;
1850
                        if (signed(glyph) == nglyphs-1)
1851
                                break;
1852
                }
1853
                PutDoc("]");
1854
                writer.endObj(fontWidths2);
1855
                PdfId fontEncoding2 = writer.newObject();
1856
                writer.startObj(fontEncoding2);
1857
                QStringList toUnicodeMaps;
1858
                QList<int> toUnicodeMapsCount;
1859
                QString toUnicodeMap = "";
1860
                int toUnicodeMapCounter = 0;
1861
                PutDoc("<< /Type /Encoding\n");
1862
                PutDoc("/Differences [ \n");
1863
                int crc = 0;
1864
                bool startOfSeq = true;
1865
                for (int ww2 = 32; ww2 < 256; ++ww2)
1866
                {
1867
                        uint glyph = 224 * Fc + ww2 - 32;
1868
                        ScFace::FaceEncoding::ConstIterator glIt = gl.find(glyph);
1869
                        if (glIt != gl.cend() && !glIt.value().second.isEmpty())
1870
                        {
1871
                                if (startOfSeq)
1872
                                {
1873
                                        PutDoc(Pdf::toPdf(ww2)+" ");
1874
                                        startOfSeq = false;
1875
                                }
1876
                                PutDoc(Pdf::toName(glIt.value().second)+" ");
1877
                                QString tmp, tmp2;
1878
                                tmp.sprintf("%02X", ww2);
1879
                                tmp2.sprintf("%04X", glIt.value().first);
1880
                                toUnicodeMap += "<" + Pdf::toAscii(tmp) + "> <" + Pdf::toAscii(tmp2) + ">\n";
1881
                                //QString("<%1> <%2>\n").arg(tmp).arg((tmp2));
1882
                                toUnicodeMapCounter++;
1883
                                if (toUnicodeMapCounter == 100)
1884
                                {
1885
                                        toUnicodeMaps.append(toUnicodeMap);
1886
                                        toUnicodeMapsCount.append(toUnicodeMapCounter);
1887
                                        toUnicodeMap = "";
1888
                                        toUnicodeMapCounter = 0;
1889
                                }
1890
                                crc++;
1891
                        }
1892
                        else
1893
                        {
1894
                                startOfSeq = true;
1895
                        }
1896
                        if (signed(glyph) == nglyphs-1)
1897
                                break;
1898
                        if (crc > 8)
1899
                        {
1900
                                PutDoc("\n");
1901
                                crc = 0;
1902
                        }
1903
                }
1904
                if (toUnicodeMapCounter != 0)
1905
                {
1906
                        toUnicodeMaps.append(toUnicodeMap);
1907
                        toUnicodeMapsCount.append(toUnicodeMapCounter);
1908
                }
1909
                PutDoc("]\n");
1910
                PutDoc(">>");
1911
                writer.endObj(fontEncoding2);
1912
                QByteArray toUnicodeMapStream = "";
1913
                toUnicodeMapStream += "/CIDInit /ProcSet findresource begin\n";
1914
                toUnicodeMapStream += "12 dict begin\n";
1915
                toUnicodeMapStream += "begincmap\n";
1916
                toUnicodeMapStream += "/CIDSystemInfo <<\n";
1917
                toUnicodeMapStream += "/Registry (Adobe)\n";
1918
                toUnicodeMapStream += "/Ordering (UCS)\n";
1919
                toUnicodeMapStream += "/Supplement 0\n";
1920
                toUnicodeMapStream += ">> def\n";
1921
                toUnicodeMapStream += "/CMapName /Adobe-Identity-UCS def\n";
1922
                toUnicodeMapStream += "/CMapType 2 def\n";
1923
                toUnicodeMapStream += "1 begincodespacerange\n";
1924
                toUnicodeMapStream += "<0000> <FFFF>\n";
1925
                toUnicodeMapStream += "endcodespacerange\n";
1926
                for (int uniC = 0; uniC < toUnicodeMaps.count(); uniC++)
1927
                {
1928
                        toUnicodeMapStream += Pdf::toPdf(toUnicodeMapsCount[uniC]);
1929
                        toUnicodeMapStream += " beginbfchar\n";
1930
                        toUnicodeMapStream += toUnicodeMaps[uniC];
1931
                        toUnicodeMapStream += "endbfchar\n";
1932
                }
1933
                toUnicodeMapStream += "endcmap\n";
1934
                toUnicodeMapStream += "CMapName currentdict /CMap defineresource pop\n";
1935
                toUnicodeMapStream += "end\n";
1936
                toUnicodeMapStream += "end\n";
1937
                PdfId fontToUnicode2 = WritePDFStream(toUnicodeMapStream);
1938
                PdfId fontObject2 = writer.newObject();
1939
                writer.startObj(fontObject2);
1940
                PutDoc("<<\n/Type /Font\n/Subtype ");
1941
                PutDoc(subtype + "\n");
1942
                PutDoc("/Name "+Pdf::toName(fontName)+"S"+Pdf::toPdf(Fc)+"\n");
21759 jghali 1943
                PutDoc("/BaseFont "+ Pdf::toName(baseFont) + "\n");
20112 jghali 1944
                PutDoc("/FirstChar 0\n");
1945
                PutDoc("/LastChar "+Pdf::toPdf(chCount-1)+"\n");
1946
                PutDoc("/Widths "+Pdf::toPdf(fontWidths2)+" 0 R\n");
1947
                PutDoc("/Encoding "+Pdf::toPdf(fontEncoding2)+" 0 R\n");
1948
                PutDoc("/ToUnicode "+Pdf::toPdf(fontToUnicode2)+" 0 R\n");
1949
                PutDoc("/FontDescriptor "+Pdf::toPdf(fontDes)+" 0 R\n");
1950
                PutDoc(">>");
1951
                writer.endObj(fontObject2);
1952
                pageData.FObjects[fontName + "S"+Pdf::toPdf(Fc)] = fontObject2;
1953
        } // for(Fc)
21744 jghali 1954
 
1955
        return result;
1956
}
1957
 
1958
PdfFont PDFLibCore::PDF_EncodeFormFont(const QByteArray& fontName, ScFace& face, const QByteArray& baseFont, const QByteArray& subtype, PdfId fontDes)
1959
{
1960
        PdfFont formFont;
1961
        formFont.name = Pdf::toName(fontName) + "Form";
1962
        formFont.usage = Used_in_Forms;
1963
 
20112 jghali 1964
        PdfId fontWidthsForm = writer.newObject();
1965
        writer.startObj(fontWidthsForm);
1966
        PutDoc("[ 0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 ");
21563 jghali 1967
        for (uint ww = 32; ww < 256; ++ww)
20112 jghali 1968
        {
21744 jghali 1969
                int unicode = Pdf::fromPDFDocEncoding(ww);
1970
                uint glyph  = face.char2CMap(unicode);
1971
                if (glyph > 0)
20112 jghali 1972
                        PutDoc(Pdf::toPdf(static_cast<int>(face.glyphWidth(glyph)* 1000))+" ");
1973
                else
1974
                        PutDoc("0 ");
1975
        }
1976
        PutDoc("]");
1977
        writer.endObj(fontWidthsForm);
21744 jghali 1978
 
20112 jghali 1979
        PdfId fontObjectForm = writer.newObject();
1980
        writer.startObj(fontObjectForm);
1981
        PutDoc("<<\n/Type /Font\n/Subtype ");
1982
        PutDoc(subtype + "\n");
21759 jghali 1983
        PutDoc("/Name " + formFont.name + "\n");
1984
        PutDoc("/BaseFont "+ Pdf::toName(baseFont) +"\n");
20112 jghali 1985
        PutDoc("/Encoding << \n");
1986
        PutDoc("/Differences [ \n");
1987
        PutDoc("24 /breve /caron /circumflex /dotaccent /hungarumlaut /ogonek /ring /tilde\n");
1988
        PutDoc("39 /quotesingle 96 /grave 128 /bullet /dagger /daggerdbl /ellipsis /emdash /endash /florin /fraction /guilsinglleft /guilsinglright\n");
1989
        PutDoc("/minus /perthousand /quotedblbase /quotedblleft /quotedblright /quoteleft /quoteright /quotesinglbase /trademark /fi /fl /Lslash /OE /Scaron\n");
21744 jghali 1990
        PutDoc("/Ydieresis /Zcaron /dotlessi /lslash /oe /scaron /zcaron 160 /Euro 164 /currency 166 /brokenbar 168 /dieresis /copyright /ordfeminine 172 /logicalnot\n");
20112 jghali 1991
        PutDoc("/.notdef /registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu 183 /periodcentered /cedilla /onesuperior /ordmasculine\n");
1992
        PutDoc("188 /onequarter /onehalf /threequarters 192 /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex\n");
1993
        PutDoc("/Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash\n");
1994
        PutDoc("/Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla\n");
1995
        PutDoc("/egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis\n");
1996
        PutDoc("/divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis\n");
1997
        PutDoc("] >>\n");
1998
        PutDoc("/FirstChar 0\n");
1999
        PutDoc("/LastChar 255\n");
2000
        PutDoc("/Widths "+Pdf::toPdf(fontWidthsForm)+" 0 R\n");
2001
        PutDoc("/FontDescriptor "+Pdf::toPdf(fontDes)+" 0 R\n");
2002
        PutDoc(">>");
2003
        writer.endObj(fontObjectForm);
20103 avox 2004
 
21744 jghali 2005
        pageData.FObjects[fontName + "Form"] = fontObjectForm;
2006
        UsedFontsF.insert(face.replacementName(), formFont);
2007
 
2008
        return formFont;
20103 avox 2009
}
2010
 
21075 craig 2011
/*
20103 avox 2012
static void dumpFont(QString name, QByteArray data)
2013
{
20112 jghali 2014
        QFile file(name);
20980 craig 2015
        if (file.open(QIODevice::WriteOnly))
2016
        {
2017
                QDataStream out(&file);
2018
                out.writeRawData(data.data(), data.length());
2019
                file.close();
2020
        }
20103 avox 2021
}
2022
 
2023
static void dumpCFF(QString name, cff::CFF font)
2024
{
20112 jghali 2025
        QFile file(name);
20980 craig 2026
        if (file.open(QIODevice::WriteOnly))
2027
        {
2028
                QDataStream out(&file);
2029
                font.dump(out);
2030
                file.close();
2031
        }
20103 avox 2032
}
21075 craig 2033
*/
20103 avox 2034
 
2035
 
2036
PdfFont PDFLibCore::PDF_WriteTtfSubsetFont(const QByteArray& fontName, ScFace& face, const QMap<uint,FPointArray>& RealGlyphs)
2037
{
20112 jghali 2038
        QByteArray font;
2039
        face.RawData(font);
20974 jghali 2040
        /*dumpFont(face.psName() + ".ttf", font);*/
20112 jghali 2041
        QList<ScFace::gid_type> glyphs = RealGlyphs.uniqueKeys();
2042
        glyphs.removeAll(0);
2043
        glyphs.prepend(0);
2044
        QByteArray subset = sfnt::subsetFace(font, glyphs);
20974 jghali 2045
        /*dumpFont(face.psName()+"subs.ttf", subset);*/
20112 jghali 2046
        PdfId embeddedFontObj = PDF_EmbedFontObject(subset, QByteArray());
2047
        PdfId fontDes = PDF_WriteFontDescriptor(fontName, face, face.format(), embeddedFontObj);
21759 jghali 2048
        QByteArray baseFont = sanitizeFontName(face.psName());
20112 jghali 2049
        ScFace::FaceEncoding fullEncoding, subEncoding;
2050
        QMap<uint,uint> glyphmap;
2051
        face.glyphNames(fullEncoding);
2052
        for (int i = 0; i < glyphs.length(); ++i)
2053
        {
2054
                glyphmap[glyphs[i]] = i;
2055
                qDebug() << glyphs[i] << " --> " << i << QChar(fullEncoding[glyphs[i]].first);
2056
        }
2057
 
2058
        PdfFont result = PDF_EncodeCidFont(fontName, face, baseFont, fontDes, fullEncoding, glyphmap);
2059
        return result;
20103 avox 2060
}
2061
 
2062
 
2063
PdfFont PDFLibCore::PDF_WriteCffSubsetFont(const QByteArray& fontName, ScFace& face, const QMap<uint,FPointArray>& RealGlyphs)
2064
{
20112 jghali 2065
//      QByteArray sfnt; //TEST
2066
//      face.RawData(sfnt);
2067
//      QByteArray cff = sfnt::getTable(sfnt, "CFF ");
2068
//      dumpFont(fontName, cff);
2069
//      cff::CFF cfffont(cff);
2070
//      cfffont.dump();
2071
//      QByteArray subsetfont = cff::subsetFace(cff, it.value().keys());
2072
//      dumpFont(it.key() + "subs.cff", subsetfont);
2073
//      cff::CFF subset(subsetfont);
2074
//      subset.dump();
2075
//      PDF_WriteFontDescriptor(fontName, face, fformat, 0);
2076
//      // END
2077
 
20136 avox 2078
        QByteArray font, data;
2079
        face.RawData(data);
2080
        font = sfnt::getTable(data, "CFF ");
20974 jghali 2081
        /*dumpFont(face.psName() + ".cff", font);*/
20112 jghali 2082
        QList<ScFace::gid_type> glyphs = RealGlyphs.uniqueKeys();
2083
        glyphs.removeAll(0);
2084
        glyphs.prepend(0);
2085
        QByteArray subset = cff::subsetFace(font, glyphs);
20974 jghali 2086
        /*dumpFont(face.psName()+"subs.cff", subset);*/
20112 jghali 2087
        PdfId embeddedFontObj = PDF_EmbedFontObject(subset, "/CIDFontType0C");
2088
        PdfId fontDes = PDF_WriteFontDescriptor(fontName, face, face.format(), embeddedFontObj);
21759 jghali 2089
        QByteArray baseFont = sanitizeFontName(face.psName());
20112 jghali 2090
        ScFace::FaceEncoding fullEncoding, subEncoding;
2091
        QMap<uint,uint> glyphmap;
2092
        face.glyphNames(fullEncoding);
2093
        for (int i = 0; i < glyphs.length(); ++i)
2094
        {
2095
                glyphmap[glyphs[i]] = i;
2096
                qDebug() << glyphs[i] << " --> " << i << QChar(fullEncoding[glyphs[i]].first);
2097
        }
2098
 
2099
        PdfFont result = PDF_EncodeCidFont(fontName, face, baseFont, fontDes, fullEncoding, glyphmap);
2100
        return result;
20103 avox 2101
}
2102
 
2103
 
2104
PdfId PDFLibCore::PDF_EmbedType1AsciiFontObject(const QByteArray& fon)
2105
{
20112 jghali 2106
        QByteArray fon2;
2107
        PdfId embeddedFontObject = writer.newObject();
2108
        writer.startObj(embeddedFontObject);
2109
        int len1 = fon.indexOf("eexec")+5;
2110
        fon2 = fon.left(len1) + "\n";
2111
        int len2 = fon.indexOf("0000000000000000000000000");
2112
        if (len2 == -1)
2113
                len2 = fon.length()+1;
2114
        //                        QString tm;
2115
        //                        uint value;
2116
        //                        bool ok = true;
2117
        //                              int count = 0;
2118
        //                              for (int xx = len1; xx < len2-1; ++xx)
2119
        //                              {
2120
        //                                      tm = fon.at(xx);
2121
        //                                      if ((tm == QChar(13)) || (tm == QChar(10)))
2122
        //                                              continue;
2123
        //                                      xx++;
2124
        //                                      count++;
2125
        //                                      tm += fon.at(xx);
2126
        //                                      value = tm.toUInt(&ok, 16);
2127
        //                                      fon2 += char(value);
2128
        //                              }
2129
        QByteArray hexData = QByteArray::fromHex(fon.mid(len1, len2-len1));
2130
        fon2 += hexData;
2131
        fon2 += fon.mid(len2);
2132
        if (Options.Compress)
2133
                fon2 = CompressArray(fon2);
2134
        PutDoc("<<\n/Length "+Pdf::toPdf(fon2.length()+1)+"\n");
2135
        PutDoc("/Length1 "+Pdf::toPdf(len1+1)+"\n");
2136
        PutDoc("/Length2 "+Pdf::toPdf(hexData.length())+"\n");
2137
        if(static_cast<int>(fon.length()-len2) == -1)
2138
                PutDoc("/Length3 0\n");
2139
        else
2140
                PutDoc("/Length3 "+Pdf::toPdf(fon.length()-len2)+"\n");
2141
        if (Options.Compress)
2142
                PutDoc("/Filter /FlateDecode\n");
2143
        PutDoc(">>\nstream\n"+EncStream(fon2, embeddedFontObject)+"\nendstream");
2144
        writer.endObj(embeddedFontObject);
2145
        return embeddedFontObject;
20103 avox 2146
}
2147
 
2148
 
2149
PdfId PDFLibCore::PDF_EmbedType1BinaryFontObject(const QByteArray& bb)
2150
{
20112 jghali 2151
        PdfId embeddedFontObject = writer.newObject();
2152
        QByteArray fon;
2153
        writer.startObj(embeddedFontObject);
2154
        int posi;
2155
        for (posi = 6; posi < bb.size(); ++posi)
2156
        {
2157
                if ((bb[posi] == static_cast<char>(0x80)) && (static_cast<int>(bb[posi+1]) == 2))
2158
                        break;
2159
                fon += bb[posi];
2160
        }
2161
        int len1 = fon.length();
2162
        int ulen;
2163
        ulen = bb[posi+2] & 0xff;
2164
&nb