DtkWidget 5.6.0.2
DTK Widget module
dprintpreviewwidget_p.h
1// SPDX-FileCopyrightText: 2019 - 2022 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
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 D_DECL_DEPRECATED void impositionPages(); // 拼版
273 int impositionPages(DPrintPreviewWidget::Imposition im); // 每页版数
274 QImage generateWaterMarkImage() const;
275 PrintOptions printerOptions();
276 void printByCups();
277
278 void generatePreviewPicture();// 发送requestPaint信号,重新获取原文档数据
279 void calculateNumberUpPage();// 重绘页面,当拼版数改变、纸张大小等操作时必须调用,
280 void calculateNumberPagePosition();// 计算每小页面的显示位置
281
282 void updateNumberUpContent();
283 QVector<int> requestPages(int page);// 取处理后page页的小页面
284 void releaseImpositionData();// 并打切换单页时需要释放水印、页面拼版数据
285
286 void displayWaterMarkItem();// 添加或更新水印效果,
287 void calculateNumberPageScale();// 计算缩放比,拼版数发生改变需要调用
288 void calculateCurrentNumberPage();// page是相对于原文档,添加page页需要显示的小页面到Vector
289 QByteArray foundColorModelByCups() const;
290
291 inline void setCurrentPageNumber(int page)
292 {
293 currentPageNumber = page;
294 }
295
296 GraphicsView *graphicsView;
297 QGraphicsScene *scene;
298
299 QList<QPicture> targetPictures;
302 QGraphicsRectItem *background;
303 WaterMark *waterMark;
304 QVector<int> pageRange; // 选择的页码
305 int currentPageNumber = 0; // 处理以后当前页,值一定是连续的,比如处理共10页,那么取值就是1到10
306 DPrinter::ColorMode colorMode;
307 DPrintPreviewWidget::Imposition imposition;
308 DPrintPreviewWidget::Order order;
309 qreal scale = 1.0;
310 DPrintPreviewWidget::PageRange pageRangeMode = DPrintPreviewWidget::AllPage;
311 D_DECL_DEPRECATED bool reviewChanged = true; // 预览页面是否发生改变
312
313 DPrinter *previewPrinter;
314 RefreshMode refreshMode;
315
316 QString printFromPath;
317 DPrintPreviewWidget::PrintMode printMode;
318 bool isAsynPreview;
319 QVector<int> previewPages;
320 bool asynPreviewNeedUpdate;
321 int asynPreviewTotalPage;
322 int pageCopyCount = 0;
323 bool isFirstPage;
324
325 struct NumberUpData;
326 NumberUpData *numberUpPrintData;
327 QBasicTimer updateTimer;
328 Q_DECLARE_PUBLIC(DPrintPreviewWidget)
329};
330
332 class NumberItem : public QGraphicsItem
333 {
334 public:
335 NumberItem(QVector<int> _pageNumberVector, QVector<QPointF> _numberPointVector, QRect _pageRect)
336 : numberVector(_pageNumberVector)
337 , numberPointVector(_numberPointVector)
338 {
339 brect = QRectF(QPointF(0, 0), QSizeF(_pageRect.size()));
340 setCacheMode(DeviceCoordinateCache);
341 setPos(_pageRect.topLeft());
342 }
343
344 inline void setPageNumbers(const QVector<int> &pageNumber)
345 {
346 numberVector = pageNumber;
347 }
348
349 inline void setNumberPositon(const QVector<QPointF> &numberPos)
350 {
351 numberPointVector = numberPos;
352 }
353
354 QRectF boundingRect() const override
355 {
356 return brect;
357 }
358
359 void setRect(const QRectF &rect)
360 {
361 setPos(rect.topLeft());
362 brect = QRectF(QPointF(0, 0), QSizeF(rect.size()));
363 }
364
365 void paint(QPainter *painter, const QStyleOptionGraphicsItem *item, QWidget *widget) override;
366
367 private:
368 QRectF brect;
369 QVector<int> numberVector; // 页码
370 QVector<QPointF> numberPointVector; // 坐标
371 };
372
374 WaterMark::Layout layout;
375 WaterMark::Type type;
376 qreal rotation;
377 qreal scale;
378 qreal opacity;
379 QColor color;
380 QString text;
381 QImage sourceImage;
382 QImage grayImage;
383 QFont font;
384 };
385
386 QVector<QPair<int, const QPicture *>> previewPictures; // 并打当前页面属性列表(页码,图片)
387 QVector<QPointF> paintPoints; // 并打单页位置属性列表
388 qreal scaleRatio; // 并打页面缩放因子
389 int rowCount; // 并打页面行数
390 int columnCount; // 并打页面列数
391 QPointF pageStartPoint; // 并打单页起始位置
392 QList<WaterMark *> waterList; // 并打时水印
393 WaterMarkProperty *waterProperty;
394 NumberItem *numberItem;
395 QGraphicsRectItem *waterParentItem;
396 bool needRecreateWater; // 重绘时不管当前页面水印数量和内容数量一致 都要重新生成页面 因为页面大小发生了变化
398
399 void resetData()
400 {
401 scaleRatio = 1;
402 rowCount = 0;
403 columnCount = 0;
404 pageStartPoint = QPointF(0, 0);
405 }
406
407 QVector<QPointF> updatePositions(const qreal &scale)
408 {
409 QRectF pageRect = parent->previewPrinter->pageRect();
410 QVector<QPointF> posList;
411 QPointF startP(0, 0);
412
413 QPointF topLeft;
414 if (scale >= 1.0) {
415 topLeft = QPointF(0, 0);
416 if ((parent->imposition == DPrintPreviewWidget::OneRowTwoCol) || (parent->imposition == DPrintPreviewWidget::TwoRowThreeCol)) {
417 topLeft.setY(pageStartPoint.y() * (scale - 1.0));
418 }
419 } else {
420 topLeft.setX(pageRect.width() * (1.0 - scale) / 2.0);
421 topLeft.setY((NUMBERUP_SCALE_RATIO * rowCount - NUMBERUP_SPACE_SCALE_RATIO) * pageRect.height() * scaleRatio * (1.0 - scale) / 2.0);
422 }
423
424 switch (parent->order) {
425 case DPrintPreviewWidget::Copy:
426 case DPrintPreviewWidget::L2R_T2B: {
427 startP = pageStartPoint + topLeft;
428 for (int i = 0; i < rowCount; ++i) {
429 for (int j = 0; j < columnCount; ++j) {
430 posList.append(startP + QPointF(NUMBERUP_SCALE_RATIO * j * pageRect.width(), NUMBERUP_SCALE_RATIO * i * pageRect.height()) * scaleRatio * scale);
431 }
432 }
433 } break;
434 // R2L 从右往左扩大 应为从0,0开始扩大 需增加一个expanding使其从左往右扩张
435 case DPrintPreviewWidget::R2L_T2B: {
436 qreal expanding = scale > 1 ? pageRect.width() * (scale - 1) : 0;
437 startP = pageStartPoint - QPointF(topLeft.x() - expanding - pageRect.width(), -topLeft.y());
438 for (int i = 0; i < rowCount; ++i) {
439 for (int j = 0; j < columnCount; ++j) {
440 posList.append(startP - QPointF((NUMBERUP_SCALE_RATIO * j + 1) * pageRect.width(), -(NUMBERUP_SCALE_RATIO * i) * pageRect.height()) * scaleRatio * scale);
441 }
442 }
443 } break;
444 case DPrintPreviewWidget::T2B_L2R: {
445 startP = pageStartPoint + topLeft;
446 for (int i = 0; i < columnCount; ++i) {
447 for (int j = 0; j < rowCount; ++j) {
448 posList.append(startP + QPointF(NUMBERUP_SCALE_RATIO * i * pageRect.width(), NUMBERUP_SCALE_RATIO * j * pageRect.height()) * scaleRatio * scale);
449 }
450 }
451 } break;
452 case DPrintPreviewWidget::T2B_R2L: {
453 qreal expanding = scale > 1 ? pageRect.width() * (scale - 1) : 0;
454 startP = pageStartPoint - QPointF(topLeft.x() - expanding - pageRect.width(), -topLeft.y());
455 for (int i = 0; i < columnCount; ++i) {
456 for (int j = 0; j < rowCount; ++j) {
457 posList.append(startP - QPointF((NUMBERUP_SCALE_RATIO * i + 1) * pageRect.width(), -(NUMBERUP_SCALE_RATIO * j) * pageRect.height()) * scaleRatio * scale);
458 }
459 }
460 } break;
461 }
462
463 return posList;
464 }
465
466 void setWaterMarksScale(qreal scale)
467 {
468 if (waterList.isEmpty())
469 return;
470
471 QRectF pageRect = parent->previewPrinter->pageRect();
472 QMargins pageMargins = parent->previewPrinter->pageLayout().marginsPixels(parent->previewPrinter->resolution());
473 const QVector<QPointF> &posList = updatePositions(scale);
474
475 for (int c = 0; c < waterList.count(); ++c) {
476 WaterMark *item = waterList.at(c);
477 item->setBoundingRect(QRectF(QPointF(pageMargins.left(), pageMargins.top()) + posList.at(c), pageRect.size() * scaleRatio * scale));
478 item->update();
479 }
480
481 if (numberItem)
482 numberItem->update();
483 }
484
485 void setWaterMarkOriginProperties(WaterMark *wm)
486 {
487 if (!wm || !waterProperty)
488 return;
489
490 wm->type = waterProperty->type;
491 wm->layout = waterProperty->layout;
492 wm->mScaleFactor = waterProperty->scale;
493 wm->color = waterProperty->color;
494 wm->text = waterProperty->text;
495 wm->sourceImage = waterProperty->sourceImage;
496 wm->graySourceImage = waterProperty->grayImage;
497 wm->font = waterProperty->font;
498 wm->setRotation(waterProperty->rotation);
499 wm->setOpacity(waterProperty->opacity);
500 }
501
502 void copyWaterMarkProperties()
503 {
504 // 当并打属性发生变化的时候 需要删除当前页面中的水印层
505 // 因此需要保存当前层的水印效果以便创建时直接添加
506 if (!parent->waterMark && waterList.isEmpty())
507 return;
508
509 WaterMark *wm;
510 if (waterList.isEmpty()) {
511 wm = parent->waterMark;
512 } else {
513 wm = waterList.first();
514 }
515
516 if (!waterProperty)
517 waterProperty = new WaterMarkProperty;
518
519 waterProperty->type = wm->type;
520 waterProperty->layout = wm->layout;
521 waterProperty->rotation = wm->rotation();
522 waterProperty->scale = wm->mScaleFactor;
523 waterProperty->opacity = wm->opacity();
524 waterProperty->color = wm->color;
525 waterProperty->text = wm->text;
526 waterProperty->sourceImage = wm->sourceImage;
527 waterProperty->grayImage = wm->graySourceImage;
528 waterProperty->font = wm->font;
529 }
530
531 void updateWaterMarks()
532 {
533 if (waterList.isEmpty())
534 return;
535
536 for (auto *item : qAsConst(waterList))
537 item->update();
538 }
539
540 template<typename T>
541 void setWaterMarkProperty(T outFunction)
542 {
543 if (waterList.isEmpty())
544 return;
545
546 auto *firstWm = waterList.first();
547 outFunction(firstWm);
548
549 for (auto *item : qAsConst(waterList)) {
550 if (item == firstWm)
551 continue;
552
553 // TODO: remove it in dtkwidget 5.6.
554 item->type = firstWm->type;
555 item->layout = firstWm->layout;
556 item->mScaleFactor = firstWm->mScaleFactor;
557 item->color = firstWm->color;
558 item->text = firstWm->text;
559 item->sourceImage = firstWm->sourceImage;
560 item->graySourceImage = firstWm->graySourceImage;
561 item->font = firstWm->font;
562 item->setRotation(firstWm->rotation());
563 item->setOpacity(firstWm->opacity());
564 }
565 }
566
567 NumberUpData(DPrintPreviewWidgetPrivate *parent)
568 : previewPictures(0)
569 , paintPoints(0)
570 , scaleRatio(1)
571 , rowCount(0)
572 , columnCount(0)
573 , pageStartPoint(0, 0)
574 , waterProperty(nullptr)
575 , numberItem(nullptr)
576 , waterParentItem(nullptr)
577 , needRecreateWater(false)
578 , parent(parent)
579 {
580 }
581
582 ~NumberUpData()
583 {
584 delete waterProperty;
585 delete numberItem;
586 delete waterParentItem;
587 }
588};
589
590DWIDGET_END_NAMESPACE
591Q_DECLARE_TYPEINFO(DTK_WIDGET_NAMESPACE::DPrintPreviewWidgetPrivate::NumberUpData::WaterMarkProperty, Q_PRIMITIVE_TYPE);
592#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:41
Definition: dprintpreviewwidget.h:28
Definition: dprintpreviewwidget_p.h:33
Definition: dprintpreviewwidget_p.h:206
Definition: dprintpreviewwidget_p.h:100
const T & at(int i) const const
int count(const T &value) const const
T & first()
bool isEmpty() const const
int left() const const
int top() const const
void setX(qreal x)
void setY(qreal y)
qreal y() const const
QSize size() const const
QPoint topLeft() const const
qreal height() const const
QSizeF size() const const
QPointF topLeft() const const
qreal width() const const
void append(const T &value)
const T & at(int i) const const
Definition: dprintpreviewwidget_p.h:331