DtkWidget
DTK Widget module
载入中...
搜索中...
未找到
dprintpreviewwidget_p.h
1// SPDX-FileCopyrightText: 2019 - 2026 UnionTech Software Technology Co., Ltd.
2//
3// SPDX-License-Identifier: LGPL-3.0-or-later
4
5#ifndef DPRINTPREVIEWWIDGET_P_H
6#define DPRINTPREVIEWWIDGET_P_H
7
8#include <dprintpreviewwidget.h>
9#include "dframe_p.h"
10
11#include <DIconButton>
12
13#include <QGraphicsScene>
14#include <QGraphicsView>
15#include <QWheelEvent>
16#include <QPicture>
17#include <qmath.h>
18#include <QBasicTimer>
19
20DWIDGET_BEGIN_NAMESPACE
21
22#define PREVIEW_WIDGET_MARGIN_RATIO 50
23#define PREVIEW_ENLARGE_RATIO 1.25
24#define PREVIEW_NARROW_RATIO 0.8
25#define PREVIEW_SCALEBUTTON_MARGIN 10
26#define PREVIEW_WATER_COUNT_WIDTH 28
27#define PREVIEW_WATER_COUNT_HEIGHT 20
28#define PREVIEW_WATER_COUNT_SPACE 10
29#define NUMBERUP_SCALE_RATIO 1.05
30#define NUMBERUP_SPACE_SCALE_RATIO 0.05
31
32class GraphicsView : public QGraphicsView
33{
34 Q_OBJECT
35public:
36 GraphicsView(QWidget *parent = nullptr);
37
38public Q_SLOTS:
39 void resetScale(bool autoReset = true);
40
41Q_SIGNALS:
42 void resized();
43
44protected:
45 void mousePressEvent(QMouseEvent *e) override;
46 void mouseReleaseEvent(QMouseEvent *e) override;
47 void wheelEvent(QWheelEvent *e) override;
48 void resizeEvent(QResizeEvent *e) override;
49 void showEvent(QShowEvent *e) override;
50 void changeEvent(QEvent *e) override;
51
52private Q_SLOTS:
53 void onThemeTypeChanged(DGuiApplicationHelper::ColorType themeType);
54
55private:
56 DIconButton *scaleResetButton;
57 double scaleRatio;
58};
59
60class ContentItem : public QGraphicsItem
61{
62public:
63 ContentItem(const QPicture *_pagePicture, QRect _pageRect, QGraphicsItem *parent = nullptr)
64 : QGraphicsItem(parent)
65 , pagePicture(_pagePicture)
66 , pageRect(_pageRect)
67 {
68 brect = QRectF(QPointF(0, 0), QSizeF(pageRect.size()));
69 setCacheMode(DeviceCoordinateCache);
70 setPos(pageRect.topLeft());
71 }
72
73 QRectF boundingRect() const override
74 {
75 return brect;
76 }
77
78 void setRect(const QRectF &rect)
79 {
80 setPos(rect.topLeft());
81 brect = QRectF(QPointF(0, 0), QSizeF(rect.size()));
82 }
83
84 void paint(QPainter *painter, const QStyleOptionGraphicsItem *item, QWidget *widget) override;
85 void updateGrayContent();
86 void drawNumberUpPictures(QPainter *painter);
87
88protected:
89 QPicture grayscalePaint(const QPicture &picture);
90 QImage imageGrayscale(const QImage *origin);
91
92private:
93 const QPicture *pagePicture;
94 QRect pageRect;
95 QRectF brect;
96 QPicture grayPicture;
97};
98
99class WaterMark : public QGraphicsItem
100{
101public:
102 enum Type {
103 None,
104 Text,
105 Image
106 };
107 enum Layout {
108 Center,
109 Tiled
110 };
111 WaterMark(QGraphicsItem *parent = nullptr)
112 : QGraphicsItem(parent)
113 , type(None)
114 , layout(Center)
115 {
116 }
117
118 inline void setType(Type t)
119 {
120 type = t;
121 }
122 inline Type getType() const
123 {
124 return type;
125 }
126 inline void setLayoutType(Layout l)
127 {
128 layout = l;
129 }
130 inline void setScaleFactor(qreal scale)
131 {
132 mScaleFactor = scale;
133 }
134 void setImage(const QImage &img);
135 inline void setText(const QString str)
136 {
137 type = Text;
138 text = str;
139 }
140 inline void setFont(const QFont &f)
141 {
142 font = f;
143 }
144 inline QFont getFont() const
145 {
146 return font;
147 }
148 inline void setColor(const QColor &c)
149 {
150 color = c;
151 }
152 inline QColor getColor() const
153 {
154 return color;
155 }
156 inline void setBoundingRect(const QRectF &rect)
157 {
158 qreal rotate = rotation();
159 setRotation(0);
160 brect = rect;
161 brectPolygon = mapToScene(brect);
162 qreal width = brect.width();
163 qreal height = brect.height();
164 // 取斜边为宽度的矩形 使旋转时始终保持页面在水印内部
165 qreal maxDis = qSqrt(qPow(width, 2) + qPow(height, 2));
166 twoPolygon = mapToScene(QRectF(QPointF(brect.center().x() - maxDis / 2, brect.center().y() - maxDis / 2), QSizeF(maxDis, maxDis)));
167 setTransformOriginPoint(brect.center());
168 setRotation(rotate);
169 }
170 QRectF boundingRect() const override
171 {
172 return mapToScene(brect.toRect()).boundingRect();
173 }
174 inline QPolygonF itemMaxPolygon() const
175 {
176 return twoPolygon;
177 }
178 void paint(QPainter *painter, const QStyleOptionGraphicsItem *item, QWidget *widget) override;
179 void updatePicture(QPainter *painter, bool isPreview);
180
181 void setNumberUpScale(const qreal &value);
182
183protected:
184 QPainterPath itemClipPath() const;
185
186private:
187 Type type;
188 Layout layout;
189 QImage sourceImage;
190 QImage graySourceImage;
191 QImage targetImage;
192 QRectF brect;
193 qreal mScaleFactor = 1.0;
194 QGraphicsTextItem textItem;
195 QString text;
196 QFont font;
197 QColor color;
198 qreal numberUpScale = 1;
199
200 QPolygonF brectPolygon;
201 QPolygonF twoPolygon;
202 friend class DPrintPreviewWidgetPrivate;
203};
204
205class PageItem : public QGraphicsItem
206{
207public:
208 PageItem(int _pageNum, const QPicture *_pagePicture, QSize _paperSize, QRect _pageRect)
209 : pageNum(_pageNum)
210 , pagePicture(_pagePicture)
211 , paperSize(_paperSize)
212 , pageRect(_pageRect)
213 , content(new ContentItem(_pagePicture, _pageRect, this))
214 {
215 qreal border = qMax(paperSize.height(), paperSize.width()) / PREVIEW_WIDGET_MARGIN_RATIO;
216 brect = QRectF(QPointF(-border, -border),
217 QSizeF(paperSize) + QSizeF(2 * border, 2 * border));
218 setCacheMode(DeviceCoordinateCache);
219 }
220
221 QRectF boundingRect() const override
222 {
223 return brect;
224 }
225
226 inline int pageNumber() const
227 {
228 return pageNum;
229 }
230
231 void paint(QPainter *painter, const QStyleOptionGraphicsItem *item, QWidget *widget) override;
232
233 void setVisible(bool isVisible);
234
235private:
236 int pageNum;
237 const QPicture *pagePicture;
238 QSize paperSize;
239 QRect pageRect;
240 QRectF brect;
241 ContentItem *content;
242};
243
244typedef QList<QPair<QByteArray, QByteArray>> PrintOptions;
246{
247public:
248 // 水印刷新机制,包括立刻刷新和延时刷新
249 enum RefreshMode { RefreshImmediately,
250 RefreshDelay };
252
253 void init();
254 void populateScene();
255 void updatePreview();
256 void generatePreview();
257 void fitView();
258 void print(bool printAsPicture = false);
259 void updatePageByPagePrintVector(QVector<int> &pageVector, QList<const QPicture *> &pictures) const;
260 void asynPrint(const QPointF &leftTop, const QRect &pageRect, const QVector<int> &pageVector);
261 void syncPrint(const QPointF &leftTop, const QRect &pageRect, const QVector<int> &pageVector);
262 void printAsImage(const QSize &paperSize, QVector<int> &pageVector);
263 void printSinglePageDrawUtil(QPainter *painter, const QSize &translateSize, const QPointF &leftTop, const QImage &waterImage, const QPicture *picture);
264 void printMultiPageDrawUtil(QPainter *painter, const QPointF &leftTop, const QImage &waterImage);
265
266 void setPageRangeAll();
267 void setCurrentPage(int page);
268 int pagesCount();
269 int targetPage(int page);
270 int index2page(int index);
271 int page2index(int page);
272#if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0)
273 D_DECL_DEPRECATED void impositionPages(); // 拼版
274#endif
275 int impositionPages(DPrintPreviewWidget::Imposition im); // 每页版数
276 QImage generateWaterMarkImage() const;
277 PrintOptions printerOptions();
278#ifdef Q_OS_LINUX
279 void printByCups();
280#endif
281
282 void generatePreviewPicture();// 发送requestPaint信号,重新获取原文档数据
283 void calculateNumberUpPage();// 重绘页面,当拼版数改变、纸张大小等操作时必须调用,
284 void calculateNumberPagePosition();// 计算每小页面的显示位置
285
286 void updateNumberUpContent();
287 QVector<int> requestPages(int page);// 取处理后page页的小页面
288 void releaseImpositionData();// 并打切换单页时需要释放水印、页面拼版数据
289
290 void displayWaterMarkItem();// 添加或更新水印效果,
291 void calculateNumberPageScale();// 计算缩放比,拼版数发生改变需要调用
292 void calculateCurrentNumberPage();// page是相对于原文档,添加page页需要显示的小页面到Vector
293#ifdef Q_OS_LINUX
294 QByteArray foundColorModelByCups() const;
295#endif
296
297 inline void setCurrentPageNumber(int page)
298 {
299 currentPageNumber = page;
300 }
301
302 GraphicsView *graphicsView;
303 QGraphicsScene *scene;
304
305 QList<QPicture> targetPictures;
306 QList<const QPicture *> pictures;
307 QList<QGraphicsItem *> pages;
308 QGraphicsRectItem *background;
309 WaterMark *waterMark;
310 QVector<int> pageRange; // 选择的页码
311 int currentPageNumber = 0; // 处理以后当前页,值一定是连续的,比如处理共10页,那么取值就是1到10
312 DPrinter::ColorMode colorMode;
313 DPrintPreviewWidget::Imposition imposition;
314 DPrintPreviewWidget::Order order;
315 qreal scale = 1.0;
316 DPrintPreviewWidget::PageRange pageRangeMode = DPrintPreviewWidget::AllPage;
317#if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0)
318 D_DECL_DEPRECATED bool reviewChanged = true; // 预览页面是否发生改变
319#endif
320 DPrinter *previewPrinter;
321 RefreshMode refreshMode;
322
323 QString printFromPath;
324 DPrintPreviewWidget::PrintMode printMode;
325 bool isAsynPreview;
326 QVector<int> previewPages;
327 bool asynPreviewNeedUpdate;
328 int asynPreviewTotalPage;
329 int pageCopyCount = 0;
330 bool isFirstPage;
331
332 struct NumberUpData;
333 NumberUpData *numberUpPrintData;
334 QBasicTimer updateTimer;
335 Q_DECLARE_PUBLIC(DPrintPreviewWidget)
336};
337
339 class NumberItem : public QGraphicsItem
340 {
341 public:
342 NumberItem(QVector<int> _pageNumberVector, QVector<QPointF> _numberPointVector, QRect _pageRect)
343 : numberVector(_pageNumberVector)
344 , numberPointVector(_numberPointVector)
345 {
346 brect = QRectF(QPointF(0, 0), QSizeF(_pageRect.size()));
347 setCacheMode(DeviceCoordinateCache);
348 setPos(_pageRect.topLeft());
349 }
350
351 inline void setPageNumbers(const QVector<int> &pageNumber)
352 {
353 numberVector = pageNumber;
354 }
355
356 inline void setNumberPositon(const QVector<QPointF> &numberPos)
357 {
358 numberPointVector = numberPos;
359 }
360
361 QRectF boundingRect() const override
362 {
363 return brect;
364 }
365
366 void setRect(const QRectF &rect)
367 {
368 setPos(rect.topLeft());
369 brect = QRectF(QPointF(0, 0), QSizeF(rect.size()));
370 }
371
372 void paint(QPainter *painter, const QStyleOptionGraphicsItem *item, QWidget *widget) override;
373
374 private:
375 QRectF brect;
376 QVector<int> numberVector; // 页码
377 QVector<QPointF> numberPointVector; // 坐标
378 };
379
381 WaterMark::Layout layout;
382 WaterMark::Type type;
383 qreal rotation;
384 qreal scale;
385 qreal opacity;
386 QColor color;
387 QString text;
388 QImage sourceImage;
389 QImage grayImage;
390 QFont font;
391 };
392
393 QVector<QPair<int, const QPicture *>> previewPictures; // 并打当前页面属性列表(页码,图片)
394 QVector<QPointF> paintPoints; // 并打单页位置属性列表
395 qreal scaleRatio; // 并打页面缩放因子
396 int rowCount; // 并打页面行数
397 int columnCount; // 并打页面列数
398 QPointF pageStartPoint; // 并打单页起始位置
399 QList<WaterMark *> waterList; // 并打时水印
400 WaterMarkProperty *waterProperty;
401 NumberItem *numberItem;
402 QGraphicsRectItem *waterParentItem;
403 bool needRecreateWater; // 重绘时不管当前页面水印数量和内容数量一致 都要重新生成页面 因为页面大小发生了变化
405
406 void resetData()
407 {
408 scaleRatio = 1;
409 rowCount = 0;
410 columnCount = 0;
411 pageStartPoint = QPointF(0, 0);
412 }
413
414 QVector<QPointF> updatePositions(const qreal &scale)
415 {
416#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
417 QRectF pageRect = parent->previewPrinter->pageLayout().paintRectPixels(parent->previewPrinter->resolution());
418#else
419 QRectF pageRect = parent->previewPrinter->pageRect();
420#endif
421 QVector<QPointF> posList;
422 QPointF startP(0, 0);
423
424 QPointF topLeft;
425 if (scale >= 1.0) {
426 topLeft = QPointF(0, 0);
427 if ((parent->imposition == DPrintPreviewWidget::OneRowTwoCol) || (parent->imposition == DPrintPreviewWidget::TwoRowThreeCol)) {
428 topLeft.setY(pageStartPoint.y() * (scale - 1.0));
429 }
430 } else {
431 topLeft.setX(pageRect.width() * (1.0 - scale) / 2.0);
432 topLeft.setY((NUMBERUP_SCALE_RATIO * rowCount - NUMBERUP_SPACE_SCALE_RATIO) * pageRect.height() * scaleRatio * (1.0 - scale) / 2.0);
433 }
434
435 switch (parent->order) {
436 case DPrintPreviewWidget::Copy:
437 case DPrintPreviewWidget::L2R_T2B: {
438 startP = pageStartPoint + topLeft;
439 for (int i = 0; i < rowCount; ++i) {
440 for (int j = 0; j < columnCount; ++j) {
441 posList.append(startP + QPointF(NUMBERUP_SCALE_RATIO * j * pageRect.width(), NUMBERUP_SCALE_RATIO * i * pageRect.height()) * scaleRatio * scale);
442 }
443 }
444 } break;
445 // R2L 从右往左扩大 应为从0,0开始扩大 需增加一个expanding使其从左往右扩张
446 case DPrintPreviewWidget::R2L_T2B: {
447 qreal expanding = scale > 1 ? pageRect.width() * (scale - 1) : 0;
448 startP = pageStartPoint - QPointF(topLeft.x() - expanding - pageRect.width(), -topLeft.y());
449 for (int i = 0; i < rowCount; ++i) {
450 for (int j = 0; j < columnCount; ++j) {
451 posList.append(startP - QPointF((NUMBERUP_SCALE_RATIO * j + 1) * pageRect.width(), -(NUMBERUP_SCALE_RATIO * i) * pageRect.height()) * scaleRatio * scale);
452 }
453 }
454 } break;
455 case DPrintPreviewWidget::T2B_L2R: {
456 startP = pageStartPoint + topLeft;
457 for (int i = 0; i < columnCount; ++i) {
458 for (int j = 0; j < rowCount; ++j) {
459 posList.append(startP + QPointF(NUMBERUP_SCALE_RATIO * i * pageRect.width(), NUMBERUP_SCALE_RATIO * j * pageRect.height()) * scaleRatio * scale);
460 }
461 }
462 } break;
463 case DPrintPreviewWidget::T2B_R2L: {
464 qreal expanding = scale > 1 ? pageRect.width() * (scale - 1) : 0;
465 startP = pageStartPoint - QPointF(topLeft.x() - expanding - pageRect.width(), -topLeft.y());
466 for (int i = 0; i < columnCount; ++i) {
467 for (int j = 0; j < rowCount; ++j) {
468 posList.append(startP - QPointF((NUMBERUP_SCALE_RATIO * i + 1) * pageRect.width(), -(NUMBERUP_SCALE_RATIO * j) * pageRect.height()) * scaleRatio * scale);
469 }
470 }
471 } break;
472 }
473
474 return posList;
475 }
476
477 void setWaterMarksScale(qreal scale)
478 {
479 if (waterList.isEmpty())
480 return;
481#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
482 QRectF pageRect = parent->previewPrinter->pageLayout().paintRectPixels(parent->previewPrinter->resolution());
483#else
484 QRectF pageRect = parent->previewPrinter->pageRect();
485#endif
486 QMargins pageMargins = parent->previewPrinter->pageLayout().marginsPixels(parent->previewPrinter->resolution());
487 const QVector<QPointF> &posList = updatePositions(scale);
488
489 for (int c = 0; c < waterList.count(); ++c) {
490 WaterMark *item = waterList.at(c);
491 item->setBoundingRect(QRectF(QPointF(pageMargins.left(), pageMargins.top()) + posList.at(c), pageRect.size() * scaleRatio * scale));
492 item->update();
493 }
494
495 if (numberItem)
496 numberItem->update();
497 }
498
499 void setWaterMarkOriginProperties(WaterMark *wm)
500 {
501 if (!wm || !waterProperty)
502 return;
503
504 wm->type = waterProperty->type;
505 wm->layout = waterProperty->layout;
506 wm->mScaleFactor = waterProperty->scale;
507 wm->color = waterProperty->color;
508 wm->text = waterProperty->text;
509 wm->sourceImage = waterProperty->sourceImage;
510 wm->graySourceImage = waterProperty->grayImage;
511 wm->font = waterProperty->font;
512 wm->setRotation(waterProperty->rotation);
513 wm->setOpacity(waterProperty->opacity);
514 }
515
516 void copyWaterMarkProperties()
517 {
518 // 当并打属性发生变化的时候 需要删除当前页面中的水印层
519 // 因此需要保存当前层的水印效果以便创建时直接添加
520 if (!parent->waterMark && waterList.isEmpty())
521 return;
522
523 WaterMark *wm;
524 if (waterList.isEmpty()) {
525 wm = parent->waterMark;
526 } else {
527 wm = waterList.first();
528 }
529
530 if (!waterProperty)
531 waterProperty = new WaterMarkProperty;
532
533 waterProperty->type = wm->type;
534 waterProperty->layout = wm->layout;
535 waterProperty->rotation = wm->rotation();
536 waterProperty->scale = wm->mScaleFactor;
537 waterProperty->opacity = wm->opacity();
538 waterProperty->color = wm->color;
539 waterProperty->text = wm->text;
540 waterProperty->sourceImage = wm->sourceImage;
541 waterProperty->grayImage = wm->graySourceImage;
542 waterProperty->font = wm->font;
543 }
544
545 void updateWaterMarks()
546 {
547 if (waterList.isEmpty())
548 return;
549
550 for (auto *item : std::as_const(waterList))
551 item->update();
552 }
553
554 template<typename T>
555 void setWaterMarkProperty(T outFunction)
556 {
557 if (waterList.isEmpty())
558 return;
559
560 auto *firstWm = waterList.first();
561 outFunction(firstWm);
562
563 for (auto *item : std::as_const(waterList)) {
564 if (item == firstWm)
565 continue;
566
567 // TODO: remove it in dtkwidget 5.6.
568 item->type = firstWm->type;
569 item->layout = firstWm->layout;
570 item->mScaleFactor = firstWm->mScaleFactor;
571 item->color = firstWm->color;
572 item->text = firstWm->text;
573 item->sourceImage = firstWm->sourceImage;
574 item->graySourceImage = firstWm->graySourceImage;
575 item->font = firstWm->font;
576 item->setRotation(firstWm->rotation());
577 item->setOpacity(firstWm->opacity());
578 }
579 }
580
581 NumberUpData(DPrintPreviewWidgetPrivate *parent)
582 : previewPictures(0)
583 , paintPoints(0)
584 , scaleRatio(1)
585 , rowCount(0)
586 , columnCount(0)
587 , pageStartPoint(0, 0)
588 , waterProperty(nullptr)
589 , numberItem(nullptr)
590 , waterParentItem(nullptr)
591 , needRecreateWater(false)
592 , parent(parent)
593 {
594 }
595
596 ~NumberUpData()
597 {
598 delete waterProperty;
599 delete numberItem;
600 delete waterParentItem;
601 }
602};
603
604DWIDGET_END_NAMESPACE
605Q_DECLARE_TYPEINFO(DTK_WIDGET_NAMESPACE::DPrintPreviewWidgetPrivate::NumberUpData::WaterMarkProperty, Q_PRIMITIVE_TYPE);
606#endif // DPRINTPREVIEWWIDGET_P_H
Definition dprintpreviewwidget_p.h:61
Definition dframe_p.h:17
按钮的图标
Definition diconbutton.h:24
Definition dprintpreviewwidget_p.h:246
Definition dprintpreviewwidget.h:45
Definition dprintpreviewwidget.h:30
Definition dprintpreviewwidget_p.h:33
Definition dprintpreviewwidget_p.h:206
Definition dprintpreviewwidget_p.h:100
Definition dprintpreviewwidget_p.h:338