modify flipbook histogram

This commit is contained in:
shun-iwasawa 2021-10-14 14:13:07 +09:00 committed by manongjohn
parent f8e8df4fa1
commit 8b5a413d51
9 changed files with 491 additions and 126 deletions

View file

@ -66,7 +66,10 @@ public:
// per pli come sopra, ma ritorna il maincolor
// per tzp e fullcolor ritorna il colore effettivo del pixel
TPixel32 pickColor(const TPointD &point, double radius, double scale2) const;
TPixel64 pickColor16(const TPointD &point, double radius,
double scale2) const;
TPixel32 pickAverageColor(const TRectD &rect) const;
TPixel64 pickAverageColor16(const TRectD &rect) const;
// ritorna il colore medio presente nell'area della finestra corrente openGL
TPixel32 pickColor(const TRectD &area) const;
@ -80,5 +83,4 @@ public:
// il valore di ritorno si riferisce all'eventuale raster: (0,0)==leftbottom
TPoint getRasterPoint(const TPointD &p) const;
};
#endif

View file

@ -44,14 +44,21 @@ class QLabel;
class DVAPI ComboHistoRGBLabel final : public QWidget {
Q_OBJECT
public:
enum DisplayMode { Display_8bit = 0, Display_16bit, Display_0_1 };
private:
QColor m_color;
DisplayMode m_mode;
public:
ComboHistoRGBLabel(QColor color, QWidget *parent);
~ComboHistoRGBLabel() {}
void setColorAndUpdate(QColor color);
void setDisplayMode(DisplayMode mode) { m_mode = mode; }
protected:
void paintEvent(QPaintEvent *pe) override;
@ -62,17 +69,20 @@ protected:
class DVAPI ChannelHistoGraph : public QWidget {
Q_OBJECT
QVector<int> m_values;
QVector<int> m_values[2]; // 0: current raster 1: snapshot
int m_maxValue[2];
int m_pickedValue;
int m_channelIndex;
public:
int *m_channelValuePtr;
bool *m_showComparePtr;
ChannelHistoGraph(QWidget *parent = 0, int *channelValue = 0);
ChannelHistoGraph(int index, QWidget *parent = nullptr,
bool *showComparePtr = nullptr);
~ChannelHistoGraph();
virtual void setValues();
virtual void setValues(int *buf, bool isComp);
void showCurrentChannelValue(int val);
@ -90,10 +100,10 @@ class DVAPI RGBHistoGraph final : public ChannelHistoGraph {
QImage m_histoImg;
public:
RGBHistoGraph(QWidget *parent = 0, int *channelValue = 0);
RGBHistoGraph(int index, QWidget *parent = 0);
~RGBHistoGraph();
void setValues() override;
void setValues(int *buf, bool isComp) override;
protected:
void paintEvent(QPaintEvent *event) override;
@ -121,10 +131,12 @@ class DVAPI ChannelHisto final : public QWidget {
ChannelColorBar *m_colorBar;
public:
ChannelHisto(int channelIndex, int *channelValue, QWidget *parent = 0);
ChannelHisto(int channelIndex, bool *showComparePtr, QWidget *parent = 0);
~ChannelHisto() {}
void refleshValue() { m_histogramGraph->setValues(); }
void refleshValue(int *buf, bool isComp = false) {
m_histogramGraph->setValues(buf, isComp);
}
void showCurrentChannelValue(int val);
@ -153,6 +165,12 @@ class DVAPI ComboHistogram final : public QWidget {
QLabel *m_xPosLabel;
QLabel *m_yPosLabel;
QComboBox *m_displayModeCombo;
bool m_showCompare;
bool m_compHistoIsValid;
int m_channelValueComp[4][COMBOHIST_RESOLUTION_W];
public:
ComboHistogram(QWidget *parent = 0);
~ComboHistogram();
@ -160,10 +178,27 @@ public:
TRasterP getRaster() const { return m_raster; }
void setRaster(const TRasterP &raster, const TPaletteP &palette = 0);
void updateInfo(const TPixel32 &pix, const TPointD &imagePos);
void updateInfo(const TPixel64 &pix, const TPointD &imagePos);
void updateAverageColor(const TPixel32 &pix);
void updateAverageColor(const TPixel64 &pix);
void updateCompHistogram();
void setShowCompare(bool on) {
m_showCompare = on;
if (isVisible() && !m_compHistoIsValid) updateCompHistogram();
}
void invalidateCompHisto() {
m_compHistoIsValid = false;
if (isVisible() && m_showCompare) updateCompHistogram();
}
protected:
void computeChannelsValue();
void computeChannelsValue(int *buf, size_t size, TRasterP ras,
TPalette *extPlt = nullptr);
void showEvent(QShowEvent *) override;
protected slots:
void onDisplayModeChanged();
};
#endif

View file

@ -172,6 +172,27 @@ TPixel32 StylePicker::pickColor(const TPointD &pos, double radius,
//---------------------------------------------------------
TPixel64 StylePicker::pickColor16(const TPointD &pos, double radius,
double scale2) const {
TToonzImageP ti = m_image;
TRasterImageP ri = m_image;
TVectorImageP vi = m_image;
assert(ri && !ti && !vi);
if (!ri || ti || vi) return TPixel64::Transparent;
TRasterP raster = ri->getRaster();
if (raster->getPixelSize() != 8) return TPixel64::Transparent;
TPoint point = getRasterPoint(pos);
if (!raster->getBounds().contains(point)) return TPixel64::Transparent;
TRaster64P raster64 = raster;
if (!raster64) return TPixel64::Transparent;
return raster64->pixels(point.y)[point.x];
}
//---------------------------------------------------------
TPixel32 StylePicker::pickAverageColor(const TRectD &rect) const {
TRasterImageP ri = m_image;
assert(ri);
@ -216,8 +237,50 @@ TPixel32 StylePicker::pickAverageColor(const TRectD &rect) const {
//---------------------------------------------------------
namespace {
TPixel64 StylePicker::pickAverageColor16(const TRectD &rect) const {
TRasterImageP ri = m_image;
assert(ri);
if (!ri) return TPixel64::Transparent;
TRasterP raster;
raster = ri->getRaster();
if (raster->getPixelSize() != 8) return TPixel64::Transparent;
TPoint topLeft = getRasterPoint(rect.getP00());
TPoint bottomRight = getRasterPoint(rect.getP11());
if (!raster->getBounds().overlaps(TRect(topLeft, bottomRight)))
return TPixel64::Transparent;
topLeft.x = std::max(0, topLeft.x);
topLeft.y = std::max(0, topLeft.y);
bottomRight.x = std::min(raster->getLx(), bottomRight.x);
bottomRight.y = std::min(raster->getLy(), bottomRight.y);
TRaster64P raster64 = raster;
assert(raster64);
if (!raster64) return TPixel64::Transparent;
UINT r = 0, g = 0, b = 0, m = 0, size = 0;
for (int y = topLeft.y; y < bottomRight.y; y++) {
TPixel64 *p = &raster64->pixels(y)[topLeft.x];
for (int x = topLeft.x; x < bottomRight.x; x++, p++) {
r += p->r;
g += p->g;
b += p->b;
m += p->m;
size++;
}
}
if (size)
return TPixel64(r / size, g / size, b / size, m / size);
else
return TPixel64::Transparent;
}
//---------------------------------------------------------
namespace {
TPixel32 getAverageColor(const TRect &rect) {
GLenum fmt =
#if defined(TNZ_MACHINE_CHANNEL_ORDER_BGRM)
@ -234,8 +297,8 @@ TPixel32 getAverageColor(const TRect &rect) {
#endif
UINT r = 0, g = 0, b = 0, m = 0;
std::vector<TPixel32> buffer(rect.getLx() * rect.getLy());
glReadPixels(rect.x0, rect.y0, rect.getLx(), rect.getLy(), fmt,
GL_UNSIGNED_BYTE, &buffer[0]);
glReadPixels(rect.x0, rect.y0, rect.getLx(), rect.getLy(), fmt, TGL_TYPE,
&buffer[0]);
int size = rect.getLx() * rect.getLy();
for (int i = 0; i < size; i++) {
r += buffer[i].r;
@ -243,7 +306,7 @@ TPixel32 getAverageColor(const TRect &rect) {
b += buffer[i].b;
}
return TPixel32(b / size, g / size, r / size, 255);
return TPixel32(b / size, g / size, r / size, TPixel32::maxChannelValue);
}
//---------------------------------------------------------

View file

@ -791,15 +791,19 @@ void FlipBook::onButtonPressed(FlipConsole::EGadget button) {
clonedImg->setPalette(ti->getPalette());
}
TImageCache::instance()->add(QString("TnzCompareImg"), clonedImg);
// to update the histogram of compare snapshot image
m_imageViewer->invalidateCompHisto();
break;
}
case FlipConsole::eCompare:
if ((TVectorImageP)getCurrentImage(m_flipConsole->getCurrentFrame())) {
if (m_flipConsole->isChecked(FlipConsole::eCompare) &&
(TVectorImageP)getCurrentImage(m_flipConsole->getCurrentFrame())) {
DVGui::warning(
tr("It is not possible to take or compare snapshots for Toonz vector "
"levels."));
m_flipConsole->setChecked(FlipConsole::eCompare, false);
// cancel the button pressing
m_flipConsole->pressButton(FlipConsole::eCompare);
return;
}
break;

View file

@ -45,6 +45,7 @@ HistogramPopup::HistogramPopup(QString title)
mainLay->setSpacing(0);
{ mainLay->addWidget(m_histogram); }
setLayout(mainLay);
mainLay->setSizeConstraint(QLayout::SetFixedSize);
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
}
@ -74,18 +75,37 @@ void HistogramPopup::setImage(TImageP image) {
}
//-----------------------------------------------------------------------------
/*! show the picked color
*/
*/
void HistogramPopup::updateInfo(const TPixel32 &pix, const TPointD &imagePos) {
m_histogram->updateInfo(pix, imagePos);
}
void HistogramPopup::updateInfo(const TPixel64 &pix, const TPointD &imagePos) {
m_histogram->updateInfo(pix, imagePos);
}
//-----------------------------------------------------------------------------
/*! show the average-picked color
*/
*/
void HistogramPopup::updateAverageColor(const TPixel32 &pix) {
m_histogram->updateAverageColor(pix);
}
void HistogramPopup::updateAverageColor(const TPixel64 &pix) {
m_histogram->updateAverageColor(pix);
}
//-----------------------------------------------------------------------------
void HistogramPopup::setShowCompare(bool on) {
m_histogram->setShowCompare(on);
}
//-----------------------------------------------------------------------------
void HistogramPopup::invalidateCompHisto() {
m_histogram->invalidateCompHisto();
}
//=============================================================================
/*! \class ViewerHistogramPopup
\brief The ViewerHistogramPopup show the histogram pertain to

View file

@ -27,7 +27,11 @@ public:
void setImage(TImageP image);
void updateInfo(const TPixel32 &pix, const TPointD &imagePos);
void updateInfo(const TPixel64 &pix, const TPointD &imagePos);
void updateAverageColor(const TPixel32 &pix);
void updateAverageColor(const TPixel64 &pix);
void setShowCompare(bool on);
void invalidateCompHisto();
};
//=============================================================================

View file

@ -370,6 +370,10 @@ void ImageViewer::contextMenuEvent(QContextMenuEvent *event) {
//-----------------------------------------------------------------------------
void ImageViewer::setVisual(const ImagePainter::VisualSettings &settings) {
if (m_isHistogramEnable && m_histogramPopup &&
settings.m_doCompare != m_visualSettings.m_doCompare) {
m_histogramPopup->setShowCompare(settings.m_doCompare);
}
m_visualSettings = settings;
m_visualSettings.m_sceneProperties =
TApp::instance()->getCurrentScene()->getScene()->getProperties();
@ -857,7 +861,10 @@ void ImageViewer::mouseMoveEvent(QMouseEvent *event) {
if (m_rectRGBPick) {
update();
rectPickColor();
// do not pick vector image while dragging as a portion of the red
// rubber band may affect the result
TImageP img = getPickedImage(m_pos);
if (img && img->raster()) rectPickColor();
}
}
@ -941,34 +948,48 @@ void ImageViewer::pickColor(QMouseEvent *event, bool putValueToStyleEditor) {
StylePicker picker(img);
TPointD mousePos = TPointD(curPos.x(), height() - 1 - curPos.y());
TRectD area = TRectD(mousePos.x, mousePos.y, mousePos.x, mousePos.y);
TPointD pos =
getViewAff().inv() * TPointD(curPos.x() - (qreal)(width()) / 2,
-curPos.y() + (qreal)(height()) / 2);
TRectD imgRect = (img->raster()) ? convert(TRect(img->raster()->getSize()))
: img->getBBox();
TPointD imagePos =
TPointD(0.5 * imgRect.getLx() + pos.x, 0.5 * imgRect.getLy() + pos.y);
TPointD imagePos = (img->raster()) ? TPointD(0.5 * imgRect.getLx() + pos.x,
0.5 * imgRect.getLy() + pos.y)
: pos;
TPixel32 pix;
if (m_lutCalibrator && m_lutCalibrator->isValid()) {
if (!imgRect.contains(imagePos)) {
// throw transparent color if picking outside of the image
m_histogramPopup->updateInfo(TPixel32::Transparent, TPointD(-1, -1));
} else if (!img->raster()) { // vector image
// For unknown reasons, glReadPixels is covering the entire window not the
// OpenGL widget.
QPointF winPos = event->windowPos() * getDevPixRatio();
TPointD mousePos =
TPointD(winPos.x(), (double)(window()->height()) - winPos.y());
TRectD area = TRectD(mousePos.x, mousePos.y, mousePos.x, mousePos.y);
TPixel32 pix = picker.pickColor(area);
m_histogramPopup->updateInfo(pix, imagePos);
if (putValueToStyleEditor) setPickedColorToStyleEditor(pix);
} else if (img->raster()->getPixelSize() == 8) // 16bpc raster
{
// for specifying pixel range on picking vector
double scale2 = getViewAff().det();
pix = picker.pickColor(pos + TPointD(-0.5, -0.5), 10.0, scale2);
} else
pix = picker.pickColor(area);
TPixel64 pix = picker.pickColor16(pos + TPointD(-0.5, -0.5), 10.0, scale2);
// throw the picked color to the histogram
m_histogramPopup->updateInfo(pix, imagePos);
// throw it to the style editor as well
if (putValueToStyleEditor) setPickedColorToStyleEditor(toPixel32(pix));
} else { // 8bpc raster
// for specifying pixel range on picking vector
double scale2 = getViewAff().det();
TPixel32 pix = picker.pickColor(pos + TPointD(-0.5, -0.5), 10.0, scale2);
if (!img->raster() || imgRect.contains(imagePos)) {
// throw the picked color to the histogram
m_histogramPopup->updateInfo(pix, imagePos);
// throw it to the style editor as well
if (putValueToStyleEditor) setPickedColorToStyleEditor(pix);
} else {
// throw transparent color if picking outside of the image
m_histogramPopup->updateInfo(TPixel32::Transparent, TPointD(-1, -1));
}
}
@ -996,6 +1017,28 @@ void ImageViewer::rectPickColor(bool putValueToStyleEditor) {
StylePicker picker(img);
if (!img->raster()) { // vector image
TPointD pressedWinPos = convert(m_pressedMousePos) + m_winPosMousePosOffset;
TPointD startPos = TPointD(pressedWinPos.x,
(double)(window()->height()) - pressedWinPos.y);
TPointD currentWinPos =
TPointD(m_pos.x(), m_pos.y()) + m_winPosMousePosOffset;
TPointD endPos = TPointD(currentWinPos.x,
(double)(window()->height()) - currentWinPos.y);
TRectD area = TRectD(startPos, endPos);
area = area.enlarge(-4, -4);
if (area.getLx() < 2 || area.getLy() < 2) {
m_histogramPopup->updateAverageColor(TPixel32::Transparent);
return;
}
TPixel32 pix = picker.pickColor(area);
// throw the picked color to the histogram
m_histogramPopup->updateAverageColor(pix);
// throw it to the style editor as well
if (putValueToStyleEditor) setPickedColorToStyleEditor(pix);
return;
}
TPoint startPos =
TPoint(m_pressedMousePos.x, height() - 1 - m_pressedMousePos.y);
TPoint endPos = TPoint(m_pos.x(), height() - 1 - m_pos.y());
@ -1005,21 +1048,25 @@ void ImageViewer::rectPickColor(bool putValueToStyleEditor) {
m_histogramPopup->updateAverageColor(TPixel32::Transparent);
return;
}
TPointD start = getViewAff().inv() *
TPointD(startPos.x - width() / 2, startPos.y - height() / 2);
TPointD end = getViewAff().inv() *
TPointD(endPos.x - width() / 2, endPos.y - height() / 2);
TPixel32 pix;
if (m_lutCalibrator && m_lutCalibrator->isValid() && isRas32(img)) {
TPointD start = getViewAff().inv() * TPointD(startPos.x - width() / 2,
startPos.y - height() / 2);
TPointD end = getViewAff().inv() *
TPointD(endPos.x - width() / 2, endPos.y - height() / 2);
pix = picker.pickAverageColor(TRectD(start, end));
} else
pix = picker.pickColor(area.enlarge(-1, -1));
// throw the picked color to the histogram
m_histogramPopup->updateAverageColor(pix);
// throw it to the style editor as well
if (putValueToStyleEditor) setPickedColorToStyleEditor(pix);
if (img->raster()->getPixelSize() == 8) // 16bpc raster
{
TPixel64 pix = picker.pickAverageColor16(TRectD(start, end));
// throw the picked color to the histogram
m_histogramPopup->updateAverageColor(pix);
// throw it to the style editor as well
if (putValueToStyleEditor) setPickedColorToStyleEditor(toPixel32(pix));
} else { // 8bpc raster
TPixel32 pix = picker.pickAverageColor(TRectD(start, end));
// throw the picked color to the histogram
m_histogramPopup->updateAverageColor(pix);
// throw it to the style editor as well
if (putValueToStyleEditor) setPickedColorToStyleEditor(pix);
}
}
//-----------------------------------------------------------------------------
@ -1087,6 +1134,9 @@ void ImageViewer::mousePressEvent(QMouseEvent *event) {
m_mouseButton = event->button();
m_draggingZoomSelection = false;
QPointF winPosMousePos = event->windowPos() * getDevPixRatio() - m_pos;
m_winPosMousePosOffset = TPointD(winPosMousePos.x(), winPosMousePos.y());
if (m_mouseButton != Qt::LeftButton) {
event->ignore();
return;
@ -1332,6 +1382,13 @@ void ImageViewer::changeSwapBehavior(bool enable) {
//-----------------------------------------------------------------------------
void ImageViewer::invalidateCompHisto() {
if (!m_isHistogramEnable || !m_histogramPopup) return;
m_histogramPopup->invalidateCompHisto();
}
//-----------------------------------------------------------------------------
void ImageViewer::keyPressEvent(QKeyEvent *event) {
if (FlipZoomer(this).exec(event)) return;

View file

@ -38,6 +38,11 @@ class ImageViewer final : public GLWidgetForHighDpi {
FlipBook *m_flipbook;
TPoint m_pressedMousePos;
// Modifying rect-picking positon offset for vector image.
// For unknown reasons, glReadPixels is covering the entire window not the
// OpenGL widget.
TPointD m_winPosMousePosOffset;
Qt::MouseButton m_mouseButton;
bool m_draggingZoomSelection;
@ -125,6 +130,7 @@ public:
void doSwapBuffers();
void changeSwapBehavior(bool enable);
void invalidateCompHisto();
protected:
void contextMenuEvent(QContextMenuEvent *event) override;

View file

@ -12,44 +12,68 @@
#include "toonz/preferences.h"
#include "toonzqt/lutcalibrator.h"
#include "toonzqt/gutil.h"
#include "timagecache.h"
#include "trasterimage.h"
// TnzBase includes
#include "tenv.h"
#include <QPushButton>
#include <QDialog>
TEnv::IntVar HistogramChannelDisplayMode(
"HistogramChannelDisplayMode",
(int)ComboHistoRGBLabel::Display_8bit); // 8bit display by default
namespace {
inline int idx(int y, int x) { return y * COMBOHIST_RESOLUTION_W + x; }
} // namespace
//=============================================================================
// ChannelHistoGraph
//-----------------------------------------------------------------------------
ChannelHistoGraph::ChannelHistoGraph(QWidget *parent, int *channelValue)
: QWidget(parent), m_channelValuePtr(channelValue), m_pickedValue(-1) {
ChannelHistoGraph::ChannelHistoGraph(int index, QWidget *parent,
bool *showComparePtr)
: QWidget(parent)
, m_showComparePtr(showComparePtr)
, m_channelIndex(index)
, m_pickedValue(-1) {
// width 256+2 pixels, height 100+2 pixels (with margin)
setFixedSize(COMBOHIST_RESOLUTION_W + 2, COMBOHIST_RESOLUTION_H + 2);
m_values.reserve(COMBOHIST_RESOLUTION_W);
m_values[0].reserve(COMBOHIST_RESOLUTION_W);
m_values[1].reserve(COMBOHIST_RESOLUTION_W);
}
//-----------------------------------------------------------------------------
ChannelHistoGraph::~ChannelHistoGraph() { m_values.clear(); }
ChannelHistoGraph::~ChannelHistoGraph() {
m_values[0].clear();
m_values[1].clear();
}
//-----------------------------------------------------------------------------
void ChannelHistoGraph::setValues() {
m_values.clear();
m_values.resize(COMBOHIST_RESOLUTION_W);
void ChannelHistoGraph::setValues(int *buf, bool isComp) {
int id = (isComp) ? 1 : 0;
m_values[id].clear();
m_values[id].resize(COMBOHIST_RESOLUTION_W);
m_maxValue[id] = 1;
int i;
// normalize with the maximum value
int maxValue = 1;
for (i = 0; i < COMBOHIST_RESOLUTION_W; i++) {
int count = m_channelValuePtr[i];
if (maxValue < count) maxValue = count;
m_values[id][i] = buf[i];
if (m_maxValue[id] < buf[i]) m_maxValue[id] = buf[i];
}
for (i = 0; i < COMBOHIST_RESOLUTION_W; i++) {
int v = m_channelValuePtr[i];
m_values[i] =
tround((double)(v * COMBOHIST_RESOLUTION_H) / (double)maxValue);
}
// for (i = 0; i < COMBOHIST_RESOLUTION_W; i++) {
// int v = buf[i];
// m_values[id][i] =
// tround((double)(v * COMBOHIST_RESOLUTION_H) / (double)maxValue);
//}
}
//-----------------------------------------------------------------------------
@ -71,23 +95,41 @@ void ChannelHistoGraph::paintEvent(QPaintEvent *event) {
p.drawLine(posx, 1, posx, COMBOHIST_RESOLUTION_H);
}
if (m_values.size() == 0) return;
QColor compColor = (m_channelIndex == 0)
? Qt::red
: (m_channelIndex == 1)
? Qt::green
: (m_channelIndex == 2) ? Qt::blue : Qt::magenta;
compColor.setAlpha(120);
p.setPen(Qt::black);
int maxValue = m_maxValue[0];
if (!m_values[1].isEmpty() && m_showComparePtr && *m_showComparePtr &&
m_maxValue[0] < m_maxValue[1])
maxValue = m_maxValue[1];
// draw each histogram
for (i = 0; i < COMBOHIST_RESOLUTION_W; i++) {
int v = m_values[i];
if (v <= 0) continue;
int x = 1 + i;
p.drawLine(x, COMBOHIST_RESOLUTION_H + 1 - v, x, COMBOHIST_RESOLUTION_H);
}
p.translate(0, COMBOHIST_RESOLUTION_H);
p.scale(1.0, -(double)COMBOHIST_RESOLUTION_H / (double)maxValue);
// draw picked color's channel value
if (m_pickedValue > -1) {
p.setPen(Qt::white);
int x = 1 + m_pickedValue;
p.drawLine(x, 1, x, COMBOHIST_RESOLUTION_H);
for (int id = 0; id < 2; id++) {
if (m_values[id].isEmpty()) continue;
if (id == 1 && (!m_showComparePtr || !(*m_showComparePtr))) continue;
p.setPen((id == 0) ? Qt::black : compColor);
// draw each histogram
for (i = 0; i < COMBOHIST_RESOLUTION_W; i++) {
int v = m_values[id][i];
if (v <= 0) continue;
int x = 1 + i;
p.drawLine(x, 0, x, v);
}
// draw picked color's channel value
if (m_pickedValue > -1) {
p.setPen(Qt::white);
int x = 1 + m_pickedValue;
p.drawLine(x, 1, x, maxValue);
}
}
}
@ -102,8 +144,8 @@ void ChannelHistoGraph::showCurrentChannelValue(int val) {
// ChannelHistoGraph
//-----------------------------------------------------------------------------
RGBHistoGraph::RGBHistoGraph(QWidget *parent, int *channelValue)
: ChannelHistoGraph(parent, channelValue) {
RGBHistoGraph::RGBHistoGraph(int index, QWidget *parent)
: ChannelHistoGraph(index, parent) {
m_histoImg = QImage(COMBOHIST_RESOLUTION_W, COMBOHIST_RESOLUTION_H,
QImage::Format_ARGB32_Premultiplied);
}
@ -116,7 +158,7 @@ RGBHistoGraph::~RGBHistoGraph() {
//-----------------------------------------------------------------------------
void RGBHistoGraph::setValues() {
void RGBHistoGraph::setValues(int *buf, bool) {
for (int chan = 0; chan < 3; chan++) {
m_rgbValues[chan].clear();
m_rgbValues[chan].resize(COMBOHIST_RESOLUTION_W);
@ -126,12 +168,12 @@ void RGBHistoGraph::setValues() {
// normalize with the maximum value
int maxValue = 1;
for (i = 0; i < COMBOHIST_RESOLUTION_W; i++) {
int count = m_channelValuePtr[COMBOHIST_RESOLUTION_W * chan + i];
int count = buf[COMBOHIST_RESOLUTION_W * chan + i];
if (maxValue < count) maxValue = count;
}
for (i = 0; i < COMBOHIST_RESOLUTION_W; i++) {
int v = m_channelValuePtr[COMBOHIST_RESOLUTION_W * chan + i];
int v = buf[COMBOHIST_RESOLUTION_W * chan + i];
m_rgbValues[chan][i] =
tround((double)(v * COMBOHIST_RESOLUTION_H) / (double)maxValue);
}
@ -150,8 +192,8 @@ void RGBHistoGraph::setValues() {
imgPainter.setCompositionMode(QPainter::CompositionMode_Plus);
for (int chan = 0; chan < 3; chan++) {
imgPainter.setPen((chan == 0) ? Qt::red : (chan == 1) ? Qt::green
: Qt::blue);
imgPainter.setPen((chan == 0) ? Qt::red
: (chan == 1) ? Qt::green : Qt::blue);
for (int i = 0; i < COMBOHIST_RESOLUTION_W; i++) {
int v = m_rgbValues[chan][i];
@ -211,7 +253,7 @@ void ChannelColorBar::paintEvent(QPaintEvent *event) {
//=============================================================================
// ChannelHisto
//-----------------------------------------------------------------------------
ChannelHisto::ChannelHisto(int channelIndex, int *channelValue,
ChannelHisto::ChannelHisto(int channelIndex, bool *showComparePtr,
QWidget *parent) {
QString label;
QColor color;
@ -233,15 +275,16 @@ ChannelHisto::ChannelHisto(int channelIndex, int *channelValue,
color = QColor(0, 0, 0, 0);
break;
case 4:
label = tr("RGBA");
label = tr("RGB");
color = Qt::white;
break;
}
if (channelIndex != 4)
m_histogramGraph = new ChannelHistoGraph(this, channelValue);
m_histogramGraph =
new ChannelHistoGraph(channelIndex, this, showComparePtr);
else
m_histogramGraph = new RGBHistoGraph(this, channelValue);
m_histogramGraph = new RGBHistoGraph(channelIndex, this);
m_colorBar = new ChannelColorBar(this, color);
@ -302,7 +345,7 @@ void ChannelHisto::onShowAlphaButtonToggled(bool visible) {
// ComboHistoRGBLabel
//-----------------------------------------------------------------------------
ComboHistoRGBLabel::ComboHistoRGBLabel(QColor color, QWidget *parent)
: QWidget(parent), m_color(color) {
: QWidget(parent), m_color(color), m_mode(DisplayMode::Display_8bit) {
setFixedSize(COMBOHIST_RESOLUTION_W, 30);
}
@ -340,10 +383,36 @@ void ComboHistoRGBLabel::paintEvent(QPaintEvent *pe) {
p.setPen(Qt::black);
p.setBrush(Qt::NoBrush);
p.drawText(rect(), Qt::AlignCenter, tr("R:%1 G:%2 B:%3")
.arg(m_color.red())
.arg(m_color.green())
.arg(m_color.blue()));
QFont font = p.font();
const int pixelSizes[3] = {18, 14, 14};
font.setPixelSize(pixelSizes[(int)m_mode]);
p.setFont(font);
QString colorStr;
switch (m_mode) {
case Display_8bit: {
colorStr = tr("R:%1 G:%2 B:%3")
.arg(m_color.red())
.arg(m_color.green())
.arg(m_color.blue());
break;
}
case Display_16bit: {
QRgba64 rgba64 = m_color.rgba64();
colorStr = tr("R:%1 G:%2 B:%3")
.arg(rgba64.red())
.arg(rgba64.green())
.arg(rgba64.blue());
break;
}
case Display_0_1: {
colorStr = tr("R:%1 G:%2 B:%3")
.arg(m_color.redF())
.arg(m_color.greenF())
.arg(m_color.blueF());
break;
}
}
p.drawText(rect(), Qt::AlignCenter, colorStr);
}
//=============================================================================
@ -351,21 +420,35 @@ void ComboHistoRGBLabel::paintEvent(QPaintEvent *pe) {
//-----------------------------------------------------------------------------
ComboHistogram::ComboHistogram(QWidget *parent)
: QWidget(parent), m_raster(0), m_palette(0) {
for (int chan = 0; chan < 4; chan++)
m_histograms[chan] = new ChannelHisto(chan, &m_channelValue[chan][0], this);
m_histograms[4] = new ChannelHisto(4, &m_channelValue[0][0], this);
: QWidget(parent)
, m_raster(0)
, m_palette(0)
, m_showCompare(false)
, m_compHistoIsValid(true) {
for (int chan = 0; chan < 4; chan++)
m_histograms[chan] = new ChannelHisto(chan, &m_showCompare, this);
m_histograms[4] = new ChannelHisto(4, &m_showCompare, this);
// RGB label
m_rgbLabel = new ComboHistoRGBLabel(QColor(128, 128, 128), this);
m_rgbLabel->setStyleSheet("font-size: 18px;");
// m_rgbLabel->setStyleSheet("font-size: 18px;");
m_rectAverageRgbLabel = new ComboHistoRGBLabel(QColor(128, 128, 128), this);
m_rectAverageRgbLabel->setStyleSheet("font-size: 18px;");
// m_rectAverageRgbLabel->setStyleSheet("font-size: 18px;");
m_xPosLabel = new QLabel("", this);
m_yPosLabel = new QLabel("", this);
m_displayModeCombo = new QComboBox(this);
m_displayModeCombo->addItem(
tr("8bit (0-255)"), (int)ComboHistoRGBLabel::DisplayMode::Display_8bit);
m_displayModeCombo->addItem(
tr("16bit (0-65535)"),
(int)ComboHistoRGBLabel::DisplayMode::Display_16bit);
m_displayModeCombo->addItem(
tr("0.0-1.0"), (int)ComboHistoRGBLabel::DisplayMode::Display_0_1);
// layout
QVBoxLayout *mainLayout = new QVBoxLayout();
mainLayout->setMargin(5);
@ -373,8 +456,16 @@ ComboHistogram::ComboHistogram(QWidget *parent)
{
mainLayout->addWidget(m_histograms[4]); // RGB
mainLayout->addWidget(new QLabel(tr("Picked Color"), this), 0,
Qt::AlignLeft | Qt::AlignVCenter);
QHBoxLayout *labelLay = new QHBoxLayout();
labelLay->setMargin(0);
labelLay->setSpacing(0);
{
labelLay->addWidget(new QLabel(tr("Picked Color"), this), 0);
labelLay->addStretch(1);
labelLay->addWidget(m_displayModeCombo, 0);
}
mainLayout->addLayout(labelLay, 0);
mainLayout->addWidget(m_rgbLabel, 0, Qt::AlignCenter);
mainLayout->addWidget(new QLabel(tr("Average Color (Ctrl + Drag)"), this),
@ -405,11 +496,15 @@ ComboHistogram::ComboHistogram(QWidget *parent)
setLayout(mainLayout);
m_rectAverageRgbLabel->setColorAndUpdate(Qt::transparent);
connect(m_displayModeCombo, SIGNAL(activated(int)), this,
SLOT(onDisplayModeChanged()));
}
//-----------------------------------------------------------------------------
ComboHistogram::~ComboHistogram() {
memset(m_channelValue, 0, sizeof m_channelValue);
memset(m_channelValueComp, 0, sizeof m_channelValueComp);
}
//-----------------------------------------------------------------------------
@ -417,27 +512,30 @@ ComboHistogram::~ComboHistogram() {
void ComboHistogram::setRaster(const TRasterP &raster,
const TPaletteP &palette) {
if (palette.getPointer()) m_palette = palette;
m_raster = raster;
computeChannelsValue();
m_raster = raster;
computeChannelsValue(&m_channelValue[0][0], sizeof(m_channelValue), m_raster);
for (int i = 0; i < 5; i++) m_histograms[i]->refleshValue();
for (int chan = 0; chan < 4; chan++)
m_histograms[chan]->refleshValue(&m_channelValue[chan][0]);
m_histograms[4]->refleshValue(&m_channelValue[0][0]);
update();
}
//-----------------------------------------------------------------------------
void ComboHistogram::computeChannelsValue() {
memset(m_channelValue, 0, sizeof m_channelValue);
if (!m_raster.getPointer()) return;
TRasterCM32P cmRaster = m_raster;
void ComboHistogram::computeChannelsValue(int *buf, size_t size, TRasterP ras,
TPalette *extPlt) {
memset(buf, 0, size);
if (!ras.getPointer()) return;
TRasterCM32P cmRaster = ras;
bool isCmRaster = !!cmRaster;
TRaster64P raster64 = m_raster;
TRaster64P raster64 = ras;
bool is64bit = !!raster64;
int lx = m_raster->getLx();
int ly = m_raster->getLy();
int lx = ras->getLx();
int ly = ras->getLy();
if (lx > 1 && ly > 1) {
int i, j;
if (is64bit) {
@ -446,44 +544,45 @@ void ComboHistogram::computeChannelsValue() {
for (i = 0; i < lx; i++, pix_64++) {
int mValue = (int)byteFromUshort(pix_64->m);
if (mValue != 0) {
++m_channelValue[0][(int)byteFromUshort(pix_64->r)];
++m_channelValue[1][(int)byteFromUshort(pix_64->g)];
++m_channelValue[2][(int)byteFromUshort(pix_64->b)];
++buf[idx(0, (int)byteFromUshort(pix_64->r))];
++buf[idx(1, (int)byteFromUshort(pix_64->g))];
++buf[idx(2, (int)byteFromUshort(pix_64->b))];
}
++m_channelValue[3][mValue];
++buf[idx(3, mValue)];
}
}
} else if (isCmRaster) {
assert(m_palette);
TPalette *plt = (extPlt) ? extPlt : m_palette.getPointer();
assert(plt);
for (j = 0; j < ly; j++) {
TPixelCM32 *pix_cm = cmRaster->pixels(j);
for (i = 0; i < lx; i++, pix_cm++) {
int styleId =
pix_cm->getTone() < 127 ? pix_cm->getInk() : pix_cm->getPaint();
TColorStyle *colorStyle = m_palette->getStyle(styleId);
TColorStyle *colorStyle = plt->getStyle(styleId);
if (!colorStyle) continue;
TPixel color = colorStyle->getAverageColor();
int mValue = color.m;
if (mValue != 0) {
++m_channelValue[0][color.r];
++m_channelValue[1][color.g];
++m_channelValue[2][color.b];
++buf[idx(0, color.r)];
++buf[idx(1, color.g)];
++buf[idx(2, color.b)];
}
++m_channelValue[3][color.m];
++buf[idx(3, color.m)];
}
}
} else // 8bpc raster
{
for (j = 0; j < ly; j++) {
TPixel *pix = (TPixel *)m_raster->getRawData(0, j);
TPixel *pix = (TPixel *)ras->getRawData(0, j);
for (i = 0; i < lx; i++, pix++) {
int mValue = pix->m;
if (mValue != 0) {
++m_channelValue[0][pix->r];
++m_channelValue[1][pix->g];
++m_channelValue[2][pix->b];
++buf[idx(0, pix->r)];
++buf[idx(1, pix->g)];
++buf[idx(2, pix->b)];
}
++m_channelValue[3][pix->m];
++buf[idx(3, pix->m)];
}
}
}
@ -512,6 +611,29 @@ void ComboHistogram::updateInfo(const TPixel32 &pix, const TPointD &imagePos) {
//-----------------------------------------------------------------------------
void ComboHistogram::updateInfo(const TPixel64 &pix, const TPointD &imagePos) {
if (pix == TPixel64::Transparent) {
m_histograms[0]->showCurrentChannelValue(-1);
m_histograms[1]->showCurrentChannelValue(-1);
m_histograms[2]->showCurrentChannelValue(-1);
m_rgbLabel->setColorAndUpdate(Qt::transparent);
m_xPosLabel->setText("");
m_yPosLabel->setText("");
} else {
TPixel32 pix32 = toPixel32(pix);
// show picked color's channel values
m_histograms[0]->showCurrentChannelValue((int)pix32.r);
m_histograms[1]->showCurrentChannelValue((int)pix32.g);
m_histograms[2]->showCurrentChannelValue((int)pix32.b);
m_rgbLabel->setColorAndUpdate(
QColor::fromRgba64((ushort)pix.r, (ushort)pix.g, (ushort)pix.b));
m_xPosLabel->setText(QString::number(tround(imagePos.x)));
m_yPosLabel->setText(QString::number(tround(imagePos.y)));
}
}
//-----------------------------------------------------------------------------
void ComboHistogram::updateAverageColor(const TPixel32 &pix) {
if (pix == TPixel32::Transparent) {
m_rectAverageRgbLabel->setColorAndUpdate(Qt::transparent);
@ -522,3 +644,55 @@ void ComboHistogram::updateAverageColor(const TPixel32 &pix) {
}
//-----------------------------------------------------------------------------
void ComboHistogram::updateAverageColor(const TPixel64 &pix) {
if (pix == TPixel64::Transparent) {
m_rectAverageRgbLabel->setColorAndUpdate(Qt::transparent);
} else {
m_rectAverageRgbLabel->setColorAndUpdate(
QColor::fromRgba64((ushort)pix.r, (ushort)pix.g, (ushort)pix.b));
}
}
//-----------------------------------------------------------------------------
void ComboHistogram::onDisplayModeChanged() {
ComboHistoRGBLabel::DisplayMode mode =
static_cast<ComboHistoRGBLabel::DisplayMode>(
m_displayModeCombo->currentData().toInt());
m_rgbLabel->setDisplayMode(mode);
m_rectAverageRgbLabel->setDisplayMode(mode);
HistogramChannelDisplayMode = (int)mode;
update();
}
//-----------------------------------------------------------------------------
void ComboHistogram::updateCompHistogram() {
assert(!m_compHistoIsValid);
m_compHistoIsValid = true;
TImageP refimg =
TImageCache::instance()->get(QString("TnzCompareImg"), false);
if (!(TToonzImageP)refimg && !(TRasterImageP)refimg) return;
computeChannelsValue(&m_channelValueComp[0][0], sizeof m_channelValueComp,
refimg->raster(), refimg->getPalette());
for (int chan = 0; chan < 4; chan++)
m_histograms[chan]->refleshValue(&m_channelValueComp[chan][0], true);
}
//-----------------------------------------------------------------------------
void ComboHistogram::showEvent(QShowEvent *) {
if (!m_compHistoIsValid && m_showCompare) updateCompHistogram();
int envMode = HistogramChannelDisplayMode;
m_displayModeCombo->setCurrentIndex(m_displayModeCombo->findData(envMode));
ComboHistoRGBLabel::DisplayMode mode =
static_cast<ComboHistoRGBLabel::DisplayMode>(envMode);
m_rgbLabel->setDisplayMode(mode);
m_rectAverageRgbLabel->setDisplayMode(mode);
}