File indexing completed on 2024-04-21 04:33:48
0001 /******************************************************************************* 0002 * Copyright (C) 2020 by Steve Allewell * 0003 * steve.allewell@gmail.com * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 ******************************************************************************/ 0010 0011 0012 #include "ViewerTab.h" 0013 0014 #include <QImage> 0015 #include <QListWidget> 0016 #include <QPainter> 0017 #include <QPointer> 0018 #include <QPrinter> 0019 #include <QPrintDialog> 0020 #include <QProgressDialog> 0021 #include <QResizeEvent> 0022 #include <QScrollBar> 0023 #include <QShowEvent> 0024 #include <QUrl> 0025 0026 #include <KLocalizedString> 0027 #include <KMessageBox> 0028 0029 #include "Thumbnail.h" 0030 0031 0032 QByteArray readData(QDataStream &stream, int size) 0033 { 0034 std::unique_ptr<char[]> buffer(new char[size]); 0035 stream.readRawData(buffer.get(), size); 0036 return QByteArray(buffer.get(), size); 0037 } 0038 0039 0040 QByteArray readData(QDataStream &stream) 0041 { 0042 int size; 0043 stream >> size; 0044 return readData(stream, size); 0045 } 0046 0047 0048 QString readString(QDataStream &stream) 0049 { 0050 quint16 size; 0051 stream >> size; 0052 return QString(readData(stream, size)); 0053 } 0054 0055 0056 ViewerTab::ViewerTab(QWidget *parent) 0057 : QWidget(parent), 0058 m_document(nullptr) 0059 { 0060 ui.setupUi(this); 0061 0062 QScrollBar *scrollbar = ui.PagesList->verticalScrollBar(); 0063 0064 connect(ui.splitter, SIGNAL(splitterMoved(int,int)), this, SLOT(splitterMoved(int,int))); 0065 connect(scrollbar, SIGNAL(valueChanged(int)), this, SLOT(valueChanged(int))); 0066 connect(&m_timer, SIGNAL(timeout()), this, SLOT(renderPages())); 0067 } 0068 0069 0070 void ViewerTab::valueChanged(int value) 0071 { 0072 Q_UNUSED(value); 0073 0074 if (isVisible()) m_timer.start(100); 0075 } 0076 0077 0078 ViewerTab::~ViewerTab() 0079 { 0080 delete m_document; 0081 } 0082 0083 0084 int ViewerTab::load(const QUrl &url) 0085 { 0086 QFile src(url.toLocalFile()); 0087 0088 if (!src.open(QIODevice::ReadOnly)) 0089 { 0090 KMessageBox::error(nullptr, i18n("Failed to open source file.")); 0091 return -1; 0092 } 0093 0094 QDataStream stream(&src); 0095 stream.setByteOrder(QDataStream::LittleEndian); 0096 0097 if (!readData(stream, 24).contains("Pattern Viewer Data File")) { 0098 KMessageBox::error(nullptr, i18n("Not a PC Stitch Pattern Viewer file.")); 0099 return -1; 0100 } 0101 0102 stream.skipRawData(12); // some random data here, TODO determine contents 0103 // possibly a file format version 0104 0105 ui.LicenceLabel->setText(QString(readData(stream, 30))); 0106 0107 stream.skipRawData(23); // some random data here, TODO determine contents 0108 0109 ui.DesignerLabel->setText(readString(stream)); 0110 0111 QString copyright(readString(stream)); 0112 if (copyright.at(0).unicode() == 65533) 0113 copyright.replace(0, 1, QChar(0x00A9)); 0114 ui.CopyrightLabel->setText(copyright); 0115 0116 0117 m_tabTitle = readString(stream); 0118 0119 readString(stream); // there is another length encoded string here 0120 // but no content in any of the files checked 0121 0122 m_website = readString(stream); 0123 0124 m_pixmap.loadFromData(readData(stream)); 0125 0126 m_pdfData = readData(stream); 0127 0128 m_document = Poppler::Document::loadFromData(m_pdfData); 0129 0130 if (!m_document || m_document->isLocked()) { 0131 KMessageBox::error(nullptr, i18n("Failed to create PDF from data.")); 0132 delete m_document; 0133 m_document = nullptr; 0134 return -1; 0135 } 0136 0137 m_document->setRenderHint(Poppler::Document::RenderHint::Antialiasing, true); 0138 m_document->setRenderHint(Poppler::Document::RenderHint::TextAntialiasing, true); 0139 m_document->setRenderHint(Poppler::Document::RenderHint::TextHinting, true); 0140 m_document->setRenderHint(Poppler::Document::RenderHint::TextSlightHinting, true); 0141 m_document->setRenderHint(Poppler::Document::RenderHint::ThinLineSolid, true); 0142 0143 int pages = m_document->numPages(); 0144 0145 for (int page = 0 ; page < pages ; ++page) { 0146 new Thumbnail(m_document->page(page), ui.PagesList); 0147 } 0148 0149 return 0; 0150 } 0151 0152 0153 void ViewerTab::showEvent(QShowEvent *event) 0154 { 0155 QWidget::showEvent(event); 0156 0157 quickScale(); 0158 } 0159 0160 0161 QString ViewerTab::title() const 0162 { 0163 return m_tabTitle; 0164 } 0165 0166 0167 QByteArray ViewerTab::pdfData() 0168 { 0169 return m_pdfData; 0170 } 0171 0172 0173 void ViewerTab::resizeEvent(QResizeEvent *event) 0174 { 0175 QWidget::resizeEvent(event); 0176 0177 if (isVisible()) quickScale(); 0178 } 0179 0180 0181 void ViewerTab::splitterMoved(int pos, int index) 0182 { 0183 Q_UNUSED(pos); 0184 Q_UNUSED(index); 0185 0186 quickScale(); 0187 } 0188 0189 0190 void ViewerTab::quickScale() 0191 { 0192 int newIconWidth = ui.PagesList->viewport()->width() - (2 * ui.PagesList->spacing()) - ui.PagesList->contentsMargins().left() - ui.PagesList->contentsMargins().right(); 0193 0194 ui.PatternPreview->setPixmap(m_pixmap.scaled(ui.PatternPreview->width()-20, ui.PatternPreview->height()-20, Qt::KeepAspectRatio)); 0195 0196 ui.PagesList->setIconSize(QSize(newIconWidth, static_cast<Thumbnail *>(ui.PagesList->item(0))->heightForWidth(newIconWidth))); 0197 0198 for (int page = 0, pages = m_document->numPages() ; page < pages ; ++page) { 0199 Thumbnail *thumbnail = static_cast<Thumbnail *>(ui.PagesList->item(page)); 0200 QImage image = thumbnail->image(); 0201 0202 if (image.isNull()) { 0203 image = QImage(ui.PagesList->iconSize(), QImage::Format_ARGB32_Premultiplied); 0204 image.fill(Qt::white); 0205 thumbnail->setImage(image); 0206 } else { 0207 thumbnail->setImage(image.scaledToWidth(newIconWidth, Qt::FastTransformation)); 0208 } 0209 } 0210 0211 m_timer.start(100); 0212 } 0213 0214 0215 void ViewerTab::renderPages() 0216 { 0217 m_timer.stop(); 0218 0219 QScrollBar *scrollBar = ui.PagesList->verticalScrollBar(); 0220 0221 int numPages = m_document->numPages(); 0222 int pageStep = scrollBar->pageStep(); 0223 int pageLength = (scrollBar->maximum() + pageStep) / numPages; 0224 int value = scrollBar->value(); 0225 int firstPage = value / pageLength; 0226 int lastPage = std::min(((value + pageStep) / pageLength), numPages - 1); 0227 0228 for (int page = firstPage ; page <= lastPage ; ++page) { 0229 Thumbnail *thumbnail = static_cast<Thumbnail *>(ui.PagesList->item(page)); 0230 thumbnail->renderPage(); 0231 } 0232 } 0233 0234 0235 void ViewerTab::print() 0236 { 0237 QPrinter printer; 0238 0239 QList<Poppler::Page *> pages; 0240 0241 int pageCount = m_document->numPages(); 0242 0243 for (int page = 0 ; page < pageCount ; ++page) { 0244 pages.append(m_document->page(page)); 0245 } 0246 0247 printer.setFullPage(true); 0248 printer.setPrintRange(QPrinter::AllPages); 0249 printer.setFromTo(1, pageCount); 0250 0251 QPointer<QPrintDialog> printDialog = new QPrintDialog(&printer, this); 0252 0253 if (printDialog->exec() == QDialog::Accepted) { 0254 int fromPage = 1; 0255 int toPage = pageCount; 0256 0257 if (printer.printRange() == QPrinter::PageRange) { 0258 fromPage = printer.fromPage(); 0259 toPage = printer.toPage(); 0260 } 0261 0262 while (toPage < pages.count()) pages.removeLast(); 0263 while (--fromPage) pages.removeFirst(); 0264 0265 int pageCount = pages.count(); 0266 0267 QProgressDialog progress(this); 0268 progress.setWindowModality(Qt::WindowModal); 0269 progress.setRange(0, pageCount); 0270 0271 QPainter painter; 0272 painter.begin(&printer); 0273 0274 for (int page = 0 ; page < pageCount ; ++page) { 0275 if (progress.wasCanceled()) { 0276 printer.abort(); 0277 return; 0278 } 0279 0280 if (page > 0) { 0281 printer.newPage(); 0282 } 0283 0284 progress.setValue(page); 0285 progress.setLabelText(i18n("Printing page %1", page+1)); 0286 0287 Poppler::Page *pdfPage = (printer.pageOrder() == QPrinter::FirstPageFirst)?pages.takeFirst():pages.takeLast(); 0288 0289 if (pdfPage) { 0290 QSizeF pageSize = pdfPage->pageSizeF(); // size in points 1/72 inch 0291 QRect paintRect = painter.window(); 0292 0293 double scale = printer.paperRect(QPrinter::DevicePixel).width() / printer.paperRect(QPrinter::Point).width(); 0294 0295 double hScale = paintRect.width() / pageSize.width(); 0296 double vScale = paintRect.height() / pageSize.height(); 0297 0298 scale = std::min(hScale, vScale); 0299 0300 QImage image = pdfPage->renderToImage(300, 300); 0301 0302 painter.drawImage(QRectF(QPointF(0, 0), scale * pdfPage->pageSizeF()), image); 0303 } 0304 } 0305 0306 painter.end(); 0307 0308 progress.setValue(pageCount); 0309 } 0310 0311 delete printDialog; 0312 } 0313 0314 #include "moc_ViewerTab.cpp"