/*
    Scan Tailor - Interactive post-processing tool for scanned pages.
    Copyright (C) 2015  Joseph Artsimovich <joseph.artsimovich@gmail.com>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "DespeckleVisualization.h"
#include "ImageViewBase.h"
#include "imageproc/BinaryImage.h"
#include "imageproc/SEDM.h"
#include <QPainter>
#include <stdint.h>

using namespace imageproc;

namespace output
{

DespeckleVisualization::DespeckleVisualization(
	std::shared_ptr<AcceleratableOperations> const& accel_ops,
	QImage const& output, imageproc::BinaryImage const& speckles)
{
	if (output.isNull()) {
		// This can happen in batch processing mode.
		return;
	}

	m_image = output.convertToFormat(QImage::Format_RGB32);

	if (!speckles.isNull()) {
		colorizeSpeckles(m_image, speckles);
	}

	m_downscaledImage = ImageViewBase::createDownscaledImage(m_image, accel_ops);
}

void
DespeckleVisualization::colorizeSpeckles(
	QImage& image, imageproc::BinaryImage const& speckles)
{
	int const w = image.width();
	int const h = image.height();
	uint32_t* image_line = (uint32_t*)image.bits();
	int const image_stride = image.bytesPerLine() / 4;

	SEDM const sedm(speckles, SEDM::DIST_TO_BLACK, SEDM::DIST_TO_NO_BORDERS);
	uint32_t const* sedm_line = sedm.data();
	int const sedm_stride = sedm.stride();

	float const radius = 20.0 * std::min(w, h) / 3000.0;
	float const sq_radius = radius * radius;

	for (int y = 0; y < h; ++y) {
		for (int x = 0; x < w; ++x) {
			uint32_t const sq_dist = sedm_line[x];
			if (sq_dist == 0) {
				// Speckle pixel.
				image_line[x] = 0xffff0000; // opaque red
				continue;
			} else if ((image_line[x] & 0x00ffffff) == 0x0) {
				// Non-speckle black pixel.
				continue;
			}

			float const alpha_upper_bound = 0.8f;
			float const scale = alpha_upper_bound / sq_radius;
			float const alpha = alpha_upper_bound - scale * sq_dist;
			if (alpha > 0) {
				float const alpha2 = 1.0f - alpha;
				float const overlay_r = 255;
				float const overlay_g = 0;
				float const overlay_b = 0;
				float const r = overlay_r * alpha + qRed(image_line[x]) * alpha2;
				float const g = overlay_g * alpha + qGreen(image_line[x]) * alpha2;
				float const b = overlay_b * alpha + qBlue(image_line[x]) * alpha2;
				image_line[x] = qRgb(int(r), int(g), int(b));
			}
		}
		sedm_line += sedm_stride;
		image_line += image_stride;
	}
}

} // namespace output
