Kstars

media.cpp
1/*
2 SPDX-FileCopyrightText: 2018 Jasem Mutlaq <mutlaqja@ikarustech.com>
3
4 Media Channel
5
6 SPDX-License-Identifier: GPL-2.0-or-later
7*/
8
9#include "media.h"
10#include "commands.h"
11#include "skymapcomposite.h"
12#include "fitsviewer/fitsview.h"
13#include "fitsviewer/fitsdata.h"
14#include "indi/indilistener.h"
15#include "hips/hipsfinder.h"
16#include "kstarsdata.h"
17#include "ekos/auxiliary/darklibrary.h"
18#include "ekos/guide/guide.h"
19#include "ekos/align/align.h"
20#include "ekos/capture/capture.h"
21#include "ekos/capture/cameraprocess.h"
22#include "kspaths.h"
23#include "Options.h"
24
25#include "ekos_debug.h"
26#include "kstars.h"
27#include "version.h"
28
29#include <QtConcurrent>
30#include <KFormat>
31
32namespace EkosLive
33{
34
35///////////////////////////////////////////////////////////////////////////////////////////
36///
37///////////////////////////////////////////////////////////////////////////////////////////
38Media::Media(Ekos::Manager * manager, QVector<QSharedPointer<NodeManager>> &nodeManagers):
39 m_Manager(manager), m_NodeManagers(nodeManagers)
40{
41 for (auto &nodeManager : m_NodeManagers)
42 {
43 connect(nodeManager->media(), &Node::connected, this, &Media::onConnected);
44 connect(nodeManager->media(), &Node::disconnected, this, &Media::onDisconnected);
45 connect(nodeManager->media(), &Node::onTextReceived, this, &Media::onTextReceived);
46 connect(nodeManager->media(), &Node::onBinaryReceived, this, &Media::onBinaryReceived);
47 }
48
49 connect(this, &Media::newMetadata, this, &Media::uploadMetadata);
50 connect(this, &Media::newImage, this, [this](const QByteArray & image)
51 {
52 uploadImage(image);
53 m_TemporaryView.clear();
54 });
55}
56
57///////////////////////////////////////////////////////////////////////////////////////////
58///
59///////////////////////////////////////////////////////////////////////////////////////////
60bool Media::isConnected() const
61{
62 return std::any_of(m_NodeManagers.begin(), m_NodeManagers.end(), [](auto & nodeManager)
63 {
64 return nodeManager->media()->isConnected();
65 });
66}
67
68///////////////////////////////////////////////////////////////////////////////////////////
69///
70///////////////////////////////////////////////////////////////////////////////////////////
71void Media::onConnected()
72{
73 auto node = qobject_cast<Node*>(sender());
74 if (!node)
75 return;
76
77 qCInfo(KSTARS_EKOS) << "Connected to Media Websocket server at" << node->url().toDisplayString();
78
79 emit connected();
80}
81
82///////////////////////////////////////////////////////////////////////////////////////////
83///
84///////////////////////////////////////////////////////////////////////////////////////////
85void Media::onDisconnected()
86{
87 auto node = qobject_cast<Node*>(sender());
88 if (!node)
89 return;
90
91 qCInfo(KSTARS_EKOS) << "Disconnected from Message Websocket server at" << node->url().toDisplayString();
92
93 if (isConnected() == false)
94 {
95 m_sendBlobs = true;
96
97 for (const QString &oneFile : temporaryFiles)
98 QFile::remove(oneFile);
99 temporaryFiles.clear();
100
101 emit disconnected();
102 }
103}
104
105///////////////////////////////////////////////////////////////////////////////////////////
106///
107///////////////////////////////////////////////////////////////////////////////////////////
108void Media::onTextReceived(const QString &message)
109{
110 qCInfo(KSTARS_EKOS) << "Media Text Websocket Message" << message;
112 auto serverMessage = QJsonDocument::fromJson(message.toLatin1(), &error);
113 if (error.error != QJsonParseError::NoError)
114 {
115 qCWarning(KSTARS_EKOS) << "Ekos Live Parsing Error" << error.errorString();
116 return;
117 }
118
119 const QJsonObject msgObj = serverMessage.object();
120 const QString command = msgObj["type"].toString();
121 const QJsonObject payload = msgObj["payload"].toObject();
122
123 if (command == commands[ALIGN_SET_FILE_EXTENSION])
124 extension = payload["ext"].toString();
125 else if (command == commands[SET_BLOBS])
126 m_sendBlobs = msgObj["payload"].toBool();
127 // Get a list of object based on criteria
128 else if (command == commands[ASTRO_GET_OBJECTS_IMAGE])
129 {
130 int level = payload["level"].toInt(5);
131 double zoom = payload["zoom"].toInt(20000);
132 bool exact = payload["exact"].toBool(false);
133
134 // Object Names
135 QVariantList objectNames = payload["names"].toArray().toVariantList();
136
137 for (auto &oneName : objectNames)
138 {
139 const QString name = oneName.toString();
140 SkyObject *oneObject = KStarsData::Instance()->skyComposite()->findByName(name, exact);
141 if (oneObject)
142 {
143 QImage centerImage(HIPS_TILE_WIDTH, HIPS_TILE_HEIGHT, QImage::Format_ARGB32_Premultiplied);
144 double fov_w = 0, fov_h = 0;
145
146 if (oneObject->type() == SkyObject::MOON || oneObject->type() == SkyObject::PLANET)
147 {
148 QProcess xplanetProcess;
149 const QString output = KSPaths::writableLocation(QStandardPaths::TempLocation) + QDir::separator() + "xplanet.jpg";
150 xplanetProcess.start(Options::xplanetPath(), QStringList()
151 << "--num_times" << "1"
152 << "--geometry" << QString("%1x%2").arg(HIPS_TILE_WIDTH).arg(HIPS_TILE_HEIGHT)
153 << "--body" << name.toLower()
154 << "--output" << output);
155 xplanetProcess.waitForFinished(5000);
156 centerImage.load(output);
157 }
158 else
159 HIPSFinder::Instance()->render(oneObject, level, zoom, &centerImage, fov_w, fov_h);
160
161 if (!centerImage.isNull())
162 {
163 // Use seed from name, level, and zoom so that it is unique
164 // even if regenerated again.
165 auto seed = QString("%1%2%3").arg(QString::number(level), QString::number(zoom), name);
166 QString uuid = "hips_" + QCryptographicHash::hash(seed.toLatin1(), QCryptographicHash::Md5).toHex();
167 // Send everything as strings
168 QJsonObject metadata =
169 {
170 {"uuid", uuid},
171 {"name", exact ? name : oneObject->name()},
172 {"zoom", zoom},
173 {"resolution", QString("%1x%2").arg(HIPS_TILE_WIDTH).arg(HIPS_TILE_HEIGHT)},
174 {"bin", "1x1"},
175 {"fov_w", QString::number(fov_w)},
176 {"fov_h", QString::number(fov_h)},
177 {"ext", "jpg"}
178 };
179
180 QByteArray jpegData;
181 QBuffer buffer(&jpegData);
182 buffer.open(QIODevice::WriteOnly);
183
184 // First METADATA_PACKET bytes of the binary data is always allocated
185 // to the metadata, the rest to the image data.
187 meta = meta.leftJustified(METADATA_PACKET, 0);
188 buffer.write(meta);
189 centerImage.save(&buffer, "jpg", 90);
190 buffer.close();
191
192 emit newImage(jpegData);
193 }
194 }
195 }
196 }
197 else if (command == commands[ASTRO_GET_SKYPOINT_IMAGE])
198 {
199 int level = payload["level"].toInt(5);
200 double zoom = payload["zoom"].toInt(20000);
201 double ra = payload["ra"].toDouble(0);
202 double de = payload["de"].toDouble(0);
203 double width = payload["width"].toDouble(512);
204 double height = payload["height"].toDouble(512);
205
206 QImage centerImage(width, height, QImage::Format_ARGB32_Premultiplied);
207 SkyPoint coords(ra, de);
208 SkyPoint J2000Coord(coords.ra(), coords.dec());
209 J2000Coord.catalogueCoord(KStars::Instance()->data()->ut().djd());
210 coords.setRA0(J2000Coord.ra());
211 coords.setDec0(J2000Coord.dec());
212 coords.EquatorialToHorizontal(KStarsData::Instance()->lst(), KStarsData::Instance()->geo()->lat());
213
214 volatile auto jnowRAString = coords.ra().toHMSString();
215 volatile auto jnowDEString = coords.dec().toDMSString();
216 volatile auto j2000RAString = coords.ra0().toHMSString();
217 volatile auto j2000DEString = coords.dec0().toDMSString();
218
219
220 double fov_w = 0, fov_h = 0;
221 HIPSFinder::Instance()->render(&coords, level, zoom, &centerImage, fov_w, fov_h);
222
223 if (!centerImage.isNull())
224 {
225 // Use seed from name, level, and zoom so that it is unique
226 // even if regenerated again.
227 // Send everything as strings
228 QJsonObject metadata =
229 {
230 {"uuid", "skypoint_hips"},
231 {"name", "skypoint_hips"},
232 {"zoom", zoom},
233 {"resolution", QString("%1x%2").arg(width).arg(height)},
234 {"bin", "1x1"},
235 {"fov_w", QString::number(fov_w)},
236 {"fov_h", QString::number(fov_h)},
237 {"ext", "jpg"}
238 };
239
240 QByteArray jpegData;
241 QBuffer buffer(&jpegData);
242 buffer.open(QIODevice::WriteOnly);
243
244 // First METADATA_PACKET bytes of the binary data is always allocated
245 // to the metadata, the rest to the image data.
247 meta = meta.leftJustified(METADATA_PACKET, 0);
248 buffer.write(meta);
249 centerImage.save(&buffer, "jpg", 95);
250 buffer.close();
251
252 emit newImage(jpegData);
253 }
254 }
255}
256
257///////////////////////////////////////////////////////////////////////////////////////////
258///
259///////////////////////////////////////////////////////////////////////////////////////////
260void Media::onBinaryReceived(const QByteArray &message)
261{
262 // Sometimes this is triggered even though it's a text message
263 Ekos::Align * align = m_Manager->alignModule();
264 if (align)
265 {
266 QString metadataString = message.left(METADATA_PACKET);
267 QJsonDocument metadataDocument = QJsonDocument::fromJson(metadataString.toLatin1());
268 QJsonObject metadataJSON = metadataDocument.object();
269 QString extension = metadataJSON.value("ext").toString();
270 align->loadAndSlew(message.mid(METADATA_PACKET), extension);
271 }
272}
273
274///////////////////////////////////////////////////////////////////////////////////////////
275///
276///////////////////////////////////////////////////////////////////////////////////////////
277void Media::sendDarkLibraryData(const QSharedPointer<FITSData> &data)
278{
279 sendData(data, "+D");
280};
281
282///////////////////////////////////////////////////////////////////////////////////////////
283///
284///////////////////////////////////////////////////////////////////////////////////////////
285void Media::sendData(const QSharedPointer<FITSData> &data, const QString &uuid)
286{
287 if (Options::ekosLiveImageTransfer() == false || m_sendBlobs == false)
288 return;
289
290 m_UUID = uuid;
291
292 m_TemporaryView.reset(new FITSView());
293 m_TemporaryView->loadData(data);
294 QtConcurrent::run(this, &Media::upload, m_TemporaryView);
295}
296
297///////////////////////////////////////////////////////////////////////////////////////////
298///
299///////////////////////////////////////////////////////////////////////////////////////////
300void Media::sendFile(const QString &filename, const QString &uuid)
301{
302 if (Options::ekosLiveImageTransfer() == false || m_sendBlobs == false)
303 return;
304
305 m_UUID = uuid;
306
307 QSharedPointer<FITSView> previewImage(new FITSView());
308 connect(previewImage.get(), &FITSView::loaded, this, [this, previewImage]()
309 {
310 QtConcurrent::run(this, &Media::upload, previewImage);
311 });
312 previewImage->loadFile(filename);
313}
314
315///////////////////////////////////////////////////////////////////////////////////////////
316///
317///////////////////////////////////////////////////////////////////////////////////////////
318void Media::sendView(const QSharedPointer<FITSView> &view, const QString &uuid)
319{
320 if (Options::ekosLiveImageTransfer() == false || m_sendBlobs == false)
321 return;
322
323 m_UUID = uuid;
324
325 upload(view);
326}
327
328///////////////////////////////////////////////////////////////////////////////////////////
329///
330///////////////////////////////////////////////////////////////////////////////////////////
331void Media::upload(const QSharedPointer<FITSView> &view)
332{
333 const QString ext = "jpg";
334 QByteArray jpegData;
335 QBuffer buffer(&jpegData);
336 buffer.open(QIODevice::WriteOnly);
337
338 const QSharedPointer<FITSData> imageData = view->imageData();
339 QString resolution = QString("%1x%2").arg(imageData->width()).arg(imageData->height());
340 QString sizeBytes = KFormat().formatByteSize(imageData->size());
341 QVariant xbin(1), ybin(1), exposure(0), focal_length(0), gain(0), pixel_size(0), aperture(0);
342 imageData->getRecordValue("XBINNING", xbin);
343 imageData->getRecordValue("YBINNING", ybin);
344 imageData->getRecordValue("EXPTIME", exposure);
345 imageData->getRecordValue("GAIN", gain);
346 imageData->getRecordValue("PIXSIZE1", pixel_size);
347 imageData->getRecordValue("FOCALLEN", focal_length);
348 imageData->getRecordValue("APTDIA", aperture);
349
350 auto stretchParameters = view->getStretchParams();
351
352 // Account for binning
353 const double binned_pixel = pixel_size.toDouble() * xbin.toInt();
354 // Send everything as strings
355 QJsonObject metadata =
356 {
357 {"resolution", resolution},
358 {"size", sizeBytes},
359 {"channels", imageData->channels()},
360 {"mean", imageData->getAverageMean()},
361 {"median", imageData->getAverageMedian()},
362 {"stddev", imageData->getAverageStdDev()},
363 {"min", imageData->getMin()},
364 {"max", imageData->getMax()},
365 {"bin", QString("%1x%2").arg(xbin.toString(), ybin.toString())},
366 {"bpp", QString::number(imageData->bpp())},
367 {"uuid", m_UUID},
368 {"exposure", exposure.toString()},
369 {"focal_length", focal_length.toString()},
370 {"aperture", aperture.toString()},
371 {"gain", gain.toString()},
372 {"pixel_size", QString::number(binned_pixel, 'f', 4)},
373 {"shadows", stretchParameters.grey_red.shadows},
374 {"midtones", stretchParameters.grey_red.midtones},
375 {"highlights", stretchParameters.grey_red.highlights},
376 {"hasWCS", imageData->hasWCS()},
377 {"hfr", imageData->getHFR()},
378 {"view", view->objectName()},
379 {"ext", ext}
380 };
381
382 // First METADATA_PACKET bytes of the binary data is always allocated
383 // to the metadata
384 // the rest to the image data.
386 meta = meta.leftJustified(METADATA_PACKET, 0);
387 buffer.write(meta);
388
389 auto fastImage = (!Options::ekosLiveHighBandwidth() || m_UUID[0] == "+");
390 auto scaleWidth = fastImage ? HB_IMAGE_WIDTH / 2 : HB_IMAGE_WIDTH;
391
392 // For low bandwidth images
393 // Except for dark frames +D
394 QPixmap scaledImage = view->getDisplayPixmap().width() > scaleWidth ?
395 view->getDisplayPixmap().scaledToWidth(scaleWidth, fastImage ? Qt::FastTransformation : Qt::SmoothTransformation) :
396 view->getDisplayPixmap();
397 scaledImage.save(&buffer, ext.toLatin1().constData(), HB_IMAGE_QUALITY);
398
399 buffer.close();
400
401 emit newImage(jpegData);
402}
403
404///////////////////////////////////////////////////////////////////////////////////////////
405///
406///////////////////////////////////////////////////////////////////////////////////////////
407void Media::sendUpdatedFrame(const QSharedPointer<FITSView> &view)
408{
409 QString ext = "jpg";
410 QByteArray jpegData;
411 QBuffer buffer(&jpegData);
412 buffer.open(QIODevice::WriteOnly);
413
414 const QSharedPointer<FITSData> imageData = view->imageData();
415
416 if (!imageData)
417 return;
418
419 const int32_t width = imageData->width();
420 const int32_t height = imageData->height();
421 QString resolution = QString("%1x%2").arg(width).arg(height);
422 QString sizeBytes = KFormat().formatByteSize(imageData->size());
423 QVariant xbin(1), ybin(1), exposure(0), focal_length(0), gain(0), pixel_size(0), aperture(0);
424 imageData->getRecordValue("XBINNING", xbin);
425 imageData->getRecordValue("YBINNING", ybin);
426 imageData->getRecordValue("EXPTIME", exposure);
427 imageData->getRecordValue("GAIN", gain);
428 imageData->getRecordValue("PIXSIZE1", pixel_size);
429 imageData->getRecordValue("FOCALLEN", focal_length);
430 imageData->getRecordValue("APTDIA", aperture);
431
432 // Account for binning
433 const double binned_pixel = pixel_size.toDouble() * xbin.toInt();
434 // Send everything as strings
435 QJsonObject metadata =
436 {
437 {"resolution", resolution},
438 {"size", sizeBytes},
439 {"channels", imageData->channels()},
440 {"mean", imageData->getAverageMean()},
441 {"median", imageData->getAverageMedian()},
442 {"stddev", imageData->getAverageStdDev()},
443 {"bin", QString("%1x%2").arg(xbin.toString()).arg(ybin.toString())},
444 {"bpp", QString::number(imageData->bpp())},
445 {"uuid", "+A"},
446 {"exposure", exposure.toString()},
447 {"focal_length", focal_length.toString()},
448 {"aperture", aperture.toString()},
449 {"gain", gain.toString()},
450 {"pixel_size", QString::number(binned_pixel, 'f', 4)},
451 {"ext", ext}
452 };
453
454 // First METADATA_PACKET bytes of the binary data is always allocated
455 // to the metadata
456 // the rest to the image data.
458 meta = meta.leftJustified(METADATA_PACKET, 0);
459 buffer.write(meta);
460
461 // For low bandwidth images
462 QPixmap scaledImage;
463 // Align images
464 if (correctionVector.isNull() == false)
465 {
466 scaledImage = view->getDisplayPixmap();
467 const double currentZoom = view->getCurrentZoom();
468 const double normalizedZoom = currentZoom / 100;
469 // If zoom level is not 100%, then scale.
470 if (fabs(normalizedZoom - 1) > 0.001)
471 scaledImage = view->getDisplayPixmap().scaledToWidth(view->zoomedWidth());
472 else
473 scaledImage = view->getDisplayPixmap();
474 // as we factor in the zoom level, we adjust center and length accordingly
475 QPointF center = 0.5 * correctionVector.p1() * normalizedZoom + 0.5 * correctionVector.p2() * normalizedZoom;
476 uint32_t length = qMax(correctionVector.length() / normalizedZoom, 100 / normalizedZoom);
477
478 QRect boundingRectable;
479 boundingRectable.setSize(QSize(length * 2, length * 2));
480 QPoint topLeft = (center - QPointF(length, length)).toPoint();
481 boundingRectable.moveTo(topLeft);
482 boundingRectable = boundingRectable.intersected(scaledImage.rect());
483
484 emit newBoundingRect(boundingRectable, scaledImage.size(), currentZoom);
485
486 scaledImage = scaledImage.copy(boundingRectable);
487 }
488 else
489 {
490 scaledImage = view->getDisplayPixmap().width() > HB_IMAGE_WIDTH / 2 ?
491 view->getDisplayPixmap().scaledToWidth(HB_IMAGE_WIDTH / 2, Qt::FastTransformation) :
492 view->getDisplayPixmap();
493 emit newBoundingRect(QRect(), QSize(), 100);
494 }
495
496 scaledImage.save(&buffer, ext.toLatin1().constData(), HB_IMAGE_QUALITY);
497 buffer.close();
498 emit newImage(jpegData);
499}
500
501///////////////////////////////////////////////////////////////////////////////////////////
502///
503///////////////////////////////////////////////////////////////////////////////////////////
504void Media::sendVideoFrame(const QSharedPointer<QImage> &frame)
505{
506 if (Options::ekosLiveImageTransfer() == false || m_sendBlobs == false || !frame)
507 return;
508
509 int32_t width = Options::ekosLiveHighBandwidth() ? HB_VIDEO_WIDTH : HB_VIDEO_WIDTH / 2;
510 QByteArray image;
511 QBuffer buffer(&image);
512 buffer.open(QIODevice::WriteOnly);
513
514 QImage videoImage = (frame->width() > width) ? frame->scaledToWidth(width) : *frame;
515
516 QString resolution = QString("%1x%2").arg(videoImage.width()).arg(videoImage.height());
517
518 // First METADATA_PACKET bytes of the binary data is always allocated
519 // to the metadata
520 // the rest to the image data.
521 QJsonObject metadata =
522 {
523 {"resolution", resolution},
524 {"ext", "jpg"}
525 };
527 meta = meta.leftJustified(METADATA_PACKET, 0);
528 buffer.write(meta);
529
530 QImageWriter writer;
531 writer.setDevice(&buffer);
532 writer.setFormat("JPG");
533 writer.setCompression(6);
534 writer.write(videoImage);
535 buffer.close();
536
537 for (auto &nodeManager : m_NodeManagers)
538 {
539 nodeManager->media()->sendBinaryMessage(image);
540 }
541}
542
543///////////////////////////////////////////////////////////////////////////////////////////
544///
545///////////////////////////////////////////////////////////////////////////////////////////
546void Media::registerCameras()
547{
548 static const QRegularExpression re("[-{}]");
549 for(auto &oneDevice : INDIListener::devices())
550 {
551 auto camera = oneDevice->getCamera();
552 if (camera)
553 {
554 camera->disconnect(this);
555 connect(camera, &ISD::Camera::newVideoFrame, this, &Media::sendVideoFrame);
556 }
557 }
558
559 auto captureModule = m_Manager->captureModule();
560 if (!captureModule)
561 return;
562
563 auto process = captureModule->process().get();
564 process->disconnect(this);
565 connect(process, &Ekos::CameraProcess::newView, this, [this](const QSharedPointer<FITSView> &view)
566 {
567 // Set UUID for each view
569 uuid = uuid.remove(re);
570 sendView(view, uuid);
571 });
572}
573
574void Media::resetPolarView()
575{
576 this->correctionVector = QLineF();
577 m_Manager->alignModule()->zoomAlignView();
578}
579
580void Media::uploadMetadata(const QByteArray &metadata)
581{
582 for (auto &nodeManager : m_NodeManagers)
583 {
584 nodeManager->media()->sendTextMessage(metadata);
585 }
586}
587
588void Media::uploadImage(const QByteArray &image)
589{
590 for (auto &nodeManager : m_NodeManagers)
591 {
592 nodeManager->media()->sendBinaryMessage(image);
593 }
594}
595
596void Media::processNewBLOB(IBLOB * bp)
597{
598 Q_UNUSED(bp)
599}
600
601void Media::sendModuleFrame(const QSharedPointer<FITSView> &view)
602{
603 if (Options::ekosLiveImageTransfer() == false || m_sendBlobs == false)
604 return;
605
606 if (qobject_cast<Ekos::Align*>(sender()) == m_Manager->alignModule())
607 sendView(view, "+A");
608 else if (qobject_cast<Ekos::Focus*>(sender()) == m_Manager->focusModule())
609 sendView(view, "+F");
610 else if (qobject_cast<Ekos::Guide*>(sender()) == m_Manager->guideModule())
611 sendView(view, "+G");
612 else if (qobject_cast<Ekos::DarkLibrary*>(sender()) == Ekos::DarkLibrary::Instance())
613 sendView(view, "+D");
614}
615}
Align class handles plate-solving and polar alignment measurement and correction using astrometry....
Definition align.h:75
bool loadAndSlew(const QByteArray &image, const QString &extension)
DBUS interface function.
Definition align.cpp:3072
INDIListener is responsible for creating ISD::GDInterface generic devices as new devices arrive from ...
QString formatByteSize(double size, int precision=1, KFormat::BinaryUnitDialect dialect=KFormat::DefaultBinaryDialect, KFormat::BinarySizeUnits units=KFormat::DefaultBinaryUnits) const
SkyMapComposite * skyComposite()
Definition kstarsdata.h:166
static KStars * Instance()
Definition kstars.h:123
SkyObject * findByName(const QString &name, bool exact=true) override
Search the children of this SkyMapComposite for a SkyObject whose name matches the argument.
Provides all necessary information about an object in the sky: its coordinates, name(s),...
Definition skyobject.h:42
virtual QString name(void) const
Definition skyobject.h:145
int type(void) const
Definition skyobject.h:188
The sky coordinates of a point in the sky.
Definition skypoint.h:45
Generic record interfaces and implementations.
Definition cloud.cpp:23
QString name(GameStandardAction id)
GeoCoordinates geo(const QVariant &location)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
QStringView level(QStringView ifopt)
QAction * zoom(const QObject *recvr, const char *slot, QObject *parent)
KGuiItem remove()
const char * constData() const const
QByteArray left(qsizetype len) const const
QByteArray leftJustified(qsizetype width, char fill, bool truncate) const const
QByteArray mid(qsizetype pos, qsizetype len) const const
QByteArray toHex(char separator) const const
QByteArray hash(QByteArrayView data, Algorithm method)
QChar separator()
Format_ARGB32_Premultiplied
int height() const const
int width() const const
void setCompression(int compression)
void setDevice(QIODevice *device)
void setFormat(const QByteArray &format)
bool write(const QImage &image)
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
QJsonObject object() const const
QByteArray toJson(JsonFormat format) const const
QJsonValue value(QLatin1StringView key) const const
QString toString() const const
QPixmap copy(const QRect &rectangle) const const
QRect rect() const const
bool save(QIODevice *device, const char *format, int quality) const const
QSize size() const const
void start(OpenMode mode)
bool waitForFinished(int msecs)
QRect intersected(const QRect &rectangle) const const
void moveTo(const QPoint &position)
void setSize(const QSize &size)
QString arg(Args &&... args) const const
QString number(double n, char format, int precision)
QString & remove(QChar ch, Qt::CaseSensitivity cs)
QByteArray toLatin1() const const
QString toLower() const const
FastTransformation
QTextStream & center(QTextStream &stream)
QFuture< T > run(Function function,...)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QUuid createUuid()
QString toString(StringFormat mode) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jul 26 2024 11:59:51 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.