Kstars

fitshistogramcommand.cpp
1 /*
2  SPDX-FileCopyrightText: 2021 Jasem Mutlaq <[email protected]>
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 
15 FITSHistogramCommand::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 
24 FITSHistogramCommand::~FITSHistogramCommand()
25 {
26  delete[] delta;
27 }
28 
29 bool 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 
73 bool 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 
116 void 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_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 
199 void 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_FLIP_H:
225  case FITS_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 
248 QString 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.at(type - 1);
264  break;
265  }
266 
267  return i18n("Unknown");
268 }
269 
Type type(const QSqlDatabase &db)
QString i18n(const char *text, const TYPE &arg...)
WaitCursor
const T & at(int i) const const
void setOverrideCursor(const QCursor &cursor)
void restoreOverrideCursor()
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Fri Aug 12 2022 04:00:53 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.