[TASK] Move most basic logic into lazy_image.cpp.
This commit is contained in:
parent
ef298dc322
commit
884c8ee7ae
|
@ -45,9 +45,8 @@
|
|||
* @brief ImageViewer::ImageViewer
|
||||
*/
|
||||
ImageViewer::ImageViewer() {
|
||||
original_image = NULL;
|
||||
image = NULL;
|
||||
histogramm = NULL;
|
||||
original = NULL;
|
||||
working_copy = NULL;
|
||||
startLogging();
|
||||
generateMainGui();
|
||||
renewLogging();
|
||||
|
@ -66,44 +65,27 @@ ImageViewer::ImageViewer() {
|
|||
* @brief ImageViewer::initializeImage
|
||||
*/
|
||||
void ImageViewer::initializeImage() {
|
||||
if(image==NULL) {
|
||||
if(original->getImage() == NULL) {
|
||||
std::cout << "Error! No image provided!" << std::endl;
|
||||
return;
|
||||
}
|
||||
analyzeImage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses simple weights to calculate intensity of a pixel.
|
||||
* Using qRound() to reduce the error of the int cast.
|
||||
*
|
||||
* @brief ImageViewer::calcIntensity
|
||||
*/
|
||||
int ImageViewer::calcIntensity(int r, int g, int b) {
|
||||
return (int) qRound(0.299*r + 0.587*g + 0.114*b);
|
||||
}
|
||||
|
||||
/**
|
||||
* In case it is needed, convert the loaded image into grayscale.
|
||||
* This is one of the only methods modifying original_image!
|
||||
* This is the only method modifying the original image!
|
||||
*
|
||||
* @brief ImageViewer::convertToMonochrome
|
||||
*/
|
||||
void ImageViewer::convertToMonochrome() {
|
||||
if(image!=NULL) {
|
||||
if(original->getImage() != NULL) {
|
||||
logFile << "Converting image to monochrome...";
|
||||
renewLogging();
|
||||
for(int x=0; x<image->width(); x++) {
|
||||
for(int y=0; y<image->height(); y++) {
|
||||
int r,g,b;
|
||||
QColor color = QColor::fromRgb(image->pixel(x, y));
|
||||
color.getRgb(&r,&g,&b);
|
||||
int intensity = calcIntensity(r, g, b);
|
||||
color = QColor::fromRgb(intensity, intensity, intensity);
|
||||
image->setPixel(x, y, color.rgb());
|
||||
original_image->setPixel(x, y, color.rgb());
|
||||
}
|
||||
}
|
||||
|
||||
original->convertToMonochrome();
|
||||
working_copy->convertToMonochrome();
|
||||
|
||||
updateImageDisplay();
|
||||
logFile << "done." << std::endl;
|
||||
renewLogging();
|
||||
|
@ -115,9 +97,9 @@ void ImageViewer::convertToMonochrome() {
|
|||
* @brief ImageViewer::drawBlackLine
|
||||
*/
|
||||
void ImageViewer::drawBlackLine() {
|
||||
if(image!=NULL) {
|
||||
for(int i=0;i<std::min(image->width(),image->height());i++) {
|
||||
image->setPixel(i,i,0);
|
||||
if(original->getImage() != NULL) {
|
||||
for(int i=0;i<std::min(working_copy->getImage()->width(),working_copy->getImage()->height());i++) {
|
||||
working_copy->getImage()->setPixel(i,i,0);
|
||||
}
|
||||
updateImageDisplay();
|
||||
logFile << "Black line drawn." << std::endl;
|
||||
|
@ -130,13 +112,13 @@ void ImageViewer::drawBlackLine() {
|
|||
* @brief ImageViewer::drawDiagonalCross
|
||||
*/
|
||||
void ImageViewer::drawDiagonalCross() {
|
||||
if(image!=NULL) {
|
||||
if(original->getImage() != NULL) {
|
||||
int color = QColor::fromHsl(120,255,125).rgb();
|
||||
int width = image->width();
|
||||
int height = image->height();
|
||||
for(int y=0; y<image->height(); y++) {
|
||||
image->setPixel((1.0*y/height)*width,y,color);
|
||||
image->setPixel((1.0-(1.0*y/height))*width,y,color);
|
||||
int width = working_copy->getImage()->width();
|
||||
int height = working_copy->getImage()->height();
|
||||
for(int y=0; y<working_copy->getImage()->height(); y++) {
|
||||
working_copy->getImage()->setPixel((1.0*y/height)*width,y,color);
|
||||
working_copy->getImage()->setPixel((1.0-(1.0*y/height))*width,y,color);
|
||||
}
|
||||
}
|
||||
updateImageDisplay();
|
||||
|
@ -160,17 +142,17 @@ void ImageViewer::drawRainbowCross() {
|
|||
* @param initialHue
|
||||
*/
|
||||
void ImageViewer::drawRainbowCross(int initialHue=0) {
|
||||
if(image!=NULL) {
|
||||
if(original->getImage() != NULL) {
|
||||
int h = initialHue;
|
||||
QColor myColor = QColor::fromHsl(h, 255, 125);
|
||||
int image_width = image->width()-1;
|
||||
int image_width = working_copy->getImage()->width()-1;
|
||||
int range = line_slider->value();
|
||||
if(range > image->width()-2) range = image->width()-2;
|
||||
for(int i=0;i<std::min(image->width(),image->height());i++) {
|
||||
if(range > working_copy->getImage()->width()-2) range = working_copy->getImage()->width()-2;
|
||||
for(int i=0;i<std::min(working_copy->getImage()->width(),working_copy->getImage()->height());i++) {
|
||||
int color = myColor.rgb();
|
||||
for(int r=0; r<range; r++) {
|
||||
image->setPixel(i+r,i,color);
|
||||
image->setPixel((image_width-i)-r,i,color);
|
||||
working_copy->getImage()->setPixel(i+r,i,color);
|
||||
working_copy->getImage()->setPixel((image_width-i)-r,i,color);
|
||||
}
|
||||
h++;
|
||||
if(h > 359) h = 0;
|
||||
|
@ -201,107 +183,22 @@ void ImageViewer::acidTrippin() {
|
|||
* Analyze the image, get average luminance
|
||||
* Also fill grayscale_absolute_histogramm
|
||||
*
|
||||
* TODO: Decouple this from the drawing of the histogramm
|
||||
* (READ: Fuck, reanalyzing my image fucks up tools that work on histogramm data!)
|
||||
*
|
||||
* @brief ImageViewer::analyzeImage
|
||||
*/
|
||||
void ImageViewer::analyzeImage() {
|
||||
if(image!=NULL) {
|
||||
//Zero existing histogramm data first
|
||||
for(int i=0; i<256; i++) {
|
||||
grayscale_absolute_histogramm[i] = 0;
|
||||
grayscale_relative_histogramm[i] = 0;
|
||||
}
|
||||
|
||||
if(original->getImage() != NULL) {
|
||||
logFile << "Analyzing image ...";
|
||||
renewLogging();
|
||||
for(int x=0; x<image->width(); x++) {
|
||||
for(int y=0; y<image->height(); y++) {
|
||||
int r,g,b;
|
||||
QColor color = QColor::fromRgb(image->pixel(x, y));
|
||||
color.getRgb(&r,&g,&b);
|
||||
int intensity = calcIntensity(r, g, b);
|
||||
grayscale_absolute_histogramm[intensity] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
int pixels = image->width()*image->height();
|
||||
for(int i=0; i<256; i++) {
|
||||
grayscale_relative_histogramm[i] = (((double) grayscale_absolute_histogramm[i])/((double) pixels));
|
||||
}
|
||||
|
||||
original->updateStatistics();
|
||||
working_copy->updateStatistics();
|
||||
logFile << "done" << std::endl;
|
||||
renewLogging();
|
||||
|
||||
QString result = QString("Intensity: Average: %1, Variance: %2").arg(getAverageIntensity()).arg(getIntensityVariance());
|
||||
QString result = QString("Intensity: Average: %1, Variance: %2").arg(working_copy->getIntensityAverage()).arg(working_copy->getIntensityVariance());
|
||||
stats->setText(result);
|
||||
|
||||
updateHistogramm();
|
||||
histogramm_label->setPixmap(QPixmap::fromImage(*(working_copy->getHistogrammImage())));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use histogramm to retrieve the average intensity.
|
||||
* @brief ImageViewer::getAverageIntensity
|
||||
*/
|
||||
int ImageViewer::getAverageIntensity() {
|
||||
double sumIntensity = 0;
|
||||
for(int i=0; i<256;i++) {
|
||||
sumIntensity += (i*grayscale_relative_histogramm[i]);
|
||||
}
|
||||
return (int) qRound(sumIntensity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the intensity variance from the image.
|
||||
* @brief ImageViewer::getVarianceIntensity
|
||||
*/
|
||||
int ImageViewer::getIntensityVariance() {
|
||||
int average_intensity = getAverageIntensity();
|
||||
int sumDifference = 0;
|
||||
for(int x=0; x<image->width(); x++) {
|
||||
for(int y=0; y<image->height(); y++) {
|
||||
QColor color = QColor::fromRgb(image->pixel(x, y));
|
||||
int r,g,b;
|
||||
color.getRgb(&r,&g,&b);
|
||||
int intensity = calcIntensity(r, g, b);
|
||||
int diff = std::abs(intensity - average_intensity);
|
||||
sumDifference += diff;
|
||||
}
|
||||
}
|
||||
return (int) (sumDifference/(image->width()*image->height()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds up the image for the histogramm.
|
||||
* @brief ImageViewer::updateHistogramm
|
||||
*/
|
||||
void ImageViewer::updateHistogramm() {
|
||||
if(histogramm != NULL) {
|
||||
delete histogramm;
|
||||
histogramm = NULL;
|
||||
}
|
||||
//Find biggest value in histogramm data
|
||||
double max = 0;
|
||||
for(int i=0; i<256; i++) {
|
||||
if(grayscale_relative_histogramm[i] > max) max = grayscale_relative_histogramm[i];
|
||||
}
|
||||
|
||||
histogramm = new QImage(256, 100, QImage::Format_RGB32);
|
||||
histogramm->fill(QColor::fromRgb(200,200,200));
|
||||
int black = QColor::fromRgb(0,0,0).rgb();
|
||||
for(int x=0; x<256; x++) {
|
||||
int k_max = (int) qRound((100*grayscale_relative_histogramm[x])/max);
|
||||
for(int y=0; y<k_max; y++) {
|
||||
histogramm->setPixel(x, (100-y)-1, black);
|
||||
}
|
||||
}
|
||||
logFile << "Histogramm done." << std::endl;
|
||||
renewLogging();
|
||||
histogramm_label->setPixmap(QPixmap::fromImage(*histogramm));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired by the brightness_slider, this one adjusts the brightness on image.
|
||||
* @brief ImageViewer::adjustBrightness
|
||||
|
@ -310,15 +207,15 @@ void ImageViewer::adjustBrightness(int b) {
|
|||
int h, s, old_l;
|
||||
int new_l = 0;
|
||||
int delta = b - 255;
|
||||
for(int x=0; x<image->width(); x++) {
|
||||
for(int y=0; y<image->height(); y++) {
|
||||
QColor color = QColor::fromRgb(original_image->pixel(x, y));
|
||||
for(int x=0; x<working_copy->getImage()->width(); x++) {
|
||||
for(int y=0; y<working_copy->getImage()->height(); y++) {
|
||||
QColor color = QColor::fromRgb(original->getImage()->pixel(x, y));
|
||||
color.getHsl(&h, &s, &old_l);
|
||||
new_l = old_l + delta;
|
||||
if(new_l > 255) new_l = 255;
|
||||
if(new_l < 0) new_l = 0;
|
||||
color.setHsl(h, s, new_l);
|
||||
image->setPixel(x, y, color.rgb());
|
||||
working_copy->getImage()->setPixel(x, y, color.rgb());
|
||||
}
|
||||
}
|
||||
updateImageDisplay();
|
||||
|
@ -334,16 +231,16 @@ void ImageViewer::adjustContrast(int c) {
|
|||
int h, s, old_l;
|
||||
int new_l = 0;
|
||||
double alpha = c / 255.0;
|
||||
int average_intensity = getAverageIntensity();
|
||||
for(int x=0; x<image->width(); x++) {
|
||||
for(int y=0; y<image->height(); y++) {
|
||||
QColor color = QColor::fromRgb(original_image->pixel(x, y));
|
||||
int average_intensity = original->getIntensityAverage();
|
||||
for(int x=0; x<working_copy->getImage()->width(); x++) {
|
||||
for(int y=0; y<working_copy->getImage()->height(); y++) {
|
||||
QColor color = QColor::fromRgb(original->getImage()->pixel(x, y));
|
||||
color.getHsl(&h, &s, &old_l);
|
||||
new_l = average_intensity + ((int) round((old_l - average_intensity) * alpha));
|
||||
if(new_l > 255) new_l = 255;
|
||||
if(new_l < 0) new_l = 0;
|
||||
color.setHsl(h, s, new_l);
|
||||
image->setPixel(x, y, color.rgb());
|
||||
working_copy->getImage()->setPixel(x, y, color.rgb());
|
||||
}
|
||||
}
|
||||
updateImageDisplay();
|
||||
|
@ -366,6 +263,7 @@ void ImageViewer::robustAutomaticContrastAdaption(void) {
|
|||
int upper_border = -1;
|
||||
double limit = percentile / 100.0;
|
||||
double cursor = 0.0;
|
||||
double* grayscale_relative_histogramm = original->getRelativeIntensityHistogramm();
|
||||
for(int i=0; i<256; i++) {
|
||||
cursor += grayscale_relative_histogramm[i];
|
||||
if(cursor >= limit && lower_border == -1) {
|
||||
|
@ -383,9 +281,9 @@ void ImageViewer::robustAutomaticContrastAdaption(void) {
|
|||
renewLogging();
|
||||
|
||||
int h, s, l;
|
||||
for(int x=0; x<image->width(); x++) {
|
||||
for(int y=0; y<image->height(); y++) {
|
||||
QColor color = QColor::fromRgb(original_image->pixel(x, y));
|
||||
for(int x=0; x<working_copy->getImage()->width(); x++) {
|
||||
for(int y=0; y<working_copy->getImage()->height(); y++) {
|
||||
QColor color = QColor::fromRgb(original->getImage()->pixel(x, y));
|
||||
color.getHsl(&h, &s, &l);
|
||||
|
||||
if(l < lower_border) {
|
||||
|
@ -397,7 +295,7 @@ void ImageViewer::robustAutomaticContrastAdaption(void) {
|
|||
}
|
||||
|
||||
color.setHsl(h, s, l);
|
||||
image->setPixel(x, y, color.rgb());
|
||||
working_copy->getImage()->setPixel(x, y, color.rgb());
|
||||
}
|
||||
}
|
||||
updateImageDisplay();
|
||||
|
@ -513,7 +411,6 @@ void ImageViewer::generateControlPanels() {
|
|||
task_tab3 = new QVBoxLayout();
|
||||
task_tab_widget3->setLayout(task_tab3);
|
||||
|
||||
|
||||
tabWidget->addTab(task_tab_widget3, "Task #3");
|
||||
|
||||
//Show it
|
||||
|
@ -551,7 +448,7 @@ void ImageViewer::renewLogging()
|
|||
}
|
||||
|
||||
void ImageViewer::updateImageDisplay() {
|
||||
imageLabel->setPixmap(QPixmap::fromImage(*image));
|
||||
imageLabel->setPixmap(QPixmap::fromImage(*(working_copy->getImage())));
|
||||
}
|
||||
|
||||
|
||||
|
@ -611,19 +508,19 @@ void ImageViewer::print() {
|
|||
}
|
||||
|
||||
void ImageViewer::open() {
|
||||
if(image != NULL) {
|
||||
delete image;
|
||||
image = NULL;
|
||||
if(working_copy != NULL) {
|
||||
delete working_copy;
|
||||
working_copy = NULL;
|
||||
}
|
||||
if(original_image!=NULL) {
|
||||
delete original_image;
|
||||
original_image = NULL;
|
||||
if(original != NULL) {
|
||||
delete original;
|
||||
original = NULL;
|
||||
}
|
||||
QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), QDir::currentPath());
|
||||
if(!fileName.isEmpty()) {
|
||||
image = new QImage(fileName);
|
||||
original_image = new QImage(fileName);
|
||||
if(image->isNull()) {
|
||||
working_copy = new LazyImage(new QImage(fileName));
|
||||
original = new LazyImage(new QImage(fileName));
|
||||
if(working_copy->getImage()->isNull()) {
|
||||
QMessageBox::information(this, tr("Image Viewer"), tr("Cannot load %1.").arg(fileName));
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -54,6 +54,8 @@
|
|||
#include "fstream"
|
||||
#include <iostream>
|
||||
|
||||
#include "lazy_image.cpp"
|
||||
|
||||
class QAction;
|
||||
class QLabel;
|
||||
class QMenu;
|
||||
|
@ -101,10 +103,8 @@ class ImageViewer : public QMainWindow {
|
|||
QVBoxLayout* task_tab3;
|
||||
|
||||
// "My" space for storing data/results
|
||||
int grayscale_absolute_histogramm[256];
|
||||
double grayscale_relative_histogramm[256];
|
||||
QImage* histogramm;
|
||||
QImage* original_image;
|
||||
LazyImage* original;
|
||||
LazyImage* working_copy;
|
||||
|
||||
private slots:
|
||||
// Custom slots
|
||||
|
@ -113,7 +113,6 @@ class ImageViewer : public QMainWindow {
|
|||
void drawDiagonalCross();
|
||||
void acidTrippin();
|
||||
void analyzeImage();
|
||||
void updateHistogramm();
|
||||
void adjustBrightness(int b);
|
||||
void adjustContrast(int c);
|
||||
void convertToMonochrome();
|
||||
|
@ -160,7 +159,6 @@ class ImageViewer : public QMainWindow {
|
|||
QLabel* imageLabel;
|
||||
QScrollArea* scrollArea;
|
||||
double scaleFactor;
|
||||
QImage* image;
|
||||
|
||||
std::fstream logFile;
|
||||
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
#ifndef LAZY_IMAGE_C
|
||||
#define LAZY_IMAGE_C
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QMainWindow>
|
||||
#include <QColor>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
class LazyImage {
|
||||
|
||||
private:
|
||||
QImage* img; //Not managed by us, just used.
|
||||
QImage* histogramm_image;
|
||||
double histogramm_relative_intensity[256];
|
||||
int histogramm_absolute_intensity[256];
|
||||
int intensity_average;
|
||||
int intensity_variance;
|
||||
|
||||
void gatherHistogrammData(void) {
|
||||
// Zero existing histogramm data first
|
||||
for(int i=0; i<256; i++) {
|
||||
histogramm_relative_intensity[i] = 0;
|
||||
histogramm_absolute_intensity[i] = 0;
|
||||
}
|
||||
// Count all the brightness values
|
||||
for(int x=0; x<this->img->width(); x++) {
|
||||
for(int y=0; y<this->img->height(); y++) {
|
||||
int r,g,b;
|
||||
QColor color = QColor::fromRgb(this->img->pixel(x, y));
|
||||
color.getRgb(&r,&g,&b);
|
||||
int intensity = this->calcIntensity(r, g, b);
|
||||
histogramm_absolute_intensity[intensity] += 1;
|
||||
}
|
||||
}
|
||||
// Calculate relative histogramm
|
||||
int pixels = this->img->width()*this->img->height();
|
||||
for(int i=0; i<256; i++) {
|
||||
histogramm_relative_intensity[i] = (((double) histogramm_absolute_intensity[i])/((double) pixels));
|
||||
}
|
||||
};
|
||||
|
||||
void calcIntensityAverage(void) {
|
||||
double sum = 0;
|
||||
for(int i=0; i<256;i++) {
|
||||
sum += (i*histogramm_relative_intensity[i]);
|
||||
}
|
||||
this->intensity_average = (int) qRound(sum);
|
||||
};
|
||||
|
||||
void calcIntensityVariance(void) {
|
||||
int intensity_average = this->intensity_average;
|
||||
int sum_difference = 0;
|
||||
for(int x=0; x<this->img->width(); x++) {
|
||||
for(int y=0; y<this->img->height(); y++) {
|
||||
QColor color = QColor::fromRgb(this->img->pixel(x, y));
|
||||
int r,g,b;
|
||||
color.getRgb(&r,&g,&b);
|
||||
sum_difference += std::abs(this->calcIntensity(r, g, b) - intensity_average);;
|
||||
}
|
||||
}
|
||||
this->intensity_variance = (int) qRound(sum_difference/(this->img->width()*this->img->height()));
|
||||
};
|
||||
|
||||
void generateHistogrammImage(void) {
|
||||
if(this->histogramm_image != NULL) {
|
||||
delete this->histogramm_image;
|
||||
this->histogramm_image = NULL;
|
||||
}
|
||||
//Find biggest value in histogramm data
|
||||
double max = 0;
|
||||
for(int i=0; i<256; i++) {
|
||||
if(histogramm_relative_intensity[i] > max) max = histogramm_relative_intensity[i];
|
||||
}
|
||||
|
||||
this->histogramm_image = new QImage(256, 100, QImage::Format_RGB32);
|
||||
this->histogramm_image->fill(QColor::fromRgb(200,200,200));
|
||||
int black = QColor::fromRgb(0,0,0).rgb();
|
||||
for(int x=0; x<256; x++) {
|
||||
int k_max = (int) qRound((100*histogramm_relative_intensity[x])/max);
|
||||
for(int y=0; y<k_max; y++) {
|
||||
this->histogramm_image->setPixel(x, (100-y)-1, black);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
LazyImage(QImage* img) {
|
||||
this->histogramm_image = NULL;
|
||||
this->setImage(img);
|
||||
};
|
||||
|
||||
~LazyImage() {
|
||||
if(img != NULL) {
|
||||
img = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
void setImage(QImage* img) {
|
||||
if(img != NULL) {
|
||||
this->img = img;
|
||||
this->updateStatistics();
|
||||
}
|
||||
};
|
||||
|
||||
QImage* getImage(void) {
|
||||
return this->img;
|
||||
};
|
||||
|
||||
void updateStatistics(void) {
|
||||
this->gatherHistogrammData();
|
||||
this->calcIntensityAverage();
|
||||
this->calcIntensityVariance();
|
||||
this->generateHistogrammImage();
|
||||
};
|
||||
|
||||
QImage* getHistogrammImage(void) {
|
||||
return this->histogramm_image;
|
||||
};
|
||||
|
||||
/**
|
||||
* Uses simple weights to calculate intensity of a pixel.
|
||||
* Using qRound() to reduce the error of the int cast.
|
||||
*
|
||||
* @brief LazyImage::calcIntensity
|
||||
*/
|
||||
int calcIntensity(int r, int g, int b) {
|
||||
return (int) qRound(0.299*r + 0.587*g + 0.114*b);
|
||||
};
|
||||
|
||||
int getIntensityAverage(void) {
|
||||
return this->intensity_average;
|
||||
}
|
||||
|
||||
int getIntensityVariance(void) {
|
||||
return this->intensity_variance;
|
||||
};
|
||||
|
||||
int* getAbsoluteIntensityHistogramm(void) {
|
||||
return this->histogramm_absolute_intensity;
|
||||
};
|
||||
|
||||
double* getRelativeIntensityHistogramm(void) {
|
||||
return this->histogramm_relative_intensity;
|
||||
};
|
||||
|
||||
void convertToMonochrome(void) {
|
||||
for(int x=0; x<this->img->width(); x++) {
|
||||
for(int y=0; y<this->img->height(); y++) {
|
||||
int r,g,b;
|
||||
QColor color = QColor::fromRgb(this->img->pixel(x, y));
|
||||
color.getRgb(&r,&g,&b);
|
||||
int intensity = this->calcIntensity(r, g, b);
|
||||
color = QColor::fromRgb(intensity, intensity, intensity);
|
||||
this->img->setPixel(x, y, color.rgb());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue