Kstars

fitshistogramcommand.cpp
1/*
2 SPDX-FileCopyrightText: 2021 Jasem Mutlaq <mutlaqja@ikarustech.com>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include <zlib.h>
8#include <QApplication>
9
10#include "fitshistogramcommand.h"
11#include "fitshistogrameditor.h"
12#include "fitsviewer.h"
13#include "fits_debug.h"
14
15FITSHistogramCommand::FITSHistogramCommand(const QSharedPointer<FITSData> &data,
16 FITSHistogramEditor * inHisto,
17 FITSScale newType,
18 const QVector<double> &lmin,
19 const QVector<double> &lmax) : m_ImageData(data), histogram(inHisto),
20 type(newType), min(lmin), max(lmax)
21{
22}
23
24FITSHistogramCommand::~FITSHistogramCommand()
25{
26 delete[] delta;
27}
28
29bool FITSHistogramCommand::calculateDelta(const uint8_t * buffer)
30{
31 uint8_t const * image_buffer = m_ImageData->getImageBuffer();
32 uint32_t totalPixels = m_ImageData->samplesPerChannel() * m_ImageData->channels();
33 unsigned long totalBytes = totalPixels * m_ImageData->getBytesPerPixel();
34
35 auto * raw_delta = new uint8_t[totalBytes];
36
37 if (raw_delta == nullptr)
38 {
39 qCWarning(KSTARS_FITS) << "Error! not enough memory to create image delta";
40 return false;
41 }
42
43 for (uint32_t i = 0; i < totalBytes; i++)
44 raw_delta[i] = buffer[i] ^ image_buffer[i];
45
46 compressedBytes = sizeof(uint8_t) * totalBytes + totalBytes / 64 + 16 + 3;
47 delete[] delta;
48 delta = new uint8_t[compressedBytes];
49
50 if (delta == nullptr)
51 {
52 delete[] raw_delta;
53 qCCritical(KSTARS_FITS)
54 << "FITSHistogram Error: Ran out of memory compressing delta";
55 return false;
56 }
57
58 int r = compress2(delta, &compressedBytes, raw_delta, totalBytes, 5);
59
60 if (r != Z_OK)
61 {
62 delete[] raw_delta;
63 /* this should NEVER happen */
64 qCCritical(KSTARS_FITS)
65 << "FITSHistogram Error: Failed to compress raw_delta";
66 return false;
67 }
68
69 delete[] raw_delta;
70 return true;
71}
72
73bool FITSHistogramCommand::reverseDelta()
74{
75 uint8_t const * image_buffer = m_ImageData->getImageBuffer();
76 uint32_t totalPixels = m_ImageData->samplesPerChannel() * m_ImageData->channels();
77 unsigned long totalBytes = totalPixels * m_ImageData->getBytesPerPixel();
78
79 auto * output_image = new uint8_t[totalBytes];
80
81 if (output_image == nullptr)
82 {
83 qCWarning(KSTARS_FITS) << "Error! not enough memory to create output image";
84 return false;
85 }
86
87 auto * raw_delta = new uint8_t[totalBytes];
88
89 if (raw_delta == nullptr)
90 {
91 delete[] output_image;
92 qCWarning(KSTARS_FITS) << "Error! not enough memory to create image delta";
93 return false;
94 }
95
96 int r = uncompress(raw_delta, &totalBytes, delta, compressedBytes);
97 if (r != Z_OK)
98 {
99 qCCritical(KSTARS_FITS)
100 << "FITSHistogram compression error in reverseDelta()";
101 delete[] output_image;
102 delete[] raw_delta;
103 return false;
104 }
105
106 for (unsigned int i = 0; i < totalBytes; i++)
107 output_image[i] = raw_delta[i] ^ image_buffer[i];
108
109 m_ImageData->setImageBuffer(output_image);
110
111 delete[] raw_delta;
112
113 return true;
114}
115
116void FITSHistogramCommand::redo()
117{
118 uint8_t const * image_buffer = m_ImageData->getImageBuffer();
119 uint8_t * buffer = nullptr;
120 uint32_t totalPixels = m_ImageData->samplesPerChannel() * m_ImageData->channels();
121 int BBP = m_ImageData->getBytesPerPixel();
122
124
125 if (delta != nullptr)
126 {
127 FITSImage::Statistic prevStats;
128 m_ImageData->saveStatistics(prevStats);
129
130 reverseDelta();
131
132 m_ImageData->restoreStatistics(stats);
133
134 stats = prevStats;
135 }
136 else
137 {
138 m_ImageData->saveStatistics(stats);
139
140 // If it's rotation of flip, no need to calculate delta
141 if (type >= FITS_ROTATE_CW && type <= FITS_MOUNT_FLIP_V)
142 {
143 m_ImageData->applyFilter(type);
144 }
145 else
146 {
147 buffer = new uint8_t[totalPixels * BBP];
148
149 if (buffer == nullptr)
150 {
151 qWarning(KSTARS_FITS()) << "Error! not enough memory to create image buffer in redo()";
153 return;
154 }
155
156 memcpy(buffer, image_buffer, totalPixels * BBP);
157
158 QVector<double> dataMin = min, dataMax = max;
159 switch (type)
160 {
161 case FITS_AUTO:
162 case FITS_LINEAR:
163 m_ImageData->applyFilter(FITS_LINEAR, nullptr, &dataMin, &dataMax);
164 break;
165
166 case FITS_LOG:
167 m_ImageData->applyFilter(FITS_LOG, nullptr, &dataMin, &dataMax);
168 break;
169
170 case FITS_SQRT:
171 m_ImageData->applyFilter(FITS_SQRT, nullptr, &dataMin, &dataMax);
172 break;
173
174 default:
175 m_ImageData->applyFilter(type);
176 break;
177 }
178
179 calculateDelta(buffer);
180 delete[] buffer;
181 }
182 }
183
184 // if (histogram != nullptr)
185 // {
186 // histogram->construct();
187
188 // // if (tab->getViewer()->isStarsMarked())
189 // // imageData->findStars().waitForFinished();
190 // }
191
192 // image->pushFilter(type);
193 // image->rescale(ZOOM_KEEP_LEVEL);
194 // image->updateFrame();
195
197}
198
199void FITSHistogramCommand::undo()
200{
202
203 if (delta != nullptr)
204 {
205 FITSImage::Statistic prevStats;
206 m_ImageData->saveStatistics(prevStats);
207
208 reverseDelta();
209
210 m_ImageData->restoreStatistics(stats);
211
212 stats = prevStats;
213 }
214 else
215 {
216 switch (type)
217 {
218 case FITS_ROTATE_CW:
219 m_ImageData->applyFilter(FITS_ROTATE_CCW);
220 break;
221 case FITS_ROTATE_CCW:
222 m_ImageData->applyFilter(FITS_ROTATE_CW);
223 break;
224 case FITS_MOUNT_FLIP_H:
225 case FITS_MOUNT_FLIP_V:
226 m_ImageData->applyFilter(type);
227 break;
228 default:
229 break;
230 }
231 }
232
233 // if (histogram != nullptr)
234 // {
235 // histogram->construct();
236
237 // // if (tab->getViewer()->isStarsMarked())
238 // // imageData->findStars().waitForFinished();
239 // }
240
241 // image->popFilter();
242 // image->rescale(ZOOM_KEEP_LEVEL);
243 // image->updateFrame();
244
246}
247
248QString FITSHistogramCommand::text() const
249{
250 switch (type)
251 {
252 case FITS_AUTO:
253 return i18n("Auto Scale");
254 case FITS_LINEAR:
255 return i18n("Linear Scale");
256 case FITS_LOG:
257 return i18n("Logarithmic Scale");
258 case FITS_SQRT:
259 return i18n("Square Root Scale");
260
261 default:
262 if (type - 1 <= FITSViewer::filterTypes.count())
263 return FITSViewer::filterTypes[type - 1].toString();
264 break;
265 }
266
267 return i18n("Unknown");
268}
269
QString i18n(const char *text, const TYPE &arg...)
Type type(const QSqlDatabase &db)
void restoreOverrideCursor()
void setOverrideCursor(const QCursor &cursor)
WaitCursor
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 17:04:46 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.