Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Toonz includes
Toshihiro Shimizu 890ddd
#include "tpixelutils.h"
Toshihiro Shimizu 890ddd
#include "tpalette.h"
Toshihiro Shimizu 890ddd
#include "tcolorstyles.h"
Toshihiro Shimizu 890ddd
#include "timage_io.h"
Toshihiro Shimizu 890ddd
#include "tropcm.h"
Toshihiro Shimizu 890ddd
#include "ttile.h"
Toshihiro Shimizu 890ddd
#include "toonz/toonzscene.h"
Toshihiro Shimizu 890ddd
#include "toonz/tcamera.h"
Toshihiro Shimizu 890ddd
#include "autoadjust.h"
Toshihiro Shimizu 890ddd
#include "autopos.h"
Toshihiro Shimizu 890ddd
#include "cleanuppalette.h"
Toshihiro Shimizu 890ddd
#include "cleanupcommon.h"
Toshihiro Shimizu 890ddd
#include "tmsgcore.h"
Toshihiro Shimizu 890ddd
#include "toonz/cleanupparameters.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonz/tcleanupper.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
using namespace CleanupTypes;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*  The Cleanup Process Reworked   -   EXPLANATION (by Daniele)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
INTRODUCTION:
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  The purpose of a Cleanup Process is hereby intended as the task of transforming
Toshihiro Shimizu 890ddd
  a fullcolor image (any bpp, matte supported*) into a TRasterCM32 - 
Toshihiro Shimizu 890ddd
  that is, a colormap image - given an externally specified palette of ink colors to
Toshihiro Shimizu 890ddd
  be recognized. No paint color is assumed at this stage.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  Typically, artists draw outlines using a black or dark color, whereas different hues are
Toshihiro Shimizu 890ddd
  used to mark lines that denote shadows or lights on characters.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  Additional processing steps include the ability to recognize and counter any linear
Toshihiro Shimizu 890ddd
  transformation in the image which is 'signaled' by the presence of (black) pegbar holes,
Toshihiro Shimizu 890ddd
  so that the countering linear transformation maps those peg holes in the usual centered
Toshihiro Shimizu 890ddd
  horizontal fashion.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  Post-processing include despeckling (ie removal or recoloration of little blots with
Toshihiro Shimizu 890ddd
  uniform color), and tones' brigthness/contrast manipulation.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  (*) The image is first overed on top of a white background
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
CONSTRAINTS:
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  We assume the following constraints throughout the process:
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  - Palette colors:
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
    * Color 0 represents the PAPER color, and will just substitute it in the colormap.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
    * Colors with index >= 2 are MATCH-LINE colors, and their HUE ONLY (the H in HSV coordinates)
Toshihiro Shimizu 890ddd
    is essential to line recognition. The hue of image pixels is compared to that of each
Toshihiro Shimizu 890ddd
    matchline color - and the nearest matchline color is associated to that pixel.
Toshihiro Shimizu 890ddd
    If that associated matchline color is still too 'hue-distant' from the pixel color
Toshihiro Shimizu 890ddd
    (beyond a user-specified parameter), the pixel is ignored (ie associated to paper).
Toshihiro Shimizu 890ddd
    Furthermore, each matchline color also has a parameter corresponding to a saturation
Toshihiro Shimizu 890ddd
    threshold; pixels whose color's saturation is below the threshold specified by the
Toshihiro Shimizu 890ddd
    associated color are reassociated to the PAPER color.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
    * Color 1 represents the OUTLINE color, and its VALUE (the V in HSV coordinates) is
Toshihiro Shimizu 890ddd
    assumed to be the image's lowest. Its H and S components are unused. 
Toshihiro Shimizu 890ddd
    Pixels whose value is below this value + a user-defined threshold parameter are
Toshihiro Shimizu 890ddd
    'outline-PRONE' pixels (even matchline-associated pixels can be).
Toshihiro Shimizu 890ddd
    They are assumed to be full outline pixels if their CHROMA (S*V) is above a
Toshihiro Shimizu 890ddd
    'Color threshold'. This condition lets the user settle how outline/matchline
Toshihiro Shimizu 890ddd
    disputed pixels should be considered.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  - The Colormap tone for a pixel is extracted according to these rules:
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
    * Paper pixels are completely transparent (tone = 255).
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
    * Undisputed matchline colors build the tone upon the pixel's Saturation, scaled
Toshihiro Shimizu 890ddd
      so that 1.0 maps to 0, and the saturation threshold for that matchline
Toshihiro Shimizu 890ddd
      color maps to 255.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
    * Undisputed Outline colors do similarly, with the Value.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
    * Disputed outline/matchline colors result in the blend PRODUCT of the above tones.
