5#include <private/qtquickglobal_p.h>
11#if QT_CONFIG(quick_shadereffect)
12#include "qquickshadereffectsource_p.h"
15#include <QtQml/QQmlEngine>
16#include <QtQml/QQmlInfo>
18#include <private/qquickpixmap_p.h>
19#include <private/qquickitem_p.h>
20#include <private/qsgcontext_p.h>
21#include <private/qsgadaptationlayer_p.h>
23#include <QtCore/qmutex.h>
24#include <QtCore/qpointer.h>
47 qmlEngine->handle()->memoryManager->changeUnmanagedHeapSizeUsage(-image.sizeInBytes());
52 bool hasCallback()
const {
return qmlEngine && callback.isCallable(); }
56 if (url.isEmpty() && !image.isNull()) {
57 url.setScheme(QQuickPixmap::itemGrabberScheme);
58 url.setPath(QVariant::fromValue(item.data()).toString());
59 static uint counter = 0;
60 url.setFragment(QString::number(++counter));
61 cacheEntry =
new QQuickPixmap(url, image);
65 static QQuickItemGrabResult *
create(QQuickItem *item,
const QSize &size);
89
90
91
92
93
94
95
96
97
98
99
100
103
104
105
106
107
108
109
110
111
112
115
116
117
118
119
122
123
124
125
126
127
128
131
132
133
134
135
136
139
140
141
142
145
146
147
148
149
150
151
152
153
154
155
156
158QQuickItemGrabResult::QQuickItemGrabResult(QObject *parent)
159 : QObject(*
new QQuickItemGrabResultPrivate, parent)
164
165
166
167
168
172
173
174
175
176
177bool QQuickItemGrabResult::saveToFile(
const QString &fileName)
const
179 Q_D(
const QQuickItemGrabResult);
180 if (fileName.startsWith(QLatin1String(
"file:/")))
181 return saveToFile(QUrl(fileName));
182 QMutexLocker locker(&d->mutex);
183 return d->image.save(fileName);
187
188
189
190
191
192
193bool QQuickItemGrabResult::saveToFile(
const QUrl &filePath)
const
195 Q_D(
const QQuickItemGrabResult);
196 if (!filePath.isLocalFile()) {
197 qWarning() <<
"saveToFile can only save to a file on the local filesystem";
200 QMutexLocker locker(&d->mutex);
201 return d->image.save(filePath.toLocalFile());
204#if QT_VERSION < QT_VERSION_CHECK(6
, 0
, 0
)
205#if QT_DEPRECATED_SINCE(5
, 15
)
207
208
209
210bool QQuickItemGrabResult::saveToFile(
const QString &fileName)
212 return std::as_const(*
this).saveToFile(fileName);
217QUrl QQuickItemGrabResult::url()
const
219 Q_D(
const QQuickItemGrabResult);
220 QMutexLocker locker(&d->mutex);
221 d->ensureImageInCache();
225QImage QQuickItemGrabResult::image()
const
227 Q_D(
const QQuickItemGrabResult);
228 QMutexLocker locker(&d->mutex);
233
234
235bool QQuickItemGrabResult::event(QEvent *e)
237 Q_D(QQuickItemGrabResult);
238 if (e->type() == Event_Grab_Completed) {
242 QQmlEngine *engine =
nullptr;
243 if (QMutexLocker locker(&d->mutex); d->hasCallback()) {
244 callback = d->callback;
245 engine = d->qmlEngine;
251 QQmlEngine::setObjectOwnership(
this, QQmlEngine::JavaScriptOwnership);
253 callback.call(QJSValueList() << engine->newQObject(
this));
259 return QObject::event(e);
263
264
265
266void QQuickItemGrabResult::setup()
268 Q_D(QQuickItemGrabResult);
269 QMutexLocker locker(&d->mutex);
271 disconnect(d->setupConnection);
272 disconnect(d->renderConnection);
273 QCoreApplication::postEvent(
this,
new QEvent(Event_Grab_Completed));
277 QSGRenderContext *rc = QQuickWindowPrivate::get(d->window.data())->context;
278 d->devicePixelRatio = d->window->effectiveDevicePixelRatio();
279 d->texture = rc->sceneGraphContext()->createLayer(rc);
280 d->texture->setDevicePixelRatio(d->devicePixelRatio);
281 d->texture->setItem(QQuickItemPrivate::get(d->item)->itemNode());
282 d->itemSize = QSizeF(d->item->width(), d->item->height());
286
287
288
289void QQuickItemGrabResult::render()
291 Q_D(QQuickItemGrabResult);
292 QMutexLocker locker(&d->mutex);
296 d->texture->setRect(QRectF(0, d->itemSize.height(), d->itemSize.width(), -d->itemSize.height()));
297 const QSize minSize = QQuickWindowPrivate::get(d->window.data())->context->sceneGraphContext()->minimumFBOSize();
298 const QSize effectiveTextureSize = d->textureSize * d->devicePixelRatio;
299 d->texture->setSize(QSize(qMax(minSize.width(), effectiveTextureSize.width()),
300 qMax(minSize.height(), effectiveTextureSize.height())));
301 d->texture->scheduleUpdate();
302 d->texture->updateTexture();
304 const qsizetype oldImageSize = d->image.sizeInBytes();
305 d->image = d->texture->toImage();
306 d->image.setDevicePixelRatio(d->devicePixelRatio);
307 const qsizetype newImageSize = d->image.sizeInBytes();
308 if (d->hasCallback()) {
316 d->qmlEngine->handle()->memoryManager->changeUnmanagedHeapSizeUsage(
317 newImageSize - oldImageSize);
321 d->texture =
nullptr;
323 disconnect(d->setupConnection);
324 disconnect(d->renderConnection);
325 QCoreApplication::postEvent(
this,
new QEvent(Event_Grab_Completed));
330 QSize size = targetSize;
332 size = QSize(item->width(), item->height());
334 if (size.width() < 1 || size.height() < 1) {
335 qmlWarning(item) <<
"grabToImage: item has invalid dimensions";
339 if (!item->window()) {
340 qmlWarning(item) <<
"grabToImage: item is not attached to a window";
344 QWindow *effectiveWindow = item->window();
345 if (QWindow *renderWindow = QQuickRenderControl::renderWindowFor(item->window()))
346 effectiveWindow = renderWindow;
348 if (!effectiveWindow->isVisible()) {
349 qmlWarning(item) <<
"grabToImage: item's window is not visible";
355 QQuickItemGrabResult *result =
new QQuickItemGrabResult(item);
360 d->window = item->window();
361 d->textureSize = size;
363 QQuickItemPrivate::get(item)->refFromEffectItem(
false);
366 item->window()->update();
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389QSharedPointer<QQuickItemGrabResult> QQuickItem::grabToImage(
const QSize &targetSize)
391 QQuickItemGrabResult *result = QQuickItemGrabResultPrivate::create(
this, targetSize);
393 return QSharedPointer<QQuickItemGrabResult>();
395 QQuickItemGrabResultPrivate *d = result->d_func();
396 auto sharedResult = QSharedPointer<QQuickItemGrabResult>(result);
397 result->setParent(
nullptr);
399 auto weakResult = QWeakPointer(sharedResult);
400 QMutexLocker locker(&d->mutex);
401 d->setupConnection = connect(window(), &QQuickWindow::beforeSynchronizing,
402 result, [weakResult] {
403 if (
auto strong = weakResult.toStrongRef(); strong)
405 }, Qt::DirectConnection);
406 d->renderConnection = connect(window(), &QQuickWindow::afterRendering,
407 result, [weakResult] {
408 if (
auto strong = weakResult.toStrongRef(); strong)
410 }, Qt::DirectConnection);
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
446
447
448
449bool QQuickItem::grabToImage(
const QJSValue &callback,
const QSize &targetSize)
451 QQmlEngine *engine = qmlEngine(
this);
453 qmlWarning(
this) <<
"grabToImage: item has no QML engine";
457 if (!callback.isCallable()) {
458 qmlWarning(
this) <<
"grabToImage: 'callback' is not a function";
462 QSize size = targetSize;
464 size = QSize(width(), height());
466 if (size.width() < 1 || size.height() < 1) {
467 qmlWarning(
this) <<
"grabToImage: item has invalid dimensions";
472 qmlWarning(
this) <<
"grabToImage: item is not attached to a window";
476 QQuickItemGrabResult *result = QQuickItemGrabResultPrivate::create(
this, size);
482 QQuickItemGrabResultPrivate *d = result->d_func();
484 QMutexLocker locker(&d->mutex);
485 d->qmlEngine = engine;
486 d->callback = callback;
488 d->setupConnection = connect(window(), &QQuickWindow::beforeSynchronizing,
489 result, &QQuickItemGrabResult::setup, Qt::DirectConnection);
490 d->renderConnection = connect(window(), &QQuickWindow::afterRendering,
491 result, &QQuickItemGrabResult::render, Qt::DirectConnection);
498#include "moc_qquickitemgrabresult.cpp"
QQuickItemGrabResultPrivate()
~QQuickItemGrabResultPrivate()
void ensureImageInCache() const
QMetaObject::Connection setupConnection
QPointer< QQuickWindow > window
QQuickPixmap * cacheEntry
static QQuickItemGrabResult * create(QQuickItem *item, const QSize &size)
QMetaObject::Connection renderConnection
QPointer< QQuickItem > item
Combined button and popup list for selecting options.
QT_BEGIN_NAMESPACE const QEvent::Type Event_Grab_Completed