Line data Source code
1 : #include "ImageGrabber.h"
2 : #include "QBatchWebDownload.h"
3 :
4 : #include <QMimeDatabase>
5 : #include <QSvgRenderer>
6 : #include <QtConcurrent>
7 :
8 59 : ImageGrabber::ImageGrabber(QObject *parent, QNetworkAccessManager* networkManager) :
9 : QObject(parent),
10 59 : batchDownloader(new QBatchWebDownload(30000, 10, this, networkManager))
11 : {
12 59 : connect(batchDownloader, &QBatchWebDownload::finished,
13 59 : this, &ImageGrabber::onBatchFinished);
14 59 : connect(&processWatcher, &QFutureWatcher<void>::finished,
15 59 : this, &ImageGrabber::finished);
16 59 : }
17 :
18 19 : void ImageGrabber::fetchUrl(const QUrl &url)
19 : {
20 19 : QList<QUrl> urls;
21 19 : urls.append(url);
22 19 : fetchUrls(urls);
23 19 : }
24 :
25 35 : void ImageGrabber::fetchUrls(const QList<QUrl> &urls)
26 : {
27 35 : results.clear();
28 35 : batchDownloader->get(urls);
29 35 : }
30 :
31 35 : void ImageGrabber::onBatchFinished()
32 : {
33 : // Capture batch results on the main thread, then process on a background
34 : // thread to avoid blocking the UI during image decoding and MIME detection.
35 35 : QMap<QUrl, BatchWebDownloadResult> batchResults = batchDownloader->results();
36 :
37 : // Fast path: no images to process.
38 35 : if (batchResults.isEmpty()) {
39 1 : emit finished();
40 1 : return;
41 : }
42 :
43 68 : auto future = QtConcurrent::run([this, batchResults]() {
44 34 : QMimeDatabase mimeDb;
45 :
46 82 : for (auto it = batchResults.constBegin(); it != batchResults.constEnd(); ++it) {
47 48 : const QUrl& url = it.key();
48 48 : const BatchWebDownloadResult& batchResult = it.value();
49 :
50 48 : ImageData imageData;
51 :
52 48 : if (batchResult.success && !batchResult.data.isEmpty()) {
53 40 : QMimeType mimeType = mimeDb.mimeTypeForData(batchResult.data);
54 40 : imageData.mimeType = mimeType.name();
55 :
56 40 : if (mimeType.name() == "image/svg+xml") {
57 : // Use QSvgRenderer to get the SVG's logical dimensions.
58 : // QImage::fromData() rasterizes SVGs at an arbitrary size
59 : // that doesn't reflect their actual width/height.
60 3 : QSvgRenderer renderer(batchResult.data);
61 3 : if (renderer.isValid()) {
62 3 : QSize size = renderer.defaultSize();
63 3 : imageData.image = QImage(size, QImage::Format_ARGB32);
64 3 : imageData.rawData = batchResult.data;
65 : }
66 3 : } else {
67 37 : QImage image = QImage::fromData(batchResult.data);
68 37 : if (!image.isNull()) {
69 36 : imageData.image = image;
70 36 : imageData.rawData = batchResult.data;
71 : }
72 37 : }
73 40 : }
74 :
75 48 : results.insert(url, imageData);
76 48 : }
77 68 : });
78 34 : processWatcher.setFuture(future);
79 35 : }
|