Toshihiro Shimizu 890ddd
      This makes the tone smoother on outline/matchline intersections.
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
//    Local namespace stuff
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//some useful functions for doing math
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline double affMV1(const TAffine &aff, double v1, double v2)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return aff.a11 * v1 + aff.a12 * v2 + aff.a13;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline double affMV2(const TAffine &aff, double v1, double v2)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return aff.a21 * v1 + aff.a22 * v2 + aff.a23;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! Auxiliary class for HSV (toonz 4.x style)
Toshihiro Shimizu 890ddd
struct HSVColor {
Toshihiro Shimizu 890ddd
	double m_h;
Toshihiro Shimizu 890ddd
	double m_s;
Toshihiro Shimizu 890ddd
	double m_v;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	HSVColor(double h = 0, double s = 0, double v = 0)
Toshihiro Shimizu 890ddd
		: m_h(h), m_s(s), m_v(v) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	static HSVColor fromRGB(double r, double g, double b);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
HSVColor HSVColor::fromRGB(double r, double g, double b)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	double h, s, v;
Toshihiro Shimizu 890ddd
	double max, min, delta;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	max = tmax(r, g, b);
Toshihiro Shimizu 890ddd
	min = tmin(r, g, b);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	v = max;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (max != 0)
Toshihiro Shimizu 890ddd
		s = (max - min) / max;
Toshihiro Shimizu 890ddd
	else
Toshihiro Shimizu 890ddd
		s = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (s == 0)
Toshihiro Shimizu 890ddd
		h = 0;
Toshihiro Shimizu 890ddd
	else {
Toshihiro Shimizu 890ddd
		delta = max - min;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (r == max)
Toshihiro Shimizu 890ddd
			h = (g - b) / delta;
Toshihiro Shimizu 890ddd
		else if (g == max)
Toshihiro Shimizu 890ddd
			h = 2.0 + (b - r) / delta;
Toshihiro Shimizu 890ddd
		else if (b == max)
Toshihiro Shimizu 890ddd
			h = 4.0 + (r - g) / delta;
Toshihiro Shimizu 890ddd
		h = h * 60.0;
Toshihiro Shimizu 890ddd
		if (h < 0)
Toshihiro Shimizu 890ddd
			h += 360.0;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return HSVColor(h, s, v);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! Precomputation data about target colors
Toshihiro Shimizu 890ddd
struct TargetColorData {
Toshihiro Shimizu 890ddd
	int m_idx;					   //!< Palette color index
Toshihiro Shimizu 890ddd
	HSVColor m_hsv;				   //!< HSV coordinates of the color
Toshihiro Shimizu 890ddd
	double m_saturationLower;	  //!< Pixel colors associated with this color must be above this
Toshihiro Shimizu 890ddd
	double m_hueLower, m_hueUpper; //!< Pixel colors associated with this color must in this range
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	TargetColorData(const TargetColor &color)
Toshihiro Shimizu 890ddd
		: m_idx(-1), m_hsv(HSVColor::fromRGB(color.m_color.r / 255.0, color.m_color.g / 255.0, color.m_color.b / 255.0)), m_saturationLower(1.0 - color.m_threshold / 100.0), m_hueLower(m_hsv.m_h - color.m_hRange * 0.5), m_hueUpper(m_hsv.m_h + color.m_hRange * 0.5)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		if (m_hueLower < 0.0)
Toshihiro Shimizu 890ddd
			m_hueLower += 360.0;
Toshihiro Shimizu 890ddd
		if (m_hueUpper > 360.0)
Toshihiro Shimizu 890ddd
			m_hueUpper -= 360.0;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! Birghtness/Contrast color transform data
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define MAX_N_PENCILS 8
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/* the following must be updated at every change in palette content */
Toshihiro Shimizu 890ddd
int N_pencils = 4;						/* not counting autoclose */
Toshihiro Shimizu 890ddd
TPixelRGBM32 Pencil[MAX_N_PENCILS + 1]; /* last is autoclose pencil */
Toshihiro Shimizu 890ddd
int Pencil_index[MAX_N_PENCILS + 1];	/* "" */
Toshihiro Shimizu 890ddd
int Pencil_id[MAX_N_PENCILS + 1];		/* "" */
Toshihiro Shimizu 890ddd
TPixelRGBM32 Paper = TPixel32::White;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! Birghtness/Contrast color transform structure
Toshihiro Shimizu 890ddd
class TransfFunction
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	USHORT TransfFun[(MAX_N_PENCILS + 1) << 8];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void setTransfFun(int pencil, int b1, int c1)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		int i, p1, p2, brig, cont, max;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		cont = 255 - c1;
Toshihiro Shimizu 890ddd
		brig = 255 - b1;
Toshihiro Shimizu 890ddd
		max = 255;
Toshihiro Shimizu 890ddd
		notLessThan(1, cont);
Toshihiro Shimizu 890ddd
		p2 = brig;
Toshihiro Shimizu 890ddd
		p1 = p2 - cont;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		for (i = 0; i <= p1; i++)
Toshihiro Shimizu 890ddd
			TransfFun[pencil << 8 | i] = 0;
Toshihiro Shimizu 890ddd
		for (; i < p2; i++)
Toshihiro Shimizu 890ddd
			TransfFun[pencil << 8 | i] = tmin(max, max * (i - p1) / cont);
Toshihiro Shimizu 890ddd
		for (; i < 256; i++)
Toshihiro Shimizu 890ddd
			TransfFun[pencil << 8 | i] = max;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	TransfFunction(const TargetColors &colors)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		memset(TransfFun, 0, sizeof TransfFun);
Toshihiro Shimizu 890ddd
		int count = tmin(colors.getColorCount(), MAX_N_PENCILS);
Toshihiro Shimizu 890ddd
		for (int p = 0; p < count; p++) {
Toshihiro Shimizu 890ddd
			int brightness = troundp(2.55 * colors.getColor(p).m_brightness);
Toshihiro Shimizu 890ddd
			int contrast = troundp(2.55 * colors.getColor(p).m_contrast);
Toshihiro Shimizu 890ddd
			setTransfFun(p, brightness, contrast);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	USHORT *getTransfFun() { return TransfFun; }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! Brightness/Contrast functions
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void brightnessContrast(const TRasterCM32P &cm, const TargetColors &colors)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TransfFunction transform(colors);
Toshihiro Shimizu 890ddd
	USHORT *transf_fun = transform.getTransfFun();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int ink, tone;
Toshihiro Shimizu 890ddd
	int newTone, newInk;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (int y = 0; y < cm->getLy(); ++y) {
Toshihiro Shimizu 890ddd
		TPixelCM32 *pix = cm->pixels(y);
Toshihiro Shimizu 890ddd
		TPixelCM32 *endPix = pix + cm->getLx();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		for (; pix < endPix; ++pix) {
Toshihiro Shimizu 890ddd
			tone = pix->getTone();
Toshihiro Shimizu 890ddd
			if (tone < 255) {
Toshihiro Shimizu 890ddd
				ink = pix->getInk();
Toshihiro Shimizu 890ddd
				newTone = transf_fun[ink << 8 | tone];
Toshihiro Shimizu 890ddd
				newInk = (newTone == 255) ? 0 : colors.getColor(ink).m_index;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				*pix = TPixelCM32(newInk, 0, newTone);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void brightnessContrastGR8(const TRasterCM32P &cm, const TargetColors &colors)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TransfFunction transform(colors);
Toshihiro Shimizu 890ddd
	USHORT *transf_fun = transform.getTransfFun();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int val, black = colors.getColor(1).m_index;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (int y = 0; y < cm->getLy(); ++y) {
Toshihiro Shimizu 890ddd
		TPixelCM32 *pix = cm->pixels(y);
Toshihiro Shimizu 890ddd
		TPixelCM32 *endPix = pix + cm->getLx();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		for (; pix < endPix; ++pix) {
Toshihiro Shimizu 890ddd
			val = transf_fun[pix->getValue() + 256];
Toshihiro Shimizu 890ddd
			*pix = (val < 255) ? TPixelCM32(black, 0, val) : TPixelCM32();
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! Transparency check
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void transparencyCheck(const TRasterCM32P &cmin, const TRaster32P &rasout)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	for (int y = 0; y < cmin->getLy(); ++y) {
Toshihiro Shimizu 890ddd
		TPixelCM32 *pix = cmin->pixels(y);
Toshihiro Shimizu 890ddd
		TPixelCM32 *endPix = pix + cmin->getLx();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TPixel32 *outPix = rasout->pixels(y);
Toshihiro Shimizu 890ddd
		for (; pix < endPix; ++pix, ++outPix) {
Toshihiro Shimizu 890ddd
			int ink = pix->getInk();
Toshihiro Shimizu 890ddd
			int tone = pix->getTone();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (ink == 4095)
Toshihiro Shimizu 890ddd
				*outPix = TPixel32::Green;
Toshihiro Shimizu 890ddd
			else
Toshihiro Shimizu 890ddd
				*outPix = (tone == 0) ? TPixel32::Black : (tone == 255) ? TPixel32::White : TPixel32::Red;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} //namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
//    TCleanupper implementation - elementary functions
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TCleanupper *TCleanupper::instance()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	static TCleanupper theCleanupper;
Toshihiro Shimizu 890ddd
	return &theCleanupper;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TCleanupper::setParameters(CleanupParameters *parameters)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_parameters = parameters;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TPalette *TCleanupper::createToonzPaletteFromCleanupPalette()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TPalette *cleanupPalette = m_parameters->m_cleanupPalette.getPointer();
Toshihiro Shimizu 890ddd
	return createToonzPalette(cleanupPalette, 1);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
//    CleanupProcessedImage implementation
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TToonzImageP CleanupPreprocessedImage::getImg() const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return (TToonzImageP)(TImageCache::instance()->get(m_imgId, true));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
CleanupPreprocessedImage::CleanupPreprocessedImage(
Toshihiro Shimizu 890ddd
	CleanupParameters *parameters,
Toshihiro Shimizu 890ddd
	TToonzImageP processed,
Toshihiro Shimizu 890ddd
	bool fromGr8)
Toshihiro Shimizu 890ddd
	: m_wasFromGR8(fromGr8), m_autocentered(false), m_size(processed->getSize())
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (!processed)
Toshihiro Shimizu 890ddd
		m_imgId = "";
Toshihiro Shimizu 890ddd
	else {
Toshihiro Shimizu 890ddd
		m_imgId = TImageCache::instance()->getUniqueId();
Toshihiro Shimizu 890ddd
		assert(!processed->getRaster()->getParent());
Toshihiro Shimizu 890ddd
		TImageCache::instance()->add(m_imgId, (TImageP)processed);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!m_wasFromGR8) {
Toshihiro Shimizu 890ddd
		const TPixel32 white(255, 255, 255, 0);
Toshihiro Shimizu 890ddd
		for (int i = 0; i < parameters->m_colors.getColorCount(); ++i) {
Toshihiro Shimizu 890ddd
			TPixel32 cc = parameters->m_colors.getColor(i).m_color;
Toshihiro Shimizu 890ddd
			for (int tone = 0; tone < 256; tone++) {
Toshihiro Shimizu 890ddd
				m_pixelsLut.push_back(
Toshihiro Shimizu 890ddd
					blend(parameters->m_colors.getColor(i).m_color,
Toshihiro Shimizu 890ddd
						  white,
Toshihiro Shimizu 890ddd
						  tone,
Toshihiro Shimizu 890ddd
						  TPixelCM32::getMaxTone()));
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
CleanupPreprocessedImage::~CleanupPreprocessedImage()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TImageCache::instance()->remove(m_imgId);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TRasterImageP CleanupPreprocessedImage::getPreviewImage() const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TRaster32P ras(getSize());
Toshihiro Shimizu 890ddd
	TRasterImageP ri(ras);
Toshihiro Shimizu 890ddd
	double xdpi = 0, ydpi = 0;
Toshihiro Shimizu 890ddd
	getImg()->getDpi(xdpi, ydpi);
Toshihiro Shimizu 890ddd
	ri->setDpi(xdpi, ydpi);
Toshihiro Shimizu 890ddd
	return ri;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
//    TCleanupper implementation  -  Process functions
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool TCleanupper::getResampleValues(const TRasterImageP &image, TAffine &aff, double &blur,
Toshihiro Shimizu 890ddd
									TDimension &outDim, TPointD &outDpi, bool isCameraTest, bool &isSameDpi)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	double outlp, outlq;
Toshihiro Shimizu 890ddd
	double scalex, scaley;
Toshihiro Shimizu 890ddd
	double cxin, cyin, cpout, cqout;
Toshihiro Shimizu 890ddd
	double max_blur;
Toshihiro Shimizu 890ddd
	TPointD dpi;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Locking the input image to be cleanupped
Toshihiro Shimizu 890ddd
	image->getRaster()->lock();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Retrieve image infos
Toshihiro Shimizu 890ddd
	int rasterLx = image->getRaster()->getLx();
Toshihiro Shimizu 890ddd
	int rasterLy = image->getRaster()->getLy();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	/*---入力画像サイズとSaveBoxのサイズが一致しているか?の判定---*/
Toshihiro Shimizu 890ddd
	TRect saveBox = image->getSavebox();
Toshihiro Shimizu 890ddd
	bool raster_is_savebox = true;
Toshihiro Shimizu 890ddd
	if (saveBox == TRect() && (saveBox.getLx() > 0 && saveBox.getLx() < rasterLx ||
Toshihiro Shimizu 890ddd
							   saveBox.getLy() > 0 && saveBox.getLy() < rasterLy))
Toshihiro Shimizu 890ddd
		raster_is_savebox = false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	image->getDpi(dpi.x, dpi.y);
Toshihiro Shimizu 890ddd
	if (dpi == TPointD()) {
Toshihiro Shimizu 890ddd
		dpi = getCustomDpi();
Toshihiro Shimizu 890ddd
		if (dpi == TPointD())
Toshihiro Shimizu 890ddd
			dpi.x = dpi.y = 65.0; //using 65.0 as default DPI
Toshihiro Shimizu 890ddd
	} else if (!dpi.x)
Toshihiro Shimizu 890ddd
		dpi.x = dpi.y;
Toshihiro Shimizu 890ddd
	else if (!dpi.y)
Toshihiro Shimizu 890ddd
		dpi.y = dpi.x;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Retrieve some cleanup parameters
Toshihiro Shimizu 890ddd
	int rotate = m_parameters->m_rotate;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Build scaling/dpi data
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		m_parameters->getOutputImageInfo(outDim, outDpi.x, outDpi.y);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// input -> output scale factor
Toshihiro Shimizu 890ddd
		scalex = outDpi.x / dpi.x;
Toshihiro Shimizu 890ddd
		scaley = outDpi.y / dpi.y;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		outlp = outDim.lx;
Toshihiro Shimizu 890ddd
		outlq = outDim.ly;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	/*--- 拡大/縮小をしていない場合(DPIが変わらない場合)、NearestNeighborでリサンプリングする。---*/
Toshihiro Shimizu 890ddd
	isSameDpi = areAlmostEqual(outDpi.x, dpi.x, 0.1) && areAlmostEqual(outDpi.y, dpi.y, 0.1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Retrieve input center
Toshihiro Shimizu 890ddd
	if (raster_is_savebox) {
Toshihiro Shimizu 890ddd
		cxin = -saveBox.getP00().x + (saveBox.getLx() - 1) / 2.0;
Toshihiro Shimizu 890ddd
		cyin = -saveBox.getP00().y + (saveBox.getLy() - 1) / 2.0;
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		cxin = (rasterLx - 1) / 2.0;
Toshihiro Shimizu 890ddd
		cyin = (rasterLy - 1) / 2.0;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Retrieve output center
Toshihiro Shimizu 890ddd
	cpout = (outlp - 1) / 2.0;
Toshihiro Shimizu 890ddd
	cqout = (outlq - 1) / 2.0;
Toshihiro Shimizu 890ddd
	// Perform autocenter if any is found
Toshihiro Shimizu 890ddd
	double angle = 0.0;
Toshihiro Shimizu 890ddd
	double skew = 0.0;
Toshihiro Shimizu 890ddd
	TAffine pre_aff;
Toshihiro Shimizu 890ddd
	image->getRaster()->lock();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool autocentered =
Toshihiro Shimizu 890ddd
		doAutocenter(
Toshihiro Shimizu 890ddd
			angle, skew,
Toshihiro Shimizu 890ddd
			cxin, cyin, cqout, cpout,
Toshihiro Shimizu 890ddd
			dpi.x, dpi.y,
Toshihiro Shimizu 890ddd
			raster_is_savebox, saveBox,
Toshihiro Shimizu 890ddd
			image, scalex);
Toshihiro Shimizu 890ddd
	image->getRaster()->unlock();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Build the image transform as deduced by the autocenter
Toshihiro Shimizu 890ddd
	if (m_parameters->m_autocenterType == AUTOCENTER_CTR && skew) {
Toshihiro Shimizu 890ddd
		pre_aff.a11 = cos(skew * TConsts::pi_180);
Toshihiro Shimizu 890ddd
		pre_aff.a21 = sin(skew * TConsts::pi_180);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	aff = (TScale(scalex, scaley) * pre_aff) * TRotation(angle);
Toshihiro Shimizu 890ddd
	aff = aff.place(cxin, cyin, cpout, cqout);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Apply eventual additional user-defined transforms
Toshihiro Shimizu 890ddd
	TPointD pout = TPointD((outlp - 1) / 2.0, (outlq - 1) / 2.0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_parameters->m_rotate != 0)
Toshihiro Shimizu 890ddd
		aff = TRotation(-(double)m_parameters->m_rotate).place(pout, pout) * aff;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_parameters->m_flipx || m_parameters->m_flipy)
Toshihiro Shimizu 890ddd
		aff = TScale(m_parameters->m_flipx ? -1 : 1, m_parameters->m_flipy ? -1 : 1).place(pout, pout) * aff;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!isCameraTest)
Toshihiro Shimizu 890ddd
		aff = TTranslation(m_parameters->m_offx * outDpi.x / 2, m_parameters->m_offy * outDpi.y / 2) * aff;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	max_blur = 20.0 * sqrt(fabs(scalex /*** * oversample_factor ***/));
Toshihiro Shimizu 890ddd
	blur = pow(max_blur, (100 - m_parameters->m_sharpness) / (100 - 1));
Toshihiro Shimizu 890ddd
	return autocentered;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//this one incorporate the preprocessColors and the finalize function; used for swatch.(tipically on very small rasters)
Toshihiro Shimizu 890ddd
TRasterP TCleanupper::processColors(const TRasterP &rin)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (m_parameters->m_lineProcessingMode == lpNone)
Toshihiro Shimizu 890ddd
		return rin;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TRasterCM32P rcm = TRasterCM32P(rin->getSize());
Toshihiro Shimizu 890ddd
	if (!rcm) {
Toshihiro Shimizu 890ddd
		assert(!"failed finalRas allocation!");
Toshihiro Shimizu 890ddd
		return TRasterCM32P();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Copy current cleanup palette to parameters' colors
Toshihiro Shimizu 890ddd
	m_parameters->m_colors.update(m_parameters->m_cleanupPalette.getPointer(), m_parameters->m_noAntialias);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool toGr8 = (m_parameters->m_lineProcessingMode == lpGrey);
Toshihiro Shimizu 890ddd
	if (toGr8) {
Toshihiro Shimizu 890ddd
		//No (color) processing. Not even thresholding. This just means that all the important
Toshihiro Shimizu 890ddd
		//stuff here is made in the brightness/contrast stage...
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//NOTE: Most of the color processing should be DISABLED in this case!!
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//finalRas->clear();
Toshihiro Shimizu 890ddd
		rin->lock();
Toshihiro Shimizu 890ddd
		rcm->lock();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (TRasterGR8P(rin)) {
Toshihiro Shimizu 890ddd
			UCHAR *rowin = rin->getRawData();
Toshihiro Shimizu 890ddd
			TUINT32 *rowout = reinterpret_cast<tuint32 *="">(rcm->getRawData());</tuint32>
Toshihiro Shimizu 890ddd
			for (int i = 0; i < rin->getLy(); i++) {
Toshihiro Shimizu 890ddd
				for (int j = 0; j < rin->getLx(); j++)
Toshihiro Shimizu 890ddd
					*rowout++ = *rowin++; //Direct copy for now... :(
Toshihiro Shimizu 890ddd
				rowin += rin->getWrap() - rin->getLx();
Toshihiro Shimizu 890ddd
				rowout += rcm->getWrap() - rcm->getLx();
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			TPixel32 *rowin = reinterpret_cast<tpixel32 *="">(rin->getRawData());</tpixel32>
Toshihiro Shimizu 890ddd
			TUINT32 *rowout = reinterpret_cast<tuint32 *="">(rcm->getRawData());</tuint32>
Toshihiro Shimizu 890ddd
			for (int i = 0; i < rin->getLy(); i++) {
Toshihiro Shimizu 890ddd
				for (int j = 0; j < rin->getLx(); j++)
Toshihiro Shimizu 890ddd
					*rowout++ = TPixelGR8::from(*rowin++).value;
Toshihiro Shimizu 890ddd
				rowin += rin->getWrap() - rin->getLx();
Toshihiro Shimizu 890ddd
				rowout += rcm->getWrap() - rcm->getLx();
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		rin->unlock();
Toshihiro Shimizu 890ddd
		rcm->unlock();
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		assert(TRaster32P(rin));
Toshihiro Shimizu 890ddd
		preprocessColors(rcm, rin, m_parameters->m_colors);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//outImg->setDpi(outDpi.x, outDpi.y);
Toshihiro Shimizu 890ddd
	CleanupPreprocessedImage cpi(m_parameters, TToonzImageP(rcm, rcm->getBounds()), toGr8);
Toshihiro Shimizu 890ddd
	cpi.m_autocentered = true;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TRaster32P rout = TRaster32P(rin->getSize());
Toshihiro Shimizu 890ddd
	finalize(rout, &cpi);
Toshihiro Shimizu 890ddd
	return rout;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
CleanupPreprocessedImage *TCleanupper::process(
Toshihiro Shimizu 890ddd
	TRasterImageP &image, bool first_image, TRasterImageP &onlyResampledImage,
Toshihiro Shimizu 890ddd
	bool isCameraTest, bool returnResampled, bool onlyForSwatch, TAffine *resampleAff)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TAffine aff;
Toshihiro Shimizu 890ddd
	double blur;
Toshihiro Shimizu 890ddd
	TDimension outDim(0, 0);
Toshihiro Shimizu 890ddd
	TPointD outDpi;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool isSameDpi = false;
Toshihiro Shimizu 890ddd
	bool autocentered = getResampleValues(image, aff, blur, outDim, outDpi, isCameraTest, isSameDpi);
Toshihiro Shimizu 890ddd
	if (m_parameters->m_autocenterType != AUTOCENTER_NONE && !autocentered)
Toshihiro Shimizu 890ddd
		DVGui::MsgBox(DVGui::WARNING, QObject::tr("The autocentering failed on the current drawing."));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool fromGr8 = (bool)TRasterGR8P(image->getRaster());
Toshihiro Shimizu 890ddd
	bool toGr8 = (m_parameters->m_lineProcessingMode == lpGrey);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// If necessary, perform auto-adjust
Toshihiro Shimizu 890ddd
	if (!isCameraTest && m_parameters->m_lineProcessingMode != lpNone && toGr8 && m_parameters->m_autoAdjustMode != AUTO_ADJ_NONE &&
Toshihiro Shimizu 890ddd
		!onlyForSwatch) {
Toshihiro Shimizu 890ddd
		static int ref_cum[256];
Toshihiro Shimizu 890ddd
		UCHAR lut[256];
Toshihiro Shimizu 890ddd
		int cum[256];
Toshihiro Shimizu 890ddd
		double x0_src_f, y0_src_f, x1_src_f, y1_src_f;
Toshihiro Shimizu 890ddd
		int x0_src, y0_src, x1_src, y1_src;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//cleanup_message("Autoadjusting... \n");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TAffine inv = aff.inv();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		x0_src_f = affMV1(inv, 0, 0);
Toshihiro Shimizu 890ddd
		y0_src_f = affMV2(inv, 0, 0);
Toshihiro Shimizu 890ddd
		x1_src_f = affMV1(inv, outDim.lx - 1, outDim.ly - 1);
Toshihiro Shimizu 890ddd
		y1_src_f = affMV2(inv, outDim.lx - 1, outDim.ly - 1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		x0_src = tround(x0_src_f);
Toshihiro Shimizu 890ddd
		y0_src = tround(y0_src_f);
Toshihiro Shimizu 890ddd
		x1_src = tround(x1_src_f);
Toshihiro Shimizu 890ddd
		y1_src = tround(y1_src_f);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		set_autoadjust_window(x0_src, y0_src, x1_src, y1_src);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (!TRasterGR8P(image->getRaster())) {
Toshihiro Shimizu 890ddd
			//Auto-adjusting a 32-bit image. This means that a white background must be introduced first.
Toshihiro Shimizu 890ddd
			TRaster32P ras32(image->getRaster()->clone());
Toshihiro Shimizu 890ddd
			TRop::addBackground(ras32, TPixel32::White);
Toshihiro Shimizu 890ddd
			image = TRasterImageP(ras32); //old image is released here
Toshihiro Shimizu 890ddd
			ras32 = TRaster32P();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			TRasterGR8P rgr(image->getRaster()->getSize());
Toshihiro Shimizu 890ddd
			TRop::copy(rgr, image->getRaster());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			//This is now legit. It was NOT before the clone, since the original could be cached.
Toshihiro Shimizu 890ddd
			image->setRaster(rgr);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		switch (m_parameters->m_autoAdjustMode) {
Toshihiro Shimizu 890ddd
		case AUTO_ADJ_HISTOGRAM: {
Toshihiro Shimizu 890ddd
			if (first_image) {
Toshihiro Shimizu 890ddd
				build_gr_cum(image, ref_cum);
Toshihiro Shimizu 890ddd
			} else {
Toshihiro Shimizu 890ddd
				build_gr_cum(image, cum);
Toshihiro Shimizu 890ddd
				build_gr_lut(ref_cum, cum, lut);
Toshihiro Shimizu 890ddd
				apply_lut(image, lut);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			CASE AUTO_ADJ_HISTO_L : histo_l_algo(image, first_image);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			CASE AUTO_ADJ_BLACK_EQ : black_eq_algo(image);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			CASE AUTO_ADJ_NONE : DEFAULT : assert(false);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	fromGr8 = (bool)TRasterGR8P(image->getRaster()); //may have changed type due to auto-adjust
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	assert(returnResampled || !onlyForSwatch); //if onlyForSwatch, then returnResampled
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Allocate output colormap raster
Toshihiro Shimizu 890ddd
	TRasterCM32P finalRas;
Toshihiro Shimizu 890ddd
	if (!onlyForSwatch) {
Toshihiro Shimizu 890ddd
		finalRas = TRasterCM32P(outDim);
Toshihiro Shimizu 890ddd
		if (!finalRas) {
Toshihiro Shimizu 890ddd
			TImageCache::instance()->outputMap(outDim.lx * outDim.ly * 4, "C:\\cachelog");
Toshihiro Shimizu 890ddd
			assert(!"failed finalRas allocation!");
Toshihiro Shimizu 890ddd
			return 0;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// In case the input raster was a greymap, we cannot reutilize finalRas's buffer to transform the final
Toshihiro Shimizu 890ddd
	// fullcolor pixels to colormap pixels directly (1 32-bit pixel would hold 4 8-bit pixels) - therefore,
Toshihiro Shimizu 890ddd
	// a secondary greymap is allocated.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//NOTE: This should be considered obsolete? By using TRop::resample( <traster32p& instance=""> , ...) we</traster32p&>
Toshihiro Shimizu 890ddd
	//should get the same effect!!
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TRasterP tmp_ras;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (returnResampled || (fromGr8 && toGr8)) {
Toshihiro Shimizu 890ddd
		if (fromGr8 && toGr8)
Toshihiro Shimizu 890ddd
			tmp_ras = TRasterGR8P(outDim);
Toshihiro Shimizu 890ddd
		else
Toshihiro Shimizu 890ddd
			tmp_ras = TRaster32P(outDim);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (!tmp_ras) {
Toshihiro Shimizu 890ddd
			TImageCache::instance()->outputMap(outDim.lx * outDim.ly * 4, "C:\\cachelog");
Toshihiro Shimizu 890ddd
			assert(!"failed tmp_ras allocation!");
Toshihiro Shimizu 890ddd
			return 0;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	} else
Toshihiro Shimizu 890ddd
		//if finalRas is allocated, and the intermediate raster has to be 32-bit, we can perform pixel
Toshihiro Shimizu 890ddd
		//conversion directly on the same output buffer
Toshihiro Shimizu 890ddd
		tmp_ras = TRaster32P(outDim.lx, outDim.ly, outDim.lx, (TPixel32 *)finalRas->getRawData());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TRop::ResampleFilterType flt_type;
Toshihiro Shimizu 890ddd
	if (isSameDpi)
Toshihiro Shimizu 890ddd
		flt_type = TRop::ClosestPixel; //NearestNeighbor
Toshihiro Shimizu 890ddd
	else if (isCameraTest)
Toshihiro Shimizu 890ddd
		flt_type = TRop::Triangle;
Toshihiro Shimizu 890ddd
	else
Toshihiro Shimizu 890ddd
		flt_type = TRop::Hann2;
Toshihiro Shimizu 890ddd
	TRop::resample(tmp_ras, image->getRaster(), aff, flt_type, blur);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if ((TRaster32P)tmp_ras)
Toshihiro Shimizu 890ddd
		//Add white background to deal with semitransparent pixels
Toshihiro Shimizu 890ddd
		TRop::addBackground(tmp_ras, TPixel32::White);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (resampleAff)
Toshihiro Shimizu 890ddd
		*resampleAff = aff;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	image->getRaster()->unlock();
Toshihiro Shimizu 890ddd
	image = TRasterImageP();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (returnResampled) {
Toshihiro Shimizu 890ddd
		onlyResampledImage = TRasterImageP(tmp_ras);
Toshihiro Shimizu 890ddd
		onlyResampledImage->setDpi(outDpi.x, outDpi.y);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (onlyForSwatch)
Toshihiro Shimizu 890ddd
		return 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	assert(finalRas);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Copy current cleanup palette to parameters' colors
Toshihiro Shimizu 890ddd
	m_parameters->m_colors.update(m_parameters->m_cleanupPalette.getPointer(), m_parameters->m_noAntialias);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (toGr8) {
Toshihiro Shimizu 890ddd
		//No (color) processing. Not even thresholding. This just means that all the important
Toshihiro Shimizu 890ddd
		//stuff here is made in the brightness/contrast stage...
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//NOTE: Most of the color processing should be DISABLED in this case!!
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		tmp_ras->lock();
Toshihiro Shimizu 890ddd
		finalRas->lock();
Toshihiro Shimizu 890ddd
		assert(tmp_ras->getSize() == finalRas->getSize());
Toshihiro Shimizu 890ddd
		assert(tmp_ras->getLx() == tmp_ras->getWrap());
Toshihiro Shimizu 890ddd
		assert(finalRas->getLx() == finalRas->getWrap());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int pixCount = outDim.lx * outDim.ly;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (fromGr8) {
Toshihiro Shimizu 890ddd
			UCHAR *rowin = tmp_ras->getRawData();
Toshihiro Shimizu 890ddd
			TUINT32 *rowout = reinterpret_cast<tuint32 *="">(finalRas->getRawData());</tuint32>
Toshihiro Shimizu 890ddd
			for (int i = 0; i < pixCount; i++)
Toshihiro Shimizu 890ddd
				*rowout++ = *rowin++; //Direct copy for now... :(
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			TPixel32 *rowin = reinterpret_cast<tpixel32 *="">(tmp_ras->getRawData());</tpixel32>
Toshihiro Shimizu 890ddd
			TUINT32 *rowout = reinterpret_cast<tuint32 *="">(finalRas->getRawData());</tuint32>
Toshihiro Shimizu 890ddd
			for (int i = 0; i < pixCount; i++)
Toshihiro Shimizu 890ddd
				*rowout++ = TPixelGR8::from(*rowin++).value;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		tmp_ras->unlock();
Toshihiro Shimizu 890ddd
		finalRas->unlock();
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		//WARNING: finalRas and tmp_ras may share the SAME buffer!
Toshihiro Shimizu 890ddd
		assert(TRaster32P(tmp_ras));
Toshihiro Shimizu 890ddd
		preprocessColors(finalRas, tmp_ras, m_parameters->m_colors);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TToonzImageP final;
Toshihiro Shimizu 890ddd
	final = TToonzImageP(finalRas, finalRas->getBounds());
Toshihiro Shimizu 890ddd
	final->setDpi(outDpi.x, outDpi.y);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	CleanupPreprocessedImage *cpi = new CleanupPreprocessedImage(m_parameters, final, toGr8);
Toshihiro Shimizu 890ddd
	cpi->m_autocentered = autocentered;
Toshihiro Shimizu 890ddd
	cpi->m_appliedAff = aff;
Toshihiro Shimizu 890ddd
	return cpi;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TRasterImageP TCleanupper::autocenterOnly(
Toshihiro Shimizu 890ddd
	const TRasterImageP &image, bool isCameraTest, bool &autocentered)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	double xDpi, yDpi;
Toshihiro Shimizu 890ddd
	//double inlx, inly, zoom_factor, max_blur;
Toshihiro Shimizu 890ddd
	double skew = 0, angle = 0, dist = 0 /*lq_nozoom, lp_nozoom,, cx, cy, scalex, scaley*/;
Toshihiro Shimizu 890ddd
	double cxin, cyin, cpout, cqout;
Toshihiro Shimizu 890ddd
	int rasterIsSavebox = true;
Toshihiro Shimizu 890ddd
	TAffine aff, preAff, inv;
Toshihiro Shimizu 890ddd
	int rasterLx, finalLx, rasterLy, finalLy;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	rasterLx = finalLx = image->getRaster()->getLx();
Toshihiro Shimizu 890ddd
	rasterLy = finalLy = image->getRaster()->getLy();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TRect saveBox = image->getSavebox();
Toshihiro Shimizu 890ddd
	if ((saveBox == TRect()) && ((saveBox.getLx() > 0 && saveBox.getLx() < rasterLx) ||
Toshihiro Shimizu 890ddd
								 (saveBox.getLy() > 0 && saveBox.getLy() < rasterLy)))
Toshihiro Shimizu 890ddd
		rasterIsSavebox = false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int rotate = m_parameters->m_rotate;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	image->getDpi(xDpi, yDpi);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!xDpi) //using 65.0 as default DPI
Toshihiro Shimizu 890ddd
		xDpi = (yDpi ? yDpi : 65);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!yDpi)
Toshihiro Shimizu 890ddd
		yDpi = (xDpi ? xDpi : 65);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (rasterIsSavebox) {
Toshihiro Shimizu 890ddd
		cxin = -saveBox.getP00().x + (saveBox.getLx() - 1) / 2.0;
Toshihiro Shimizu 890ddd
		cyin = -saveBox.getP00().y + (saveBox.getLy() - 1) / 2.0;
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		cxin = (rasterLx - 1) / 2.0;
Toshihiro Shimizu 890ddd
		cyin = (rasterLy - 1) / 2.0;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	cpout = (rasterLx - 1) / 2.0;
Toshihiro Shimizu 890ddd
	cqout = (rasterLy - 1) / 2.0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_parameters->m_autocenterType != AUTOCENTER_NONE)
Toshihiro Shimizu 890ddd
		autocentered = doAutocenter(angle, skew, cxin, cyin, cqout, cpout,
Toshihiro Shimizu 890ddd
									xDpi, yDpi, rasterIsSavebox, saveBox, image, 1.0);
Toshihiro Shimizu 890ddd
	else
Toshihiro Shimizu 890ddd
		autocentered = true;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_parameters->m_autocenterType == AUTOCENTER_CTR && skew) {
Toshihiro Shimizu 890ddd
		aff.a11 = cos(skew * TConsts::pi_180);
Toshihiro Shimizu 890ddd
		aff.a21 = sin(skew * TConsts::pi_180);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	aff = aff * TRotation(angle);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	aff = aff.place(cxin, cyin, cpout, cqout);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (rotate != 0 && rotate != 180)
Toshihiro Shimizu 890ddd
		tswap(finalLx, finalLy);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TPointD pin = TPointD((rasterLx - 1) / 2.0, (rasterLy - 1) / 2.0);
Toshihiro Shimizu 890ddd
	TPointD pout = TPointD((finalLx - 1) / 2.0, (finalLy - 1) / 2.0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (rotate != 0)
Toshihiro Shimizu 890ddd
		aff = TRotation(-(double)rotate).place(pin, pout) * aff;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_parameters->m_flipx || m_parameters->m_flipy)
Toshihiro Shimizu 890ddd
		aff = TScale(m_parameters->m_flipx ? -1 : 1, m_parameters->m_flipy ? -1 : 1).place(pout, pout) * aff;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!isCameraTest)
Toshihiro Shimizu 890ddd
		aff = TTranslation(m_parameters->m_offx * xDpi / 2,
Toshihiro Shimizu 890ddd
						   m_parameters->m_offy * yDpi / 2) *
Toshihiro Shimizu 890ddd
			  aff;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TRasterP tmpRas;
Toshihiro Shimizu 890ddd
	TPoint dp;
Toshihiro Shimizu 890ddd
	if (isCameraTest) //in cameratest, I don't want to crop the image to be shown.
Toshihiro Shimizu 890ddd
					  // so, I resample without cropping, and I compute the offset needed to have it autocentered.
Toshihiro Shimizu 890ddd
					  // That offset is stored in the RasterImage(setOffset below) and then used when displaying the image in camerastand (in method RasterPainter::onRasterImage)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		//TPointD srcActualCenter = aff.inv()*TPointD(finalLx/2.0, finalLy/2.0);// the autocenter position in the source image
Toshihiro Shimizu 890ddd
		//TPointD srcCenter = imageToResample->getRaster()->getCenterD();*/
Toshihiro Shimizu 890ddd
		TPointD dstActualCenter = TPointD(finalLx / 2.0, finalLy / 2.0);
Toshihiro Shimizu 890ddd
		TPointD dstCenter = aff * image->getRaster()->getCenterD();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		dp = convert(dstCenter - dstActualCenter); //the amount to be offset in the destination image.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TRect r = convert(aff * convert(image->getRaster()->getBounds()));
Toshihiro Shimizu 890ddd
		aff = (TTranslation(convert(-r.getP00())) * aff);
Toshihiro Shimizu 890ddd
		//aff = aff.place(srcActualCenter, dstActualCenter);
Toshihiro Shimizu 890ddd
		tmpRas = image->getRaster()->create(r.getLx(), r.getLy());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	} else
Toshihiro Shimizu 890ddd
		tmpRas = image->getRaster()->create(finalLx, finalLy);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TRop::resample(tmpRas, image->getRaster(), aff);
Toshihiro Shimizu 890ddd
	//TImageWriter::save(TFilePath("C:\\temp\\incleanup.tif"), imageToResample);
Toshihiro Shimizu 890ddd
	//TImageWriter::save(TFilePath("C:\\temp\\outcleanup.tif"), tmp_ras);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TRasterImageP final(tmpRas);
Toshihiro Shimizu 890ddd
	final->setOffset(dp);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	final->setDpi(xDpi, yDpi);
Toshihiro Shimizu 890ddd
	//final->sethPos(finalHPos);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return final;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
//    AutoCenter
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool TCleanupper::doAutocenter(
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double &angle, double &skew,
Toshihiro Shimizu 890ddd
	double &cxin, double &cyin,
Toshihiro Shimizu 890ddd
	double &cqout, double &cpout,
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const double xdpi, const double ydpi,
Toshihiro Shimizu 890ddd
	const int raster_is_savebox,
Toshihiro Shimizu 890ddd
	const TRect saveBox,
Toshihiro Shimizu 890ddd
	const TRasterImageP &image,
Toshihiro Shimizu 890ddd
	const double scalex)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	double sigma = 0, theta = 0;
Toshihiro Shimizu 890ddd
	FDG_INFO fdg_info = m_parameters->getFdgInfo();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	switch (m_parameters->m_autocenterType) {
Toshihiro Shimizu 890ddd
	case AUTOCENTER_CTR:
Toshihiro Shimizu 890ddd
		angle = fdg_info.ctr_angle;
Toshihiro Shimizu 890ddd
		skew = fdg_info.ctr_skew;
Toshihiro Shimizu 890ddd
		cxin = mmToPixel(fdg_info.ctr_x, xdpi);
Toshihiro Shimizu 890ddd
		cyin = mmToPixel(fdg_info.ctr_y, ydpi);
Toshihiro Shimizu 890ddd
		if (raster_is_savebox) {
Toshihiro Shimizu 890ddd
			cxin -= saveBox.getP00().x;
Toshihiro Shimizu 890ddd
			cyin -= saveBox.getP00().y;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		break;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	case AUTOCENTER_FDG: {
Toshihiro Shimizu 890ddd
		// e se image->raster_is_savebox?
Toshihiro Shimizu 890ddd
		//cleanup_message ("Autocentering...");
Toshihiro Shimizu 890ddd
		int strip_width = compute_strip_pixel(&fdg_info, xdpi) + 1; /* ?!? */
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		switch (m_parameters->m_pegSide) {
Toshihiro Shimizu 890ddd
		case PEGS_BOTTOM:
Toshihiro Shimizu 890ddd
			sigma = 0.0;
Toshihiro Shimizu 890ddd
			CASE PEGS_RIGHT : sigma = 90.0;
Toshihiro Shimizu 890ddd
			CASE PEGS_TOP : sigma = 180.0;
Toshihiro Shimizu 890ddd
			CASE PEGS_LEFT : sigma = -90.0;
Toshihiro Shimizu 890ddd
		DEFAULT:
Toshihiro Shimizu 890ddd
			sigma = 0.0;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		theta = sigma;
Toshihiro Shimizu 890ddd
		if (theta > 180.0)
Toshihiro Shimizu 890ddd
			theta -= 360.0;
Toshihiro Shimizu 890ddd
		else if (theta <= -180.0)
Toshihiro Shimizu 890ddd
			theta += 360.0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		PEGS_SIDE pegs_ras_side;
Toshihiro Shimizu 890ddd
		if (theta == 0.0)
Toshihiro Shimizu 890ddd
			pegs_ras_side = PEGS_BOTTOM;
Toshihiro Shimizu 890ddd
		else if (theta == 90.0)
Toshihiro Shimizu 890ddd
			pegs_ras_side = PEGS_RIGHT;
Toshihiro Shimizu 890ddd
		else if (theta == 180.0)
Toshihiro Shimizu 890ddd
			pegs_ras_side = PEGS_TOP;
Toshihiro Shimizu 890ddd
		else if (theta == -90.0)
Toshihiro Shimizu 890ddd
			pegs_ras_side = PEGS_LEFT;
Toshihiro Shimizu 890ddd
		else
Toshihiro Shimizu 890ddd
			pegs_ras_side = PEGS_BOTTOM;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		switch (pegs_ras_side) {
Toshihiro Shimizu 890ddd
		case PEGS_LEFT:
Toshihiro Shimizu 890ddd
			__OR PEGS_RIGHT : notMoreThan(image->getRaster()->getLx(), strip_width);
Toshihiro Shimizu 890ddd
		DEFAULT:
Toshihiro Shimizu 890ddd
			notMoreThan(image->getRaster()->getLy(), strip_width);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		convert_dots_mm_to_pixel(
Toshihiro Shimizu 890ddd
			&fdg_info.dots[0],
Toshihiro Shimizu 890ddd
			fdg_info.dots.size(),
Toshihiro Shimizu 890ddd
			xdpi, ydpi);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		double cx, cy;
Toshihiro Shimizu 890ddd
		if (!get_image_rotation_and_center(
Toshihiro Shimizu 890ddd
				image->getRaster(), strip_width, pegs_ras_side,
Toshihiro Shimizu 890ddd
				&angle, &cx, &cy, &fdg_info.dots[0], fdg_info.dots.size())) {
Toshihiro Shimizu 890ddd
			return false;
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			angle *= TConsts::invOf_pi_180;
Toshihiro Shimizu 890ddd
			cxin = cx;
Toshihiro Shimizu 890ddd
			cyin = cy;
Toshihiro Shimizu 890ddd
			double dist = (double)mmToPixel(fdg_info.dist_ctr_to_ctr_hole, xdpi * scalex);
Toshihiro Shimizu 890ddd
			switch (m_parameters->m_pegSide) {
Toshihiro Shimizu 890ddd
			case PEGS_BOTTOM:
Toshihiro Shimizu 890ddd
				cqout -= dist;
Toshihiro Shimizu 890ddd
				CASE PEGS_TOP : cqout += dist;
Toshihiro Shimizu 890ddd
				CASE PEGS_LEFT : cpout -= dist;
Toshihiro Shimizu 890ddd
				CASE PEGS_RIGHT : cpout += dist;
Toshihiro Shimizu 890ddd
			DEFAULT : {
Toshihiro Shimizu 890ddd
				// bad pegs side
Toshihiro Shimizu 890ddd
				return false;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		fdg_info.dots.clear();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	break;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	default:
Toshihiro Shimizu 890ddd
		return false;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
//    (Pre) Processing  (ie the core Cleanup procedure)
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline void preprocessColor(const TPixel32 &pix, const TargetColorData &blackColor,
Toshihiro Shimizu 890ddd
							const std::vector<targetcolordata> &featureColors, int nFeatures,</targetcolordata>
Toshihiro Shimizu 890ddd
							TPixelCM32 &outpix)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//Translate the pixel to HSV
Toshihiro Shimizu 890ddd
	HSVColor pixHSV(HSVColor::fromRGB(pix.r / 255.0, pix.g / 255.0, pix.b / 255.0));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//First, check against matchline colors. This is needed as outline pixels' tone is based upon that
Toshihiro Shimizu 890ddd
	//extracted here.
Toshihiro Shimizu 890ddd
	int idx = -1, tone = 255;
Toshihiro Shimizu 890ddd
	double hDist = (std::numeric_limits<double>::max)(), newHDist;</double>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (int i = 0; i < nFeatures; ++i) {
Toshihiro Shimizu 890ddd
		const TargetColorData &fColor = featureColors[i];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Feature Color
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Retrieve the hue distance and, in case it's less than current one, this idx better
Toshihiro Shimizu 890ddd
		//approximates the color.
Toshihiro Shimizu 890ddd
		newHDist = (pixHSV.m_h > fColor.m_hsv.m_h) ? tmin(pixHSV.m_h - fColor.m_hsv.m_h, fColor.m_hsv.m_h - pixHSV.m_h + 360.0) : tmin(fColor.m_hsv.m_h - pixHSV.m_h, pixHSV.m_h - fColor.m_hsv.m_h + 360.0);
Toshihiro Shimizu 890ddd
		if (newHDist < hDist) {
Toshihiro Shimizu 890ddd
			hDist = newHDist;
Toshihiro Shimizu 890ddd
			idx = i;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (idx >= 0) {
Toshihiro Shimizu 890ddd
		const TargetColorData &fColor = featureColors[idx];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//First, perform saturation check
Toshihiro Shimizu 890ddd
		bool saturationOk = (pixHSV.m_s > fColor.m_saturationLower) &&
Toshihiro Shimizu 890ddd
							((fColor.m_hueLower <= fColor.m_hueUpper) ? (pixHSV.m_h >= fColor.m_hueLower) && (pixHSV.m_h <= fColor.m_hueUpper) : (pixHSV.m_h >= fColor.m_hueLower) || (pixHSV.m_h <= fColor.m_hueUpper));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (saturationOk) {
Toshihiro Shimizu 890ddd
			tone = 255.0 * (1.0 - pixHSV.m_s) / (1.0 - fColor.m_saturationLower);
Toshihiro Shimizu 890ddd
			idx = fColor.m_idx;
Toshihiro Shimizu 890ddd
		} else
Toshihiro Shimizu 890ddd
			idx = -1;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Check against outline color
Toshihiro Shimizu 890ddd
	if (pixHSV.m_v < blackColor.m_hsv.m_v) {
Toshihiro Shimizu 890ddd
		//Outline-sensitive tone is imposed when the value check passes
Toshihiro Shimizu 890ddd
		tone = (tone * pixHSV.m_v / blackColor.m_hsv.m_v);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//A further Chroma test is applied to decide whether a would-be outline color
Toshihiro Shimizu 890ddd
		//is to be intended as a matchline color instead (it has too much color)
Toshihiro Shimizu 890ddd
		if ((idx < 0) || (pixHSV.m_s * pixHSV.m_v) < blackColor.m_saturationLower)
Toshihiro Shimizu 890ddd
			//Outline Color
Toshihiro Shimizu 890ddd
			idx = 1;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	outpix = (idx > 0 && tone < 255) ? TPixelCM32(idx, 0, tone) : TPixelCM32();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TCleanupper::preprocessColors(
Toshihiro Shimizu 890ddd
	const TRasterCM32P &outRas,
Toshihiro Shimizu 890ddd
	const TRaster32P &raster32,
Toshihiro Shimizu 890ddd
	const TargetColors &colors)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(outRas && outRas->getSize() == raster32->getSize());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Convert the target palette to HSV colorspace
Toshihiro Shimizu 890ddd
	std::vector<targetcolordata> pencilsHSV;</targetcolordata>
Toshihiro Shimizu 890ddd
	for (int i = 2; i < colors.getColorCount(); ++i) {
Toshihiro Shimizu 890ddd
		TargetColorData cdata(colors.getColor(i));
Toshihiro Shimizu 890ddd
		cdata.m_idx = i;
Toshihiro Shimizu 890ddd
		pencilsHSV.push_back(cdata);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Extract the 'black' Value
Toshihiro Shimizu 890ddd
	TargetColor black = colors.getColor(1);
Toshihiro Shimizu 890ddd
	TargetColorData blackData(black);
Toshihiro Shimizu 890ddd
	blackData.m_hsv.m_v += (1.0 - black.m_threshold / 100.0);
Toshihiro Shimizu 890ddd
	blackData.m_saturationLower = sq(1.0 - black.m_hRange / 100.0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	raster32->lock();
Toshihiro Shimizu 890ddd
	outRas->lock();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//For every image pixel, process it
Toshihiro Shimizu 890ddd
	for (int j = 0; j < raster32->getLy(); j++) {
Toshihiro Shimizu 890ddd
		TPixel32 *pix = raster32->pixels(j);
Toshihiro Shimizu 890ddd
		TPixel32 *endPix = pix + raster32->getLx();
Toshihiro Shimizu 890ddd
		TPixelCM32 *outPix = outRas->pixels(j);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		while (pix < endPix) {
Toshihiro Shimizu 890ddd
			if (*pix == TPixel32::White || pix->m < 255) //sometimes the resampling produces semitransparent pixels
Toshihiro Shimizu 890ddd
														 //on the  border of the raster; I discards those pixels.
Toshihiro Shimizu 890ddd
														 //(which otherwise creates a black border in the final cleanupped image)  vinz
Toshihiro Shimizu 890ddd
				*outPix = TPixelCM32();
Toshihiro Shimizu 890ddd
			else
Toshihiro Shimizu 890ddd
				preprocessColor(*pix, blackData, pencilsHSV, pencilsHSV.size(), *outPix);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			pix++;
Toshihiro Shimizu 890ddd
			outPix++;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	raster32->unlock();
Toshihiro Shimizu 890ddd
	outRas->unlock();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
//    Post-Processing
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TCleanupper::finalize(
Toshihiro Shimizu 890ddd
	const TRaster32P &outRas,
Toshihiro Shimizu 890ddd
	CleanupPreprocessedImage *srcImg)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (!outRas)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (srcImg->m_wasFromGR8)
Toshihiro Shimizu 890ddd
		doPostProcessingGR8(outRas, srcImg);
Toshihiro Shimizu 890ddd
	else
Toshihiro Shimizu 890ddd
		doPostProcessingColor(outRas, srcImg);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TToonzImageP TCleanupper::finalize(CleanupPreprocessedImage *src, bool isCleanupper)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (src->m_wasFromGR8)
Toshihiro Shimizu 890ddd
		return doPostProcessingGR8(src);
Toshihiro Shimizu 890ddd
	else
Toshihiro Shimizu 890ddd
		return doPostProcessingColor(src->getImg(), isCleanupper);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TCleanupper::doPostProcessingGR8(
Toshihiro Shimizu 890ddd
	const TRaster32P &outRas,
Toshihiro Shimizu 890ddd
	CleanupPreprocessedImage *srcImg)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TToonzImageP image = srcImg->getImg();
Toshihiro Shimizu 890ddd
	TRasterCM32P rasCM32 = image->getRaster();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	rasCM32->lock();
Toshihiro Shimizu 890ddd
	outRas->lock();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TRasterCM32P cmout(outRas->getLx(), outRas->getLy(), outRas->getWrap(), (TPixelCM32 *)outRas->getRawData());
Toshihiro Shimizu 890ddd
	TRop::copy(cmout, rasCM32);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	rasCM32->unlock();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Apply brightness/contrast and grayscale conversion directly
Toshihiro Shimizu 890ddd
	brightnessContrastGR8(cmout, m_parameters->m_colors);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Apply despeckling
Toshihiro Shimizu 890ddd
	if (m_parameters->m_despeckling)
Toshihiro Shimizu 890ddd
		TRop::despeckle(cmout, m_parameters->m_despeckling, m_parameters->m_transparencyCheckEnabled);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Morphological antialiasing
Toshihiro Shimizu 890ddd
	if (m_parameters->m_postAntialias) {
Toshihiro Shimizu 890ddd
		TRasterCM32P newRas(cmout->getLx(), cmout->getLy());
Toshihiro Shimizu 890ddd
		TRop::antialias(cmout, newRas, 10, m_parameters->m_aaValue);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		cmout->unlock();
Toshihiro Shimizu 890ddd
		cmout = newRas;
Toshihiro Shimizu 890ddd
		cmout->lock();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Finally, do transparency check
Toshihiro Shimizu 890ddd
	if (m_parameters->m_transparencyCheckEnabled)
Toshihiro Shimizu 890ddd
		transparencyCheck(cmout, outRas);
Toshihiro Shimizu 890ddd
	else
Toshihiro Shimizu 890ddd
		//TRop::convert(outRas, cmout, m_parameters->m_cleanupPalette);
Toshihiro Shimizu 890ddd
		TRop::convert(outRas, cmout, createToonzPaletteFromCleanupPalette());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	outRas->unlock();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TToonzImageP TCleanupper::doPostProcessingGR8(const CleanupPreprocessedImage *img)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TToonzImageP image = img->getImg();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TRasterCM32P rasCM32 = image->getRaster();
Toshihiro Shimizu 890ddd
	TRasterCM32P cmout(rasCM32->clone());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	cmout->lock();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Apply brightness/contrast and grayscale conversion directly
Toshihiro Shimizu 890ddd
	brightnessContrastGR8(cmout, m_parameters->m_colors);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Apply despeckling
Toshihiro Shimizu 890ddd
	if (m_parameters->m_despeckling)
Toshihiro Shimizu 890ddd
		TRop::despeckle(cmout, m_parameters->m_despeckling, false);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Morphological antialiasing
Toshihiro Shimizu 890ddd
	if (m_parameters->m_postAntialias) {
Toshihiro Shimizu 890ddd
		TRasterCM32P newRas(cmout->getLx(), cmout->getLy());
Toshihiro Shimizu 890ddd
		TRop::antialias(cmout, newRas, 10, m_parameters->m_aaValue);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		cmout->unlock();
Toshihiro Shimizu 890ddd
		cmout = newRas;
Toshihiro Shimizu 890ddd
		cmout->lock();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	cmout->unlock();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Rebuild the cmap's bbox
Toshihiro Shimizu 890ddd
	TRect bbox;
Toshihiro Shimizu 890ddd
	TRop::computeBBox(cmout, bbox);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Copy the dpi
Toshihiro Shimizu 890ddd
	TToonzImageP outImg(cmout, bbox);
Toshihiro Shimizu 890ddd
	double dpix, dpiy;
Toshihiro Shimizu 890ddd
	image->getDpi(dpix, dpiy);
Toshihiro Shimizu 890ddd
	outImg->setDpi(dpix, dpiy);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return outImg;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TCleanupper::doPostProcessingColor(
Toshihiro Shimizu 890ddd
	const TRaster32P &outRas,
Toshihiro Shimizu 890ddd
	CleanupPreprocessedImage *srcImg)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(srcImg);
Toshihiro Shimizu 890ddd
	assert(outRas->getSize() == srcImg->getSize());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TToonzImageP imgToProcess = srcImg->getImg();
Toshihiro Shimizu 890ddd
	TRasterCM32P rasCM32 = imgToProcess->getRaster();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	rasCM32->lock();
Toshihiro Shimizu 890ddd
	outRas->lock();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TRasterCM32P cmout(outRas->getLx(), outRas->getLy(), outRas->getWrap(), (TPixelCM32 *)outRas->getRawData());
Toshihiro Shimizu 890ddd
	TRop::copy(cmout, rasCM32);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	rasCM32->unlock();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//First, deal with brightness/contrast
Toshihiro Shimizu 890ddd
	brightnessContrast(cmout, m_parameters->m_colors);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Then, apply despeckling
Toshihiro Shimizu 890ddd
	if (m_parameters->m_despeckling)
Toshihiro Shimizu 890ddd
		TRop::despeckle(cmout, m_parameters->m_despeckling, m_parameters->m_transparencyCheckEnabled);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Morphological antialiasing
Toshihiro Shimizu 890ddd
	if (m_parameters->m_postAntialias) {
Toshihiro Shimizu 890ddd
		TRasterCM32P newRas(cmout->getLx(), cmout->getLy());
Toshihiro Shimizu 890ddd
		TRop::antialias(cmout, newRas, 10, m_parameters->m_aaValue);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		cmout->unlock();
Toshihiro Shimizu 890ddd
		cmout = newRas;
Toshihiro Shimizu 890ddd
		cmout->lock();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Finally, do transparency check
Toshihiro Shimizu 890ddd
	if (m_parameters->m_transparencyCheckEnabled)
Toshihiro Shimizu 890ddd
		transparencyCheck(cmout, outRas);
Toshihiro Shimizu 890ddd
	else
Toshihiro Shimizu 890ddd
		//TRop::convert(outRas, cmout, m_parameters->m_cleanupPalette);
Toshihiro Shimizu 890ddd
		TRop::convert(outRas, cmout, createToonzPaletteFromCleanupPalette());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	outRas->unlock();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TToonzImageP TCleanupper::doPostProcessingColor(const TToonzImageP &imgToProcess, bool isCleanupper)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//(Build and) Copy imgToProcess to output image
Toshihiro Shimizu 890ddd
	TToonzImageP outImage;
Toshihiro Shimizu 890ddd
	if (isCleanupper)
Toshihiro Shimizu 890ddd
		outImage = imgToProcess;
Toshihiro Shimizu 890ddd
	else
Toshihiro Shimizu 890ddd
		outImage = TToonzImageP(imgToProcess->cloneImage());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	assert(outImage);
Toshihiro Shimizu 890ddd
	assert(m_parameters->m_colors.getColorCount() < 9);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Perform post-processing
Toshihiro Shimizu 890ddd
	TRasterCM32P outRasCM32 = outImage->getRaster();
Toshihiro Shimizu 890ddd
	outRasCM32->lock();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Brightness/Contrast
Toshihiro Shimizu 890ddd
	brightnessContrast(outRasCM32, m_parameters->m_colors);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Despeckling
Toshihiro Shimizu 890ddd
	if (m_parameters->m_despeckling)
Toshihiro Shimizu 890ddd
		TRop::despeckle(outRasCM32, m_parameters->m_despeckling, false);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Morphological antialiasing
Toshihiro Shimizu 890ddd
	if (m_parameters->m_postAntialias) {
Toshihiro Shimizu 890ddd
		TRasterCM32P newRas(outRasCM32->getLx(), outRasCM32->getLy());
Toshihiro Shimizu 890ddd
		TRop::antialias(outRasCM32, newRas, 10, m_parameters->m_aaValue);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		outRasCM32->unlock();
Toshihiro Shimizu 890ddd
		outRasCM32 = newRas;
Toshihiro Shimizu 890ddd
		outImage->setCMapped(outRasCM32);
Toshihiro Shimizu 890ddd
		outRasCM32->lock();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TRect bbox;
Toshihiro Shimizu 890ddd
	TRop::computeBBox(outRasCM32, bbox);
Toshihiro Shimizu 890ddd
	outImage->setSavebox(bbox);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	outRasCM32->unlock();
Toshihiro Shimizu 890ddd
	return outImage;
Toshihiro Shimizu 890ddd
}