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