|
|
|
/*
|
|
|
|
* Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org>
|
|
|
|
*
|
|
|
|
* this program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the gnu general public license as published by
|
|
|
|
* the free software foundation; either version 2 of the license, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* this program is distributed in the hope that it will be useful,
|
|
|
|
* but without any warranty; without even the implied warranty of
|
|
|
|
* merchantability or fitness for a particular purpose. see the
|
|
|
|
* gnu general public license for more details.
|
|
|
|
*
|
|
|
|
* you should have received a copy of the gnu general public license
|
|
|
|
* along with this program; if not, write to the free software
|
|
|
|
* foundation, inc., 675 mass ave, cambridge, ma 02139, usa.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <tqimage.h>
|
|
|
|
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <tqcolor.h>
|
|
|
|
|
|
|
|
#include "kis_layer.h"
|
|
|
|
#include "kis_debug_areas.h"
|
|
|
|
#include "kis_types.h"
|
|
|
|
#include "kis_colorspace_factory_registry.h"
|
|
|
|
#include "kis_fill_painter.h"
|
|
|
|
#include "kis_iterators_pixel.h"
|
|
|
|
#include "kis_integer_maths.h"
|
|
|
|
#include "kis_image.h"
|
|
|
|
#include "kis_datamanager.h"
|
|
|
|
#include "kis_fill_painter.h"
|
|
|
|
#include "kis_selection.h"
|
|
|
|
|
|
|
|
KisSelection::KisSelection(KisPaintDeviceSP dev)
|
|
|
|
: super(dev->parentLayer()
|
|
|
|
, KisMetaRegistry::instance()->csRegistry()->getAlpha8()
|
|
|
|
, (TQString("selection for ") + dev->name()).latin1())
|
|
|
|
, m_parentPaintDevice(dev)
|
|
|
|
, m_doCacheExactRect(false)
|
|
|
|
, m_dirty(false)
|
|
|
|
{
|
|
|
|
Q_ASSERT(dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
KisSelection::KisSelection()
|
|
|
|
: super(KisMetaRegistry::instance()->csRegistry()->getAlpha8(), "anonymous selection")
|
|
|
|
, m_parentPaintDevice(0), m_dirty(false)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
KisSelection::KisSelection(const KisSelection& rhs)
|
|
|
|
: super(rhs), m_parentPaintDevice(rhs.m_parentPaintDevice), m_doCacheExactRect(rhs.m_doCacheExactRect),
|
|
|
|
m_cachedExactRect(rhs.m_cachedExactRect), m_dirty(rhs.m_dirty)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
KisSelection::~KisSelection()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
TQ_UINT8 KisSelection::selected(TQ_INT32 x, TQ_INT32 y)
|
|
|
|
{
|
|
|
|
KisHLineIteratorPixel iter = createHLineIterator(x, y, 1, false);
|
|
|
|
|
|
|
|
TQ_UINT8 *pix = iter.rawData();
|
|
|
|
|
|
|
|
return *pix;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisSelection::setSelected(TQ_INT32 x, TQ_INT32 y, TQ_UINT8 s)
|
|
|
|
{
|
|
|
|
KisHLineIteratorPixel iter = createHLineIterator(x, y, 1, true);
|
|
|
|
|
|
|
|
TQ_UINT8 *pix = iter.rawData();
|
|
|
|
|
|
|
|
*pix = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQImage KisSelection::maskImage()
|
|
|
|
{
|
|
|
|
// If part of a KisAdjustmentLayer, there may be no tqparent device.
|
|
|
|
TQImage img;
|
|
|
|
TQRect bounds;
|
|
|
|
if (m_parentPaintDevice) {
|
|
|
|
|
|
|
|
bounds = m_parentPaintDevice->exactBounds();
|
|
|
|
bounds = bounds.intersect( m_parentPaintDevice->image()->bounds() );
|
|
|
|
img = TQImage(bounds.width(), bounds.height(), 32);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
bounds = TQRect( 0, 0, image()->width(), image()->height());
|
|
|
|
img = TQImage(bounds.width(), bounds.height(), 32);
|
|
|
|
}
|
|
|
|
|
|
|
|
KisHLineIteratorPixel it = createHLineIterator(bounds.x(), bounds.y(), bounds.width(), false);
|
|
|
|
for (int y2 = bounds.y(); y2 < bounds.height() - bounds.y(); ++y2) {
|
|
|
|
int x2 = 0;
|
|
|
|
while (!it.isDone()) {
|
|
|
|
TQ_UINT8 s = MAX_SELECTED - *(it.rawData());
|
|
|
|
TQ_INT32 c = tqRgb(s, s, s);
|
|
|
|
img.setPixel(x2, y2, c);
|
|
|
|
++x2;
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
it.nextRow();
|
|
|
|
}
|
|
|
|
return img;
|
|
|
|
}
|
|
|
|
void KisSelection::select(TQRect r)
|
|
|
|
{
|
|
|
|
KisFillPainter painter(this);
|
|
|
|
KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry()->getRGB8();
|
|
|
|
painter.fillRect(r, KisColor(TQt::white, cs), MAX_SELECTED);
|
|
|
|
TQ_INT32 x, y, w, h;
|
|
|
|
extent(x, y, w, h);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisSelection::clear(TQRect r)
|
|
|
|
{
|
|
|
|
KisFillPainter painter(this);
|
|
|
|
KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry()->getRGB8();
|
|
|
|
painter.fillRect(r, KisColor(TQt::white, cs), MIN_SELECTED);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisSelection::clear()
|
|
|
|
{
|
|
|
|
TQ_UINT8 defPixel = MIN_SELECTED;
|
|
|
|
m_datamanager->setDefaultPixel(&defPixel);
|
|
|
|
m_datamanager->clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisSelection::invert()
|
|
|
|
{
|
|
|
|
TQ_INT32 x,y,w,h;
|
|
|
|
|
|
|
|
extent(x, y, w, h);
|
|
|
|
KisRectIterator it = createRectIterator(x, y, w, h, true);
|
|
|
|
while ( ! it.isDone() )
|
|
|
|
{
|
|
|
|
// CBR this is wrong only first byte is inverted
|
|
|
|
// BSAR: But we have always only one byte in this color model :-).
|
|
|
|
*(it.rawData()) = MAX_SELECTED - *(it.rawData());
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
TQ_UINT8 defPixel = MAX_SELECTED - *(m_datamanager->defaultPixel());
|
|
|
|
m_datamanager->setDefaultPixel(&defPixel);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KisSelection::isTotallyUnselected(TQRect r)
|
|
|
|
{
|
|
|
|
if(*(m_datamanager->defaultPixel()) != MIN_SELECTED)
|
|
|
|
return false;
|
|
|
|
TQRect sr = selectedExactRect();
|
|
|
|
return ! r.intersects(sr);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KisSelection::isProbablyTotallyUnselected(TQRect r)
|
|
|
|
{
|
|
|
|
if(*(m_datamanager->defaultPixel()) != MIN_SELECTED)
|
|
|
|
return false;
|
|
|
|
TQRect sr = selectedRect();
|
|
|
|
return ! r.intersects(sr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TQRect KisSelection::selectedRect() const
|
|
|
|
{
|
|
|
|
if(*(m_datamanager->defaultPixel()) == MIN_SELECTED || !m_parentPaintDevice)
|
|
|
|
return extent();
|
|
|
|
else
|
|
|
|
return extent().unite(m_parentPaintDevice->extent());
|
|
|
|
}
|
|
|
|
|
|
|
|
TQRect KisSelection::selectedExactRect() const
|
|
|
|
{
|
|
|
|
if(m_doCacheExactRect)
|
|
|
|
return m_cachedExactRect;
|
|
|
|
else if(*(m_datamanager->defaultPixel()) == MIN_SELECTED || !m_parentPaintDevice)
|
|
|
|
return exactBounds();
|
|
|
|
else
|
|
|
|
return exactBounds().unite(m_parentPaintDevice->exactBounds());
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisSelection::stopCachingExactRect()
|
|
|
|
{
|
|
|
|
kdDebug() << "stop caching the exact rect" << endl;
|
|
|
|
m_doCacheExactRect = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KisSelection::startCachingExactRect()
|
|
|
|
{
|
|
|
|
kdDebug() << "start caching the exact rect" << endl;
|
|
|
|
if(*(m_datamanager->defaultPixel()) == MIN_SELECTED || !m_parentPaintDevice)
|
|
|
|
m_cachedExactRect = exactBounds();
|
|
|
|
else
|
|
|
|
m_cachedExactRect = exactBounds().unite(m_parentPaintDevice->exactBounds());
|
|
|
|
m_doCacheExactRect = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisSelection::paintUniformSelectionRegion(TQImage img, const TQRect& imageRect, const TQRegion& uniformRegion)
|
|
|
|
{
|
|
|
|
Q_ASSERT(img.size() == imageRect.size());
|
|
|
|
Q_ASSERT(imageRect.tqcontains(uniformRegion.boundingRect()));
|
|
|
|
|
|
|
|
if (img.isNull() || img.size() != imageRect.size() || !imageRect.tqcontains(uniformRegion.boundingRect())) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*m_datamanager->defaultPixel() == MIN_SELECTED) {
|
|
|
|
|
|
|
|
TQRegion region = uniformRegion & TQRegion(imageRect);
|
|
|
|
|
|
|
|
if (!region.isEmpty()) {
|
|
|
|
TQMemArray<TQRect> rects = region.tqrects();
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < rects.count(); i++) {
|
|
|
|
TQRect r = rects[i];
|
|
|
|
|
|
|
|
for (TQ_INT32 y = 0; y < r.height(); ++y) {
|
|
|
|
|
|
|
|
TQRgb *imagePixel = reinterpret_cast<TQRgb *>(img.scanLine(r.y() - imageRect.y() + y));
|
|
|
|
imagePixel += r.x() - imageRect.x();
|
|
|
|
|
|
|
|
TQ_INT32 numPixels = r.width();
|
|
|
|
|
|
|
|
while (numPixels > 0) {
|
|
|
|
|
|
|
|
TQRgb srcPixel = *imagePixel;
|
|
|
|
TQ_UINT8 srcGrey = (tqRed(srcPixel) + tqGreen(srcPixel) + tqBlue(srcPixel)) / 9;
|
|
|
|
TQ_UINT8 srcAlpha = tqAlpha(srcPixel);
|
|
|
|
|
|
|
|
srcGrey = UINT8_MULT(srcGrey, srcAlpha);
|
|
|
|
TQ_UINT8 dstAlpha = TQMAX(srcAlpha, 192);
|
|
|
|
|
|
|
|
TQRgb dstPixel = tqRgba(128 + srcGrey, 128 + srcGrey, 165 + srcGrey, dstAlpha);
|
|
|
|
*imagePixel = dstPixel;
|
|
|
|
|
|
|
|
++imagePixel;
|
|
|
|
--numPixels;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisSelection::paintSelection(TQImage img, TQ_INT32 imageRectX, TQ_INT32 imageRectY, TQ_INT32 imageRectWidth, TQ_INT32 imageRectHeight)
|
|
|
|
{
|
|
|
|
Q_ASSERT(img.size() == TQSize(imageRectWidth, imageRectHeight));
|
|
|
|
|
|
|
|
if (img.isNull() || img.size() != TQSize(imageRectWidth, imageRectHeight)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQRect imageRect(imageRectX, imageRectY, imageRectWidth, imageRectHeight);
|
|
|
|
TQRect selectionExtent = extent();
|
|
|
|
|
|
|
|
selectionExtent.setLeft(selectionExtent.left() - 1);
|
|
|
|
selectionExtent.setTop(selectionExtent.top() - 1);
|
|
|
|
selectionExtent.setWidth(selectionExtent.width() + 2);
|
|
|
|
selectionExtent.setHeight(selectionExtent.height() + 2);
|
|
|
|
|
|
|
|
TQRegion uniformRegion = TQRegion(imageRect);
|
|
|
|
uniformRegion -= TQRegion(selectionExtent);
|
|
|
|
|
|
|
|
if (!uniformRegion.isEmpty()) {
|
|
|
|
paintUniformSelectionRegion(img, imageRect, uniformRegion);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQRect nonuniformRect = imageRect & selectionExtent;
|
|
|
|
|
|
|
|
if (!nonuniformRect.isEmpty()) {
|
|
|
|
|
|
|
|
const TQ_INT32 imageRectOffsetX = nonuniformRect.x() - imageRectX;
|
|
|
|
const TQ_INT32 imageRectOffsetY = nonuniformRect.y() - imageRectY;
|
|
|
|
|
|
|
|
imageRectX = nonuniformRect.x();
|
|
|
|
imageRectY = nonuniformRect.y();
|
|
|
|
imageRectWidth = nonuniformRect.width();
|
|
|
|
imageRectHeight = nonuniformRect.height();
|
|
|
|
|
|
|
|
const TQ_INT32 NUM_SELECTION_ROWS = 3;
|
|
|
|
|
|
|
|
TQ_UINT8 *selectionRow[NUM_SELECTION_ROWS];
|
|
|
|
|
|
|
|
TQ_INT32 aboveRowIndex = 0;
|
|
|
|
TQ_INT32 centreRowIndex = 1;
|
|
|
|
TQ_INT32 belowRowIndex = 2;
|
|
|
|
|
|
|
|
selectionRow[aboveRowIndex] = new TQ_UINT8[imageRectWidth + 2];
|
|
|
|
selectionRow[centreRowIndex] = new TQ_UINT8[imageRectWidth + 2];
|
|
|
|
selectionRow[belowRowIndex] = new TQ_UINT8[imageRectWidth + 2];
|
|
|
|
|
|
|
|
readBytes(selectionRow[centreRowIndex], imageRectX - 1, imageRectY - 1, imageRectWidth + 2, 1);
|
|
|
|
readBytes(selectionRow[belowRowIndex], imageRectX - 1, imageRectY, imageRectWidth + 2, 1);
|
|
|
|
|
|
|
|
for (TQ_INT32 y = 0; y < imageRectHeight; ++y) {
|
|
|
|
|
|
|
|
TQ_INT32 oldAboveRowIndex = aboveRowIndex;
|
|
|
|
aboveRowIndex = centreRowIndex;
|
|
|
|
centreRowIndex = belowRowIndex;
|
|
|
|
belowRowIndex = oldAboveRowIndex;
|
|
|
|
|
|
|
|
readBytes(selectionRow[belowRowIndex], imageRectX - 1, imageRectY + y + 1, imageRectWidth + 2, 1);
|
|
|
|
|
|
|
|
const TQ_UINT8 *aboveRow = selectionRow[aboveRowIndex] + 1;
|
|
|
|
const TQ_UINT8 *centreRow = selectionRow[centreRowIndex] + 1;
|
|
|
|
const TQ_UINT8 *belowRow = selectionRow[belowRowIndex] + 1;
|
|
|
|
|
|
|
|
TQRgb *imagePixel = reinterpret_cast<TQRgb *>(img.scanLine(imageRectOffsetY + y));
|
|
|
|
imagePixel += imageRectOffsetX;
|
|
|
|
|
|
|
|
for (TQ_INT32 x = 0; x < imageRectWidth; ++x) {
|
|
|
|
|
|
|
|
TQ_UINT8 centre = *centreRow;
|
|
|
|
|
|
|
|
if (centre != MAX_SELECTED) {
|
|
|
|
|
|
|
|
// this is where we come if the pixels should be blue or bluish
|
|
|
|
|
|
|
|
TQRgb srcPixel = *imagePixel;
|
|
|
|
TQ_UINT8 srcGrey = (tqRed(srcPixel) + tqGreen(srcPixel) + tqBlue(srcPixel)) / 9;
|
|
|
|
TQ_UINT8 srcAlpha = tqAlpha(srcPixel);
|
|
|
|
|
|
|
|
// Colour influence is proportional to alphaPixel.
|
|
|
|
srcGrey = UINT8_MULT(srcGrey, srcAlpha);
|
|
|
|
|
|
|
|
TQRgb dstPixel;
|
|
|
|
|
|
|
|
if (centre == MIN_SELECTED) {
|
|
|
|
//this is where we come if the pixels should be blue (or red outline)
|
|
|
|
|
|
|
|
TQ_UINT8 left = *(centreRow - 1);
|
|
|
|
TQ_UINT8 right = *(centreRow + 1);
|
|
|
|
TQ_UINT8 above = *aboveRow;
|
|
|
|
TQ_UINT8 below = *belowRow;
|
|
|
|
|
|
|
|
// Stop unselected transparent areas from appearing the same
|
|
|
|
// as selected transparent areas.
|
|
|
|
TQ_UINT8 dstAlpha = TQMAX(srcAlpha, 192);
|
|
|
|
|
|
|
|
// now for a simple outline based on 4-connectivity
|
|
|
|
if (left != MIN_SELECTED || right != MIN_SELECTED || above != MIN_SELECTED || below != MIN_SELECTED) {
|
|
|
|
dstPixel = tqRgba(255, 0, 0, dstAlpha);
|
|
|
|
} else {
|
|
|
|
dstPixel = tqRgba(128 + srcGrey, 128 + srcGrey, 165 + srcGrey, dstAlpha);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
dstPixel = tqRgba(UINT8_BLEND(tqRed(srcPixel), srcGrey + 128, centre),
|
|
|
|
UINT8_BLEND(tqGreen(srcPixel), srcGrey + 128, centre),
|
|
|
|
UINT8_BLEND(tqBlue(srcPixel), srcGrey + 165, centre),
|
|
|
|
srcAlpha);
|
|
|
|
}
|
|
|
|
|
|
|
|
*imagePixel = dstPixel;
|
|
|
|
}
|
|
|
|
|
|
|
|
aboveRow++;
|
|
|
|
centreRow++;
|
|
|
|
belowRow++;
|
|
|
|
imagePixel++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
delete [] selectionRow[aboveRowIndex];
|
|
|
|
delete [] selectionRow[centreRowIndex];
|
|
|
|
delete [] selectionRow[belowRowIndex];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisSelection::paintSelection(TQImage img, const TQRect& scaledImageRect, const TQSize& scaledImageSize, const TQSize& imageSize)
|
|
|
|
{
|
|
|
|
if (img.isNull() || scaledImageRect.isEmpty() || scaledImageSize.isEmpty() || imageSize.isEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Q_ASSERT(img.size() == scaledImageRect.size());
|
|
|
|
|
|
|
|
if (img.size() != scaledImageRect.size()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQ_INT32 imageWidth = imageSize.width();
|
|
|
|
TQ_INT32 imageHeight = imageSize.height();
|
|
|
|
|
|
|
|
TQRect selectionExtent = extent();
|
|
|
|
|
|
|
|
selectionExtent.setLeft(selectionExtent.left() - 1);
|
|
|
|
selectionExtent.setTop(selectionExtent.top() - 1);
|
|
|
|
selectionExtent.setWidth(selectionExtent.width() + 2);
|
|
|
|
selectionExtent.setHeight(selectionExtent.height() + 2);
|
|
|
|
|
|
|
|
double xScale = static_cast<double>(scaledImageSize.width()) / imageWidth;
|
|
|
|
double yScale = static_cast<double>(scaledImageSize.height()) / imageHeight;
|
|
|
|
|
|
|
|
TQRect scaledSelectionExtent;
|
|
|
|
|
|
|
|
scaledSelectionExtent.setLeft(static_cast<int>(selectionExtent.left() * xScale));
|
|
|
|
scaledSelectionExtent.setRight(static_cast<int>(ceil((selectionExtent.right() + 1) * xScale)) - 1);
|
|
|
|
scaledSelectionExtent.setTop(static_cast<int>(selectionExtent.top() * yScale));
|
|
|
|
scaledSelectionExtent.setBottom(static_cast<int>(ceil((selectionExtent.bottom() + 1) * yScale)) - 1);
|
|
|
|
|
|
|
|
TQRegion uniformRegion = TQRegion(scaledImageRect);
|
|
|
|
uniformRegion -= TQRegion(scaledSelectionExtent);
|
|
|
|
|
|
|
|
if (!uniformRegion.isEmpty()) {
|
|
|
|
paintUniformSelectionRegion(img, scaledImageRect, uniformRegion);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQRect nonuniformRect = scaledImageRect & scaledSelectionExtent;
|
|
|
|
|
|
|
|
if (!nonuniformRect.isEmpty()) {
|
|
|
|
|
|
|
|
const TQ_INT32 scaledImageRectXOffset = nonuniformRect.x() - scaledImageRect.x();
|
|
|
|
const TQ_INT32 scaledImageRectYOffset = nonuniformRect.y() - scaledImageRect.y();
|
|
|
|
|
|
|
|
const TQ_INT32 scaledImageRectX = nonuniformRect.x();
|
|
|
|
const TQ_INT32 scaledImageRectY = nonuniformRect.y();
|
|
|
|
const TQ_INT32 scaledImageRectWidth = nonuniformRect.width();
|
|
|
|
const TQ_INT32 scaledImageRectHeight = nonuniformRect.height();
|
|
|
|
|
|
|
|
const TQ_INT32 imageRowLeft = static_cast<TQ_INT32>(scaledImageRectX / xScale);
|
|
|
|
const TQ_INT32 imageRowRight = static_cast<TQ_INT32>((ceil((scaledImageRectX + scaledImageRectWidth - 1 + 1) / xScale)) - 1);
|
|
|
|
|
|
|
|
const TQ_INT32 imageRowWidth = imageRowRight - imageRowLeft + 1;
|
|
|
|
const TQ_INT32 imageRowStride = imageRowWidth + 2;
|
|
|
|
|
|
|
|
const TQ_INT32 NUM_SELECTION_ROWS = 3;
|
|
|
|
|
|
|
|
TQ_INT32 aboveRowIndex = 0;
|
|
|
|
TQ_INT32 centreRowIndex = 1;
|
|
|
|
TQ_INT32 belowRowIndex = 2;
|
|
|
|
|
|
|
|
TQ_INT32 aboveRowSrcY = -3;
|
|
|
|
TQ_INT32 centreRowSrcY = -3;
|
|
|
|
TQ_INT32 belowRowSrcY = -3;
|
|
|
|
|
|
|
|
TQ_UINT8 *selectionRows = new TQ_UINT8[imageRowStride * NUM_SELECTION_ROWS];
|
|
|
|
TQ_UINT8 *selectionRow[NUM_SELECTION_ROWS];
|
|
|
|
|
|
|
|
selectionRow[0] = selectionRows + 1;
|
|
|
|
selectionRow[1] = selectionRow[0] + imageRowStride;
|
|
|
|
selectionRow[2] = selectionRow[0] + (2 * imageRowStride);
|
|
|
|
|
|
|
|
for (TQ_INT32 y = 0; y < scaledImageRectHeight; ++y) {
|
|
|
|
|
|
|
|
TQ_INT32 scaledY = scaledImageRectY + y;
|
|
|
|
TQ_INT32 srcY = (scaledY * imageHeight) / scaledImageSize.height();
|
|
|
|
|
|
|
|
TQ_UINT8 *aboveRow;
|
|
|
|
TQ_UINT8 *centreRow;
|
|
|
|
TQ_UINT8 *belowRow;
|
|
|
|
|
|
|
|
if (srcY - 1 == aboveRowSrcY) {
|
|
|
|
aboveRow = selectionRow[aboveRowIndex];
|
|
|
|
centreRow = selectionRow[centreRowIndex];
|
|
|
|
belowRow = selectionRow[belowRowIndex];
|
|
|
|
} else if (srcY - 1 == centreRowSrcY) {
|
|
|
|
|
|
|
|
TQ_INT32 oldAboveRowIndex = aboveRowIndex;
|
|
|
|
|
|
|
|
aboveRowIndex = centreRowIndex;
|
|
|
|
centreRowIndex = belowRowIndex;
|
|
|
|
belowRowIndex = oldAboveRowIndex;
|
|
|
|
|
|
|
|
aboveRow = selectionRow[aboveRowIndex];
|
|
|
|
centreRow = selectionRow[centreRowIndex];
|
|
|
|
belowRow = selectionRow[belowRowIndex];
|
|
|
|
|
|
|
|
readBytes(belowRow - 1, imageRowLeft - 1, srcY + 1, imageRowStride, 1);
|
|
|
|
|
|
|
|
} else if (srcY - 1 == belowRowSrcY) {
|
|
|
|
|
|
|
|
TQ_INT32 oldAboveRowIndex = aboveRowIndex;
|
|
|
|
TQ_INT32 oldCentreRowIndex = centreRowIndex;
|
|
|
|
|
|
|
|
aboveRowIndex = belowRowIndex;
|
|
|
|
centreRowIndex = oldAboveRowIndex;
|
|
|
|
belowRowIndex = oldCentreRowIndex;
|
|
|
|
|
|
|
|
aboveRow = selectionRow[aboveRowIndex];
|
|
|
|
centreRow = selectionRow[centreRowIndex];
|
|
|
|
belowRow = selectionRow[belowRowIndex];
|
|
|
|
|
|
|
|
if (belowRowIndex == centreRowIndex + 1) {
|
|
|
|
readBytes(centreRow - 1, imageRowLeft - 1, srcY, imageRowStride, 2);
|
|
|
|
} else {
|
|
|
|
readBytes(centreRow - 1, imageRowLeft - 1, srcY, imageRowStride, 1);
|
|
|
|
readBytes(belowRow - 1, imageRowLeft - 1, srcY + 1, imageRowStride, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
aboveRowIndex = 0;
|
|
|
|
centreRowIndex = 1;
|
|
|
|
belowRowIndex = 2;
|
|
|
|
|
|
|
|
aboveRow = selectionRow[aboveRowIndex];
|
|
|
|
centreRow = selectionRow[centreRowIndex];
|
|
|
|
belowRow = selectionRow[belowRowIndex];
|
|
|
|
|
|
|
|
readBytes(selectionRows, imageRowLeft - 1, srcY - 1, imageRowStride, NUM_SELECTION_ROWS);
|
|
|
|
}
|
|
|
|
|
|
|
|
aboveRowSrcY = srcY - 1;
|
|
|
|
centreRowSrcY = aboveRowSrcY + 1;
|
|
|
|
belowRowSrcY = centreRowSrcY + 1;
|
|
|
|
|
|
|
|
TQRgb *imagePixel = reinterpret_cast<TQRgb *>(img.scanLine(scaledImageRectYOffset + y));
|
|
|
|
imagePixel += scaledImageRectXOffset;
|
|
|
|
|
|
|
|
for (TQ_INT32 x = 0; x < scaledImageRectWidth; ++x) {
|
|
|
|
|
|
|
|
TQ_INT32 scaledX = scaledImageRectX + x;
|
|
|
|
TQ_INT32 srcX = (scaledX * imageWidth) / scaledImageSize.width();
|
|
|
|
|
|
|
|
TQ_UINT8 centre = *(centreRow + srcX - imageRowLeft);
|
|
|
|
|
|
|
|
if (centre != MAX_SELECTED) {
|
|
|
|
|
|
|
|
// this is where we come if the pixels should be blue or bluish
|
|
|
|
|
|
|
|
TQRgb srcPixel = *imagePixel;
|
|
|
|
TQ_UINT8 srcGrey = (tqRed(srcPixel) + tqGreen(srcPixel) + tqBlue(srcPixel)) / 9;
|
|
|
|
TQ_UINT8 srcAlpha = tqAlpha(srcPixel);
|
|
|
|
|
|
|
|
// Colour influence is proportional to alphaPixel.
|
|
|
|
srcGrey = UINT8_MULT(srcGrey, srcAlpha);
|
|
|
|
|
|
|
|
TQRgb dstPixel;
|
|
|
|
|
|
|
|
if (centre == MIN_SELECTED) {
|
|
|
|
//this is where we come if the pixels should be blue (or red outline)
|
|
|
|
|
|
|
|
TQ_UINT8 left = *(centreRow + (srcX - imageRowLeft) - 1);
|
|
|
|
TQ_UINT8 right = *(centreRow + (srcX - imageRowLeft) + 1);
|
|
|
|
TQ_UINT8 above = *(aboveRow + (srcX - imageRowLeft));
|
|
|
|
TQ_UINT8 below = *(belowRow + (srcX - imageRowLeft));
|
|
|
|
|
|
|
|
// Stop unselected transparent areas from appearing the same
|
|
|
|
// as selected transparent areas.
|
|
|
|
TQ_UINT8 dstAlpha = TQMAX(srcAlpha, 192);
|
|
|
|
|
|
|
|
// now for a simple outline based on 4-connectivity
|
|
|
|
if (left != MIN_SELECTED || right != MIN_SELECTED || above != MIN_SELECTED || below != MIN_SELECTED) {
|
|
|
|
dstPixel = tqRgba(255, 0, 0, dstAlpha);
|
|
|
|
} else {
|
|
|
|
dstPixel = tqRgba(128 + srcGrey, 128 + srcGrey, 165 + srcGrey, dstAlpha);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
dstPixel = tqRgba(UINT8_BLEND(tqRed(srcPixel), srcGrey + 128, centre),
|
|
|
|
UINT8_BLEND(tqGreen(srcPixel), srcGrey + 128, centre),
|
|
|
|
UINT8_BLEND(tqBlue(srcPixel), srcGrey + 165, centre),
|
|
|
|
srcAlpha);
|
|
|
|
}
|
|
|
|
|
|
|
|
*imagePixel = dstPixel;
|
|
|
|
}
|
|
|
|
|
|
|
|
imagePixel++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
delete [] selectionRows;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisSelection::setDirty(const TQRect& rc)
|
|
|
|
{
|
|
|
|
if (m_dirty)
|
|
|
|
super::setDirty(rc);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisSelection::setDirty()
|
|
|
|
{
|
|
|
|
if (m_dirty)
|
|
|
|
super::setDirty();
|
|
|
|
}
|