You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/chalk/plugins/viewplugins/scripting/chalkcore/krs_iterator.h

308 lines
12 KiB

/*
* Copyright (c) 2005 Cyrille Berger <cberger@cberger.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef KROSS_KRITACOREKRS_ITERATOR_H
#define KROSS_KRITACOREKRS_ITERATOR_H
#include <tqobject.h>
#include <api/class.h>
//#include <api/proxy.h>
//#include <api/variant.h>
#include <tdelocale.h>
#include <kis_paint_layer.h>
#include <kis_paint_device.h>
#include <kis_types.h>
#include <kis_script_monitor.h>
namespace Kross {
namespace ChalkCore {
//<beurk> stupid TQt which doesn't support templated TQObject
class IteratorMemoryManaged {
public:
virtual void invalidateIterator() = 0;
};
class IteratorMemoryManager : public TQObject {
TQ_OBJECT
public:
IteratorMemoryManager(IteratorMemoryManaged* it) : m_it(it)
{
// Connect the Monitor to know when the invalidating of iterator is needed
connect(KisScriptMonitor::instance(), TQT_SIGNAL(executionFinished(const Kross::Api::ScriptAction* )), this, TQT_SLOT(invalidateIterator()));
}
public slots:
void invalidateIterator()
{
m_it->invalidateIterator();
}
private:
IteratorMemoryManaged* m_it;
};
//</beurk>
/**
* This object allow to change the value of pixel one by one.
* The name of some function depends of the colorspace, for instance, if
* the colorspace of the layer is RGB, you will have setR, setG, setB... and for CMYK,
* setC, setM, setY, setK. In the doc bellow we will consider the colorspace is called ABC with
* three channels : A, B and C.
*
* Function: setA setB setC
* Those functions take one argument:
* - the new value of one of the channel of this pixel
*
* Function: setABC
* Set the value of all channels.
* This function take one argument:
* - an array with the new value for all channels
*/
template<class _T_It>
class Iterator : public Kross::Api::Class<Iterator<_T_It> >, private IteratorMemoryManaged
{
public:
Iterator(_T_It it, KisPaintLayerSP layer) : Kross::Api::Class<Iterator<_T_It> >("ChalkIterator"), m_itmm (new IteratorMemoryManager(this)), m_it(new _T_It(it)), nchannels(layer->paintDevice()->nChannels()), m_layer(layer)
{
// navigate in the iterator
this->addFunction("next",
new Kross::Api::ProxyFunction<
Iterator<_T_It>, // instance
bool (Iterator<_T_It>::*)(), // method
Kross::Api::Variant // return-value
>(this, &Iterator<_T_It>::next));
this->addFunction("isDone",
new Kross::Api::ProxyFunction<
Iterator<_T_It>, // instance
bool (Iterator<_T_It>::*)(), // method
Kross::Api::Variant // return-value
>(this, &Iterator<_T_It>::isDone));
// get/set value
TQValueVector<KisChannelInfo *> channels = layer->paintDevice()->colorSpace()->channels();
TQString initiales = "";
for(TQValueVector<KisChannelInfo *>::iterator itC = channels.begin(); itC != channels.end(); itC++)
{
KisChannelInfo * ci = *itC;
initiales += ci->name().left(1);
switch(ci->channelValueType())
{
case KisChannelInfo::UINT8:
this->addFunction("get"+ci->name(),
new Kross::Api::Function1< Iterator<_T_It> , uint >(
this, &Iterator<_T_It>::getChannelUINT8, ci->pos() ) );
this->addFunction("set"+ci->name(),
new Kross::Api::Function1< Iterator<_T_It> , uint >(
this, &Iterator<_T_It>::setChannelUINT8, ci->pos() ) );
break;
case KisChannelInfo::UINT16:
this->addFunction("get"+ci->name(),
new Kross::Api::Function1< Iterator<_T_It> , uint >(
this, &Iterator<_T_It>::getChannelUINT16, ci->pos() ) );
this->addFunction("set"+ci->name(),
new Kross::Api::Function1< Iterator<_T_It> , uint >(
this, &Iterator<_T_It>::setChannelUINT16, ci->pos() ) );
break;
case KisChannelInfo::FLOAT32:
this->addFunction("get"+ci->name(),
new Kross::Api::Function1< Iterator<_T_It> , uint >(
this, &Iterator<_T_It>::getChannelFLOAT, ci->pos() ) );
this->addFunction("set"+ci->name(),
new Kross::Api::Function1< Iterator<_T_It> , uint >(
this, &Iterator<_T_It>::setChannelFLOAT, ci->pos() ) );
break;
default:
kdDebug(41011) << "unsupported data format in scripts" << endl;
break;
}
}
initiales = initiales.upper();
// set/get general
this->addFunction("set" + initiales, &Iterator::setPixel);
this->addFunction("get" + initiales, &Iterator::getPixel);
kdDebug(41011) << ( "get" + initiales ) << endl;
// Various colorSpace
this->addFunction("invertColor", &Iterator::invertColor);
this->addFunction("darken", &Iterator::darken);
}
~Iterator()
{
invalidateIterator();
delete m_itmm;
}
virtual const TQString getClassName() const {
return "Kross::ChalkCore::KrsDoc";
};
private:
/**
* Darken a pixel.
* This functions at least one argument:
* - shade amount use to darken all color channels
*
* This function can take the following optional argument:
* - compensation to limit the darkening
*/
Kross::Api::Object::Ptr darken(Kross::Api::List::Ptr args)
{
TQ_INT32 shade = Kross::Api::Variant::toUInt( args->item(0) );
bool compensate = (args->count() == 2);
double compensation = compensate ? Kross::Api::Variant::toDouble( args->item(2) ) : 0.;
m_layer->paintDevice()->colorSpace()->darken(m_it->rawData(), m_it->rawData(), shade, compensate, compensation, 1);
return 0;
}
/**
* Invert the color of a pixel.
*/
Kross::Api::Object::Ptr invertColor(Kross::Api::List::Ptr )
{
m_layer->paintDevice()->colorSpace()->invertColor(m_it->rawData(), 1);
return 0;
}
/**
* Increment the positon, and go to the next pixel.
*/
bool next()
{
++(*m_it);
return m_it->isDone();
}
/**
* Return true if the iterator is at the end, and that no more pixels are available.
*/
bool isDone()
{
return m_it->isDone();
}
Kross::Api::Object::Ptr getChannelUINT8(Kross::Api::List::Ptr, uint channelpos)
{
TQ_UINT8* data = (TQ_UINT8*)(m_it->rawData() + channelpos);
return new Kross::Api::Variant( * data);
}
Kross::Api::Object::Ptr setChannelUINT8(Kross::Api::List::Ptr args, uint channelpos)
{
TQ_UINT8* data = (TQ_UINT8*)(m_it->rawData() + channelpos); //*(uint*)channelpos);
*data = Kross::Api::Variant::toUInt( args->item(0) );
return 0;
}
Kross::Api::Object::Ptr getChannelUINT16(Kross::Api::List::Ptr, uint channelpos)
{
TQ_UINT16* data = (TQ_UINT16*)(m_it->rawData() + channelpos);
return new Kross::Api::Variant( * data);
}
Kross::Api::Object::Ptr setChannelUINT16(Kross::Api::List::Ptr args, uint channelpos)
{
TQ_UINT16* data = (TQ_UINT16*)(m_it->rawData() + channelpos);
*data = Kross::Api::Variant::toUInt( args->item(0) );
return 0;
}
Kross::Api::Object::Ptr getChannelFLOAT(Kross::Api::List::Ptr, uint channelpos)
{
float* data = (float*)(m_it->rawData() + channelpos);
return new Kross::Api::Variant( * data);
}
Kross::Api::Object::Ptr setChannelFLOAT(Kross::Api::List::Ptr args, uint channelpos)
{
float* data = (float*)(m_it->rawData() + channelpos);
*data = Kross::Api::Variant::toUInt( args->item(0) );
return 0;
}
Kross::Api::Object::Ptr getPixel(Kross::Api::List::Ptr)
{
TQValueVector<KisChannelInfo *> channels = m_layer->paintDevice()->colorSpace()->channels();
TQValueList<TQVariant> pixel;
for(TQValueVector<KisChannelInfo *>::iterator itC = channels.begin(); itC != channels.end(); itC++)
{
KisChannelInfo * ci = *itC;
TQ_UINT8* data = (TQ_UINT8*)(m_it->rawData() + ci->pos());
switch(ci->channelValueType())
{
case KisChannelInfo::UINT8:
pixel.push_back( *data);
break;
case KisChannelInfo::UINT16:
pixel.push_back( *((TQ_UINT16*) data) );
break;
case KisChannelInfo::FLOAT32:
pixel.push_back( *((float*) data) );
break;
default:
kdDebug(41011) << i18n("An error has occurred in %1").arg("getPixel") << endl;
kdDebug(41011) << i18n("unsupported data format in scripts") << endl;
break;
}
}
return new Kross::Api::Variant( pixel);
}
Kross::Api::Object::Ptr setPixel(Kross::Api::List::Ptr args)
{
TQValueList<TQVariant> pixel = Kross::Api::Variant::toList( args->item(0) );
TQValueVector<KisChannelInfo *> channels = m_layer->paintDevice()->colorSpace()->channels();
uint i = 0;
for(TQValueVector<KisChannelInfo *>::iterator itC = channels.begin(); itC != channels.end(); itC++, i++)
{
KisChannelInfo * ci = *itC;
TQ_UINT8* data = (TQ_UINT8*)(m_it->rawData() + ci->pos());
switch(ci->channelValueType())
{
case KisChannelInfo::UINT8:
*data = pixel[i].toUInt();
break;
case KisChannelInfo::UINT16:
*((TQ_UINT16*) data) = pixel[i].toUInt();
break;
case KisChannelInfo::FLOAT32:
*((float*) data) = pixel[i].toDouble();
break;
default:
kdDebug(41011) << i18n("An error has occurred in %1").arg("setPixel") << endl;
kdDebug(41011) << i18n("unsupported data format in scripts") << endl;
break;
}
}
return 0;
}
private:
virtual void invalidateIterator()
{
kdDebug(41011) << "invalidating iterator" << endl;
if(m_it)
{
kdDebug(41011) << "deleting iterator" << endl;
delete m_it;
}
m_it = 0;
kdDebug() << " Iterator = " << m_it << endl;
}
private:
IteratorMemoryManager* m_itmm;
_T_It* m_it;
int nchannels;
KisPaintLayerSP m_layer;
};
}
}
#endif