Kstars

videowg.cpp
1/*
2 SPDX-FileCopyrightText: 2017 Jasem Mutlaq <mutlaqja@ikarustech.com>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "videowg.h"
8#include "collimationoverlaytypes.h"
9
10#include "kstars_debug.h"
11#include "kstarsdata.h"
12#include "kstars.h"
13
14#include <QImageReader>
15#include <QMouseEvent>
16#include <QResizeEvent>
17#include <QRubberBand>
18#include <QSqlTableModel>
19#include <QSqlRecord>
20#include <QtMath>
21
22VideoWG::VideoWG(QWidget *parent) : QLabel(parent)
23{
24 streamImage.reset(new QImage());
25
26 grayTable.resize(256);
27
28 for (int i = 0; i < 256; i++)
29 grayTable[i] = qRgb(i, i, i);
30}
31
32bool VideoWG::newBayerFrame(IBLOB *bp, const BayerParams &params)
33{
34 return debayer(bp, params);
35}
36
37bool VideoWG::newFrame(IBLOB *bp)
38{
39 if (bp->size <= 0)
40 return false;
41
42 bool rc = false;
43 QString format(bp->format);
44 if (m_RawFormat != format)
45 {
46 format.remove('.');
47 format.remove("stream_");
48 m_RawFormatSupported = QImageReader::supportedImageFormats().contains(format.toLatin1());
49 m_RawFormat = format;
50 }
51
52 if (m_RawFormatSupported)
53 rc = streamImage->loadFromData(static_cast<uchar *>(bp->blob), bp->size);
54 else if (static_cast<uint32_t>(bp->size) == totalBaseCount)
55 {
56 streamImage.reset(new QImage(static_cast<uchar *>(bp->blob), streamW, streamH, QImage::Format_Indexed8));
57 streamImage->setColorTable(grayTable);
58 rc = !streamImage->isNull();
59 }
60 else if (static_cast<uint32_t>(bp->size) == totalBaseCount * 3)
61 {
62 streamImage.reset(new QImage(static_cast<uchar *>(bp->blob), streamW, streamH, QImage::Format_RGB888));
63 rc = !streamImage->isNull();
64 }
65
66 if (rc)
67 {
68 kPix = QPixmap::fromImage(streamImage->scaled(size(), Qt::KeepAspectRatio));
69
70 paintOverlay(kPix);
71
72 setPixmap(kPix);
73 }
74
75 emit imageChanged(streamImage);
76
77 return rc;
78}
79
80bool VideoWG::save(const QString &filename, const char *format)
81{
82 return kPix.save(filename, format);
83}
84
85void VideoWG::setSize(uint16_t w, uint16_t h)
86{
87 streamW = w;
88 streamH = h;
89 totalBaseCount = w * h;
90}
91
92//void VideoWG::resizeEvent(QResizeEvent *ev)
93//{
94// setPixmap(QPixmap::fromImage(streamImage->scaled(ev->size(), Qt::KeepAspectRatio)));
95// ev->accept();
96//}
97
98void VideoWG::mousePressEvent(QMouseEvent *event)
99{
100 origin = event->pos();
101 if (!rubberBand)
102 rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
103 rubberBand->setGeometry(QRect(origin, QSize()));
104 rubberBand->show();
105}
106
107void VideoWG::mouseMoveEvent(QMouseEvent *event)
108{
109 rubberBand->setGeometry(QRect(origin, event->pos()).normalized());
110}
111
112void VideoWG::mouseReleaseEvent(QMouseEvent *event)
113{
114 rubberBand->hide();
115
116 if (event->button() == Qt::RightButton)
117 {
118 emit newSelection(QRect());
119 return;
120 }
121
122 QRect rawSelection = rubberBand->geometry();
123 int pixmapX = (width() - kPix.width()) / 2;
124 int pixmapY = (height() - kPix.height()) / 2;
125
127
128 double scaleX = static_cast<double>(streamImage->width()) / kPix.width();
129 double scaleY = static_cast<double>(streamImage->height()) / kPix.height();
130
133 finalSelection.setWidth(rawSelection.width() * scaleX);
134 finalSelection.setHeight(rawSelection.height() * scaleY);
135
136 emit newSelection(finalSelection);
137 // determine selection, for example using QRect::intersects()
138 // and QRect::contains().
139}
140
141bool VideoWG::debayer(const IBLOB *bp, const BayerParams &params)
142{
143 uint32_t rgb_size = streamW * streamH * 3;
144 auto * destinationBuffer = new uint8_t[rgb_size];
145
146 if (destinationBuffer == nullptr)
147 {
148 qCCritical(KSTARS) << "Unable to allocate memory for temporary bayer buffer.";
149 return false;
150 }
151
152 int ds1394_height = streamH;
153
154 uint8_t * dc1394_source = reinterpret_cast<uint8_t*>(bp->blob);
155 if (params.offsetY == 1)
156 {
157 dc1394_source += streamW;
159 }
160 if (params.offsetX == 1)
161 {
163 }
164 dc1394error_t error_code = dc1394_bayer_decoding_8bit(dc1394_source, destinationBuffer, streamW, ds1394_height,
165 params.filter, params.method);
166
167 if (error_code != DC1394_SUCCESS)
168 {
169 qCCritical(KSTARS) << "Debayer failed" << error_code;
170 delete[] destinationBuffer;
171 return false;
172 }
173
174 streamImage.reset(new QImage(destinationBuffer, streamW, streamH, QImage::Format_RGB888));
175 bool rc = !streamImage->isNull();
176
177 if (rc)
178 {
179 kPix = QPixmap::fromImage(streamImage->scaled(size(), Qt::KeepAspectRatio));
180
181 paintOverlay(kPix);
182
183 setPixmap(kPix);
184 }
185
186 emit imageChanged(streamImage);
187
188 delete[] destinationBuffer;
189 return rc;
190}
191
192void VideoWG::paintOverlay(QPixmap &imagePix)
193{
194 if (!overlayEnabled || m_EnabledOverlayElements.count() == 0) return;
195
196 // Anchor - default to center of image
197 QPointF m_anchor (static_cast<float>(kPix.width() / 2), static_cast<float>(kPix.height()/2));
198 scale = (static_cast<float>(kPix.width()) / static_cast<float>(streamW));
199
200 // Apply any offset from (only) the first enabled anchor element
201 bool foundAnchor = false;
202 for (auto &oneElement : m_EnabledOverlayElements) {
203 if (oneElement["Type"] == "Anchor" && !foundAnchor) {
204 m_anchor.setX(m_anchor.x() + oneElement["OffsetX"].toInt());
205 m_anchor.setY(m_anchor.y() + oneElement["OffsetY"].toInt());
206 foundAnchor = true;
207 }
208 }
209
210 painter->begin(&imagePix);
211 painter->translate(m_anchor);
212 painter->scale(scale, scale);
213
214 for (auto &currentElement : m_EnabledOverlayElements) {
215
216 painter->save();
217 QPen m_pen = QPen(QColor(currentElement["Colour"].toString()));
218 m_pen.setWidth(currentElement["Thickness"].toUInt());
221 painter->setPen(m_pen);
222 painter->translate(currentElement["OffsetX"].toFloat(), currentElement["OffsetY"].toFloat());
223
224 int m_count = currentElement["Count"].toUInt();
225 float m_pcd = currentElement["PCD"].toFloat();
226
227 if (m_count == 1) {
228 PaintOneItem(currentElement["Type"].toString(), QPointF(0.0, 0.0), currentElement["SizeX"].toUInt(), currentElement["SizeY"].toUInt(), currentElement["Thickness"].toUInt());
229 } else if (m_count > 1) {
230 float slice = 360 / m_count;
231 for (int i = 0; i < m_count; i++) {
232 painter->save();
233 painter->rotate((slice * i) + currentElement["Rotation"].toFloat());
234 PaintOneItem(currentElement["Type"].toString(), QPointF((m_pcd / 2), 0.0), currentElement["SizeX"].toUInt(), currentElement["SizeY"].toUInt(), currentElement["Thickness"].toUInt());
235 painter->restore();
236 }
237 }
238
239 painter->restore();
240 }
241 painter->end();
242}
243
244void VideoWG::setupOverlay ()
245{
246 if (overlayEnabled) {
247 initOverlayModel();
248
249 typeValues = new QStringList;
250 collimationoverlaytype m_types;
251 const QMetaObject *m_metaobject = m_types.metaObject();
252 QMetaEnum m_metaEnum = m_metaobject->enumerator(m_metaobject->indexOfEnumerator("Types"));
253 for (int i = 0; i < m_metaEnum.keyCount(); i++) {
254 *typeValues << tr(m_metaEnum.key(i));
255 }
256
257 painter = new QPainter;
258 }
259}
260
261void VideoWG::initOverlayModel()
262{
263 m_CollimationOverlayElements.clear();
264 auto userdb = QSqlDatabase::database(KStarsData::Instance()->userdb()->connectionName());
265 m_CollimationOverlayElementsModel = new QSqlTableModel(this, userdb);
266 modelChanged();
267}
268
269void VideoWG::modelChanged()
270{
271 m_CollimationOverlayElements.clear();
272 m_EnabledOverlayElements.clear();
273 KStars::Instance()->data()->userdb()->GetCollimationOverlayElements(m_CollimationOverlayElements);
274 for (auto &oneElement : m_CollimationOverlayElements)
275 if (oneElement["Enabled"] == Qt::Checked)
276 m_EnabledOverlayElements.append(oneElement);
277}
278
279void VideoWG::PaintOneItem (QString type, QPointF position, int sizeX, int sizeY, int thickness)
280{
281 float m_sizeX = sizeX - (thickness / 2);
282 float m_sizeY = sizeY - (thickness / 2);
283
284 switch (typeValues->indexOf(type)) {
285case 0: // Anchor - ignore as we're not drawing it
286 break;
287
288case 1: // Ellipse
289 painter->drawEllipse(position, m_sizeX, m_sizeY);
290 break;
291
292case 2: // Rectangle
293{
294 QRect m_rect((position.x() - (m_sizeX / 2)), (position.y() - (m_sizeY / 2)), (m_sizeX - (thickness / 2)), (m_sizeY - (thickness / 2)));
295 painter->drawRect(m_rect);
296 break;
297}
298
299case 3: // Line
300 painter->drawLine(position.x(), position.y(), sizeX, sizeY);
301 break;
302
303default:
304 break;
305 };
306}
307
308void VideoWG::toggleOverlay()
309{
310 if (overlayEnabled == false) {
311 overlayEnabled = true;
312 if (m_CollimationOverlayElementsModel == nullptr) {
313 setupOverlay();
314 }
315 } else if (overlayEnabled == true) {
316 overlayEnabled = false;
317 }
318}
319
320VideoWG::~VideoWG()
321{
322 delete m_CollimationOverlayElementsModel;
323 delete m_CurrentElement;
324 delete typeValues;
325 delete painter;
326}
static KStars * Instance()
Definition kstars.h:123
char * toString(const EngineQuery &query)
Int toInt() const const
QList< QByteArray > supportedImageFormats()
virtual bool event(QEvent *e) override
void setPixmap(const QPixmap &)
void clear()
bool contains(const AT &value) const const
qsizetype count() const const
QString tr(const char *sourceText, const char *disambiguation, int n)
bool begin(QPaintDevice *device)
void drawEllipse(const QPoint &center, int rx, int ry)
void drawLine(const QLine &line)
void drawRect(const QRect &rectangle)
bool end()
void restore()
void rotate(qreal angle)
void save()
void scale(qreal sx, qreal sy)
void setPen(Qt::PenStyle style)
void translate(const QPoint &offset)
void setCapStyle(Qt::PenCapStyle style)
void setJoinStyle(Qt::PenJoinStyle style)
void setWidth(int width)
QPixmap fromImage(QImage &&image, Qt::ImageConversionFlags flags)
int height() const const
bool save(QIODevice *device, const char *format, int quality) const const
int width() const const
qreal x() const const
qreal y() const const
QRect normalized() const const
void setGeometry(const QRect &rect)
QSqlDatabase database(const QString &connectionName, bool open)
qsizetype indexOf(const QRegularExpression &re, qsizetype from) const const
KeepAspectRatio
RightButton
MiterJoin
void hide()
void show()
void resize(const QSize &)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:19:03 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.