File indexing completed on 2024-04-21 14:45:49
0001 /* 0002 SPDX-FileCopyrightText: 2021 Jasem Mutlaq <mutlaqja@ikarustech.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include <zlib.h> 0008 #include <QApplication> 0009 0010 #include "fitshistogramcommand.h" 0011 #include "fitshistogrameditor.h" 0012 #include "fitsviewer.h" 0013 #include "fits_debug.h" 0014 0015 FITSHistogramCommand::FITSHistogramCommand(const QSharedPointer<FITSData> &data, 0016 FITSHistogramEditor * inHisto, 0017 FITSScale newType, 0018 const QVector<double> &lmin, 0019 const QVector<double> &lmax) : m_ImageData(data), histogram(inHisto), 0020 type(newType), min(lmin), max(lmax) 0021 { 0022 } 0023 0024 FITSHistogramCommand::~FITSHistogramCommand() 0025 { 0026 delete[] delta; 0027 } 0028 0029 bool FITSHistogramCommand::calculateDelta(const uint8_t * buffer) 0030 { 0031 uint8_t const * image_buffer = m_ImageData->getImageBuffer(); 0032 uint32_t totalPixels = m_ImageData->samplesPerChannel() * m_ImageData->channels(); 0033 unsigned long totalBytes = totalPixels * m_ImageData->getBytesPerPixel(); 0034 0035 auto * raw_delta = new uint8_t[totalBytes]; 0036 0037 if (raw_delta == nullptr) 0038 { 0039 qCWarning(KSTARS_FITS) << "Error! not enough memory to create image delta"; 0040 return false; 0041 } 0042 0043 for (uint32_t i = 0; i < totalBytes; i++) 0044 raw_delta[i] = buffer[i] ^ image_buffer[i]; 0045 0046 compressedBytes = sizeof(uint8_t) * totalBytes + totalBytes / 64 + 16 + 3; 0047 delete[] delta; 0048 delta = new uint8_t[compressedBytes]; 0049 0050 if (delta == nullptr) 0051 { 0052 delete[] raw_delta; 0053 qCCritical(KSTARS_FITS) 0054 << "FITSHistogram Error: Ran out of memory compressing delta"; 0055 return false; 0056 } 0057 0058 int r = compress2(delta, &compressedBytes, raw_delta, totalBytes, 5); 0059 0060 if (r != Z_OK) 0061 { 0062 delete[] raw_delta; 0063 /* this should NEVER happen */ 0064 qCCritical(KSTARS_FITS) 0065 << "FITSHistogram Error: Failed to compress raw_delta"; 0066 return false; 0067 } 0068 0069 delete[] raw_delta; 0070 return true; 0071 } 0072 0073 bool FITSHistogramCommand::reverseDelta() 0074 { 0075 uint8_t const * image_buffer = m_ImageData->getImageBuffer(); 0076 uint32_t totalPixels = m_ImageData->samplesPerChannel() * m_ImageData->channels(); 0077 unsigned long totalBytes = totalPixels * m_ImageData->getBytesPerPixel(); 0078 0079 auto * output_image = new uint8_t[totalBytes]; 0080 0081 if (output_image == nullptr) 0082 { 0083 qCWarning(KSTARS_FITS) << "Error! not enough memory to create output image"; 0084 return false; 0085 } 0086 0087 auto * raw_delta = new uint8_t[totalBytes]; 0088 0089 if (raw_delta == nullptr) 0090 { 0091 delete[] output_image; 0092 qCWarning(KSTARS_FITS) << "Error! not enough memory to create image delta"; 0093 return false; 0094 } 0095 0096 int r = uncompress(raw_delta, &totalBytes, delta, compressedBytes); 0097 if (r != Z_OK) 0098 { 0099 qCCritical(KSTARS_FITS) 0100 << "FITSHistogram compression error in reverseDelta()"; 0101 delete[] output_image; 0102 delete[] raw_delta; 0103 return false; 0104 } 0105 0106 for (unsigned int i = 0; i < totalBytes; i++) 0107 output_image[i] = raw_delta[i] ^ image_buffer[i]; 0108 0109 m_ImageData->setImageBuffer(output_image); 0110 0111 delete[] raw_delta; 0112 0113 return true; 0114 } 0115 0116 void FITSHistogramCommand::redo() 0117 { 0118 uint8_t const * image_buffer = m_ImageData->getImageBuffer(); 0119 uint8_t * buffer = nullptr; 0120 uint32_t totalPixels = m_ImageData->samplesPerChannel() * m_ImageData->channels(); 0121 int BBP = m_ImageData->getBytesPerPixel(); 0122 0123 QApplication::setOverrideCursor(Qt::WaitCursor); 0124 0125 if (delta != nullptr) 0126 { 0127 FITSImage::Statistic prevStats; 0128 m_ImageData->saveStatistics(prevStats); 0129 0130 reverseDelta(); 0131 0132 m_ImageData->restoreStatistics(stats); 0133 0134 stats = prevStats; 0135 } 0136 else 0137 { 0138 m_ImageData->saveStatistics(stats); 0139 0140 // If it's rotation of flip, no need to calculate delta 0141 if (type >= FITS_ROTATE_CW && type <= FITS_MOUNT_FLIP_V) 0142 { 0143 m_ImageData->applyFilter(type); 0144 } 0145 else 0146 { 0147 buffer = new uint8_t[totalPixels * BBP]; 0148 0149 if (buffer == nullptr) 0150 { 0151 qWarning(KSTARS_FITS()) << "Error! not enough memory to create image buffer in redo()"; 0152 QApplication::restoreOverrideCursor(); 0153 return; 0154 } 0155 0156 memcpy(buffer, image_buffer, totalPixels * BBP); 0157 0158 QVector<double> dataMin = min, dataMax = max; 0159 switch (type) 0160 { 0161 case FITS_AUTO: 0162 case FITS_LINEAR: 0163 m_ImageData->applyFilter(FITS_LINEAR, nullptr, &dataMin, &dataMax); 0164 break; 0165 0166 case FITS_LOG: 0167 m_ImageData->applyFilter(FITS_LOG, nullptr, &dataMin, &dataMax); 0168 break; 0169 0170 case FITS_SQRT: 0171 m_ImageData->applyFilter(FITS_SQRT, nullptr, &dataMin, &dataMax); 0172 break; 0173 0174 default: 0175 m_ImageData->applyFilter(type); 0176 break; 0177 } 0178 0179 calculateDelta(buffer); 0180 delete[] buffer; 0181 } 0182 } 0183 0184 // if (histogram != nullptr) 0185 // { 0186 // histogram->construct(); 0187 0188 // // if (tab->getViewer()->isStarsMarked()) 0189 // // imageData->findStars().waitForFinished(); 0190 // } 0191 0192 // image->pushFilter(type); 0193 // image->rescale(ZOOM_KEEP_LEVEL); 0194 // image->updateFrame(); 0195 0196 QApplication::restoreOverrideCursor(); 0197 } 0198 0199 void FITSHistogramCommand::undo() 0200 { 0201 QApplication::setOverrideCursor(Qt::WaitCursor); 0202 0203 if (delta != nullptr) 0204 { 0205 FITSImage::Statistic prevStats; 0206 m_ImageData->saveStatistics(prevStats); 0207 0208 reverseDelta(); 0209 0210 m_ImageData->restoreStatistics(stats); 0211 0212 stats = prevStats; 0213 } 0214 else 0215 { 0216 switch (type) 0217 { 0218 case FITS_ROTATE_CW: 0219 m_ImageData->applyFilter(FITS_ROTATE_CCW); 0220 break; 0221 case FITS_ROTATE_CCW: 0222 m_ImageData->applyFilter(FITS_ROTATE_CW); 0223 break; 0224 case FITS_MOUNT_FLIP_H: 0225 case FITS_MOUNT_FLIP_V: 0226 m_ImageData->applyFilter(type); 0227 break; 0228 default: 0229 break; 0230 } 0231 } 0232 0233 // if (histogram != nullptr) 0234 // { 0235 // histogram->construct(); 0236 0237 // // if (tab->getViewer()->isStarsMarked()) 0238 // // imageData->findStars().waitForFinished(); 0239 // } 0240 0241 // image->popFilter(); 0242 // image->rescale(ZOOM_KEEP_LEVEL); 0243 // image->updateFrame(); 0244 0245 QApplication::restoreOverrideCursor(); 0246 } 0247 0248 QString FITSHistogramCommand::text() const 0249 { 0250 switch (type) 0251 { 0252 case FITS_AUTO: 0253 return i18n("Auto Scale"); 0254 case FITS_LINEAR: 0255 return i18n("Linear Scale"); 0256 case FITS_LOG: 0257 return i18n("Logarithmic Scale"); 0258 case FITS_SQRT: 0259 return i18n("Square Root Scale"); 0260 0261 default: 0262 if (type - 1 <= FITSViewer::filterTypes.count()) 0263 return FITSViewer::filterTypes.at(type - 1); 0264 break; 0265 } 0266 0267 return i18n("Unknown"); 0268 } 0269