Subversion Repositories Scribus

Rev

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