[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-kimageshop
Subject:    KisScaleVisitor
From:       Michael Thaler <michael.thaler () ph ! tum ! de>
Date:       2004-09-22 8:30:46
Message-ID: 200409221030.47038.michael.thaler () physik ! tu-muenchen ! de
[Download RAW message or body]

Hello,

I moved the scaling code to a visitor. Please copy the attached files to 
krita/core/ (or maybe better to krita/core/visitors, but I don't know how to 
set up the automake stuff...) and apply the attached patch.

I will work on progress info for the scaling code next. Then I try to 
implement simple image rotation. There is an advanced algorith which works 
really good, which is explained in Graphics Gems I, but unfortunately someone 
borrowed the book from our library and I will have to wait until mid of 
october to get the book.

Michael

["kis_scale_visitor.h" (text/x-chdr)]

/*
 *  copyright (c) 2004 Michael Thaler <michael.thaler@physik.tu-muenchen.de>
 *
 *  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.
 */
#ifndef KIS_SCALE_VISITOR_H_
#define KIS_SCALE_VISITOR_H_

#include "kis_types.h"
#include "kis_paint_device.h"

class KisScaleVisitor {
        
        /* Structs for the image rescaling routine */
	struct CONTRIB {
		Q_INT32 m_pixel;
		double m_weight;
	};
 
	struct CLIST {
		Q_INT32  n;  //number of contributors
		CONTRIB *p; //pointer to list of contributions
	};
public:
        KisScaleVisitor();
        ~KisScaleVisitor();
        void visitKisPaintDevice(KisPaintDevice* dev);
        void scale(double sx, double sy);
private:
        KisPaintDevice* m_dev;
        
        
        /**
	 * calc_x_contrib()
	 *       
	 * Calculates the filter weights for a single target column.
	 * contribX->p must be freed afterwards.
	 *
	 * Returns -1 if error, 0 otherwise.
	 */
                
        int calc_x_contrib(CLIST *contribX, double xcale, double fwidth, int \
dstwidth, int srcwidth, double (KisScaleVisitor::*filterf)(double), Q_INT32 i);

	/* scaling filter function definitions */
	double filter(double t);
	double box_filter(double t);
	double triangle_filter(double t);
	double bell_filter(double t);
	double B_spline_filter(double t);
	double sinc(double x);
	double Lanczos3_filter(double t);
	double Mitchell_filter(double t);

        CLIST * contrib;  //array of contribution lists
};

inline KisScaleVisitor::KisScaleVisitor()
{
}

inline KisScaleVisitor::~KisScaleVisitor()
{
}

inline void KisScaleVisitor::visitKisPaintDevice(KisPaintDevice* dev)
{
        m_dev=dev;
}
#endif // KIS_SCALE_VISITOR_H_


["kis_scale_visitor.cc" (text/x-c++src)]

/*
 *  Copyright (c) 2004 Michael Thaler <michael.thaler@physik.tu-muenchen.de>
 *
 *  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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
#include <qwmatrix.h>

#include <kdebug.h>

#include "kis_scale_visitor.h"

void KisScaleVisitor::scale(double xscale, double yscale) 
{
        
        //define filter supports
        const double filter_support=1.0;
        const double box_support=0.5;
        const double triangle_support=1.0;
        const double bell_support=1.5;
        const double B_spline_support=2.0;
        const double Lanczos3_support=3.0;
        const double Mitchell_support=2.0;
       
        double (KisScaleVisitor::*filterf)(double) = \
&KisScaleVisitor::Mitchell_filter; //pointer to filter function  double fwidth;
        
        // target image data
        Q_INT32 targetW;
        Q_INT32 targetH;
        
        // compute size of target image
        // (this bit seems to be mostly from QImage.xForm)
        QWMatrix scale_matrix;
	scale_matrix.scale(xscale, yscale);
        scale_matrix = QPixmap::trueMatrix( scale_matrix, m_dev->width(), \
m_dev->height() );  if ( scale_matrix.m11() == 1.0F && scale_matrix.m22() == 1.0F ) {
                kdDebug() << "Identity matrix, do nothing.\n";
                return;
        }
        targetW = qRound( scale_matrix.m11() * m_dev->width() );
        targetH = qRound( scale_matrix.m22() * m_dev->height() );
        targetW = QABS( targetW );
        targetH = QABS( targetH );

        //set filter type
        enum filterType {
                BOX_FILTER,
                TRIANGLE_FILTER,
                BELL_FILTER,
                B_SPLINE_FILTER,
                FILTER,
                LANCZOS3_FILTER,
                MITCHELL_FILTER
        };
        filterType filter=MITCHELL_FILTER;
        switch(filter){
                case BOX_FILTER: filterf=&KisScaleVisitor::box_filter; \
                fwidth=box_support; break;
                case TRIANGLE_FILTER: filterf=&KisScaleVisitor::triangle_filter; \
                fwidth=triangle_support; break;
                case BELL_FILTER: filterf=&KisScaleVisitor::bell_filter; \
                fwidth=bell_support; break;
                case B_SPLINE_FILTER: filterf=&KisScaleVisitor::B_spline_filter; \
                fwidth=B_spline_support; break;
                case FILTER: filterf=&KisScaleVisitor::filter; fwidth=filter_support; \
                break;
                case LANCZOS3_FILTER: filterf=&KisScaleVisitor::Lanczos3_filter; \
                fwidth=Lanczos3_support; break;
                case MITCHELL_FILTER: filterf=&KisScaleVisitor::Mitchell_filter; \
fwidth=Mitchell_support; break;  }
         
        KisTileMgrSP tm = new KisTileMgr(m_dev -> colorStrategy() -> depth(), \
                targetW, targetH);
        QUANTUM * newData = new QUANTUM[targetW * targetH * m_dev -> depth() * \
sizeof(QUANTUM)];  int n;				/* pixel number */
        double center, left, right;	/* filter calculation variables */
        double m_width, fscale, weight[m_dev -> depth()];	/* filter calculation \
variables */  QUANTUM *pel = new QUANTUM[m_dev -> depth() * sizeof(QUANTUM)];
        QUANTUM *pel2 = new QUANTUM[m_dev -> depth() * sizeof(QUANTUM)];
        bool bPelDelta[m_dev -> depth()];
        CLIST	*contribY;		/* array of contribution lists */
        CLIST	contribX;
        int		nRet = -1;
        const Q_INT32 BLACK_PIXEL=0;
        const Q_INT32 WHITE_PIXEL=255;
        
        
        // create intermediate column to hold horizontal dst column zoom
        QUANTUM * tmp = new QUANTUM[m_dev -> height() * m_dev -> depth() * \
sizeof(QUANTUM)];  
        /* Build y weights */
        /* pre-calculate filter contributions for a column */
        contribY = (CLIST *)calloc(targetH, sizeof(CLIST));
        int k;
        
        if(yscale < 1.0)
        {
                m_width = fwidth / yscale;
                fscale = 1.0 / yscale;
                for(int y = 0; y < targetH; y++)
                {
                        contribY[y].n = 0;
                        contribY[y].p = (CONTRIB *)calloc((int) (m_width * 2 + 1), \
sizeof(CONTRIB));  center = (double) y / yscale;
                        left = ceil(center - m_width);
                        right = floor(center + m_width);
                        for(int xx = (int)left; xx <= right; xx++) {
                                weight[0] = center - (double) xx;
                                weight[0] = (this->*filterf)(weight[0] / fscale) / \
fscale;  if(xx < 0) {
                                        n = -xx;
                                } else if(xx >= m_dev -> height()) {
                                        n = (m_dev -> height() - xx) + m_dev -> \
height() - 1;  } else {
                                        n = xx;
                                }
                                k = contribY[y].n++;
                                contribY[y].p[k].m_pixel = n;
                                contribY[y].p[k].m_weight = weight[0];
                        }
                }
        } else {
                for(int y = 0; y < targetH; y++) {
                        contribY[y].n = 0;
                        contribY[y].p = (CONTRIB *)calloc((int) (fwidth * 2 + 1), \
sizeof(CONTRIB));  center = (double) y / yscale;
                        left = ceil(center - fwidth);
                        right = floor(center + fwidth);
                        for(int xx = (int)left; xx <= right; xx++) {
                                weight[0] = center - (double) xx;
                                weight[0] = (this->*filterf)(weight[0]);
                                if(xx < 0) {
                                        n = -xx;
                                } else if(xx >= m_dev -> height()) {
                                        n = (m_dev -> height() - xx) + m_dev -> \
height() - 1;  } else {
                                        n = xx;
                                }
                                k = contribY[y].n++;
                                contribY[y].p[k].m_pixel = n;
                                contribY[y].p[k].m_weight = weight[0];
                        }
                }
        }


        for(int x = 0; x < targetW; x++)
        {
                calc_x_contrib(&contribX, xscale, fwidth, targetW, m_dev -> width(), \
filterf, x);  /* Apply horz filter to make dst column in tmp. */
                for(int y = 0; y < m_dev -> height(); y++)
                {
                        for(int channel = 0; channel < m_dev -> depth(); channel++){
                                weight[channel] = 0.0;
                                bPelDelta[channel] = FALSE;
                        }
                        m_dev -> tiles() -> readPixelData(contribX.p[0].m_pixel, y, \
contribX.p[0].m_pixel, y, pel, m_dev -> depth());  for(int xx = 0; xx < contribX.n; \
xx++)  {
                                if (!(contribX.p[xx].m_pixel < 0 || \
                contribX.p[xx].m_pixel >= m_dev -> width())){
                                        m_dev -> \
tiles()->readPixelData(contribX.p[xx].m_pixel, y, contribX.p[xx].m_pixel, y, pel2, \
                m_dev -> depth());
                                        for(int channel = 0; channel < m_dev -> \
depth(); channel++)  {
                                                if(pel2[channel] != pel[channel]) \
                bPelDelta[channel] = TRUE;
                                                weight[channel] += pel2[channel] * \
contribX.p[xx].m_weight;  }
                                }
                        }
                        
                        for(int channel = 0; channel < m_dev -> depth(); channel++){
                                weight[channel] = bPelDelta[channel] ? \
                static_cast<int>(qRound(weight[channel])) : pel[channel];
                                tmp[y*m_dev -> depth()+channel] = \
static_cast<QUANTUM>(CLAMP(weight[channel], BLACK_PIXEL, WHITE_PIXEL));  }
                } /* next row in temp column */
                free(contribX.p);

                /* The temp column has been built. Now stretch it 
                vertically into dst column. */
                for(int y = 0; y < targetH; y++)
                {
                        for(int channel = 0; channel < m_dev -> depth(); channel++){
                                weight[channel] = 0.0;
                                bPelDelta[channel] = FALSE;
                                pel[channel] = tmp[contribY[y].p[0].m_pixel*m_dev -> \
depth()+channel];  }
                        for(int xx = 0; xx < contribY[y].n; xx++)
                        {
                                for(int channel = 0; channel < m_dev -> depth(); \
                channel++){
                                        pel2[channel] = \
                tmp[contribY[y].p[xx].m_pixel*m_dev -> depth()+channel];
                                        if(pel2[channel] != pel[channel]) \
                bPelDelta[channel] = TRUE;
                                        weight[channel] += pel2[channel] * \
contribY[y].p[xx].m_weight;  }
                        }
                        for(int channel = 0; channel < m_dev -> depth(); channel++){
                                weight[channel] = bPelDelta[channel] ? \
                static_cast<int>(qRound(weight[channel])) : pel[channel];
                                int currentPos = (y*targetW+x) * m_dev -> depth(); // \
                try to be at least a little efficient
                                if (weight[channel]<0) newData[currentPos + channel] \
                = 0;
                                else if (weight[channel]>255) newData[currentPos + \
                channel] = 255;
                                else newData[currentPos + channel] = \
(uchar)weight[channel];  }
                } /* next dst row */
        } /* next dst column */
        tm -> writePixelData(0, 0, targetW - 1, targetH - 1, newData, targetW * m_dev \
-> depth());  m_dev -> setTiles(tm); // Also sets width and height correctly
        nRet = 0; /* success */

        free(tmp);

        /* free the memory allocated for vertical filter weights */
        for(int y = 0; y < targetH; y++)
                free(contribY[y].p);
        free(contribY);

        //return nRet;
        return;
}

int KisScaleVisitor::calc_x_contrib(CLIST *contribX, double xscale, double fwidth, \
int /*dstwidth*/, int srcwidth, double (KisScaleVisitor::*filterf)(double), Q_INT32 \
x) {
        //CLIST* contribX: receiver of contrib info
        //double xscale: horizontal zooming scale
        //double fwidth: Filter sampling width
        //int dstwidth: Target bitmap width
        //int srcwidth: Source bitmap width
        //double (*filterf)(double): Filter proc
        //int i: Pixel column in source bitmap being processed
        
        double width;
        double fscale;
        double center, left, right;
        double weight;
        Q_INT32 k, n;

        if(xscale < 1.0)
        {
                /* Shrinking image */
                width = fwidth / xscale;
                fscale = 1.0 / xscale;

                contribX->n = 0;
                contribX->p = (CONTRIB *)calloc((int) (width * 2 + 1), \
sizeof(CONTRIB));  center = (double) x / xscale;
                left = ceil(center - width);
                right = floor(center + width);
                for(int xx = (int)left; xx <= right; ++xx)
                {
                        weight = center - (double) xx;
                        weight = (this->*filterf)(weight / fscale) / fscale;
                        if(xx < 0)
                                n = -xx;
                        else if(xx >= srcwidth)
                                n = (srcwidth - xx) + srcwidth - 1;
                        else                                                          \
  n = xx;

                        k = contribX->n++;
                        contribX->p[k].m_pixel = n;
                        contribX->p[k].m_weight = weight;
                }
        }
        else
        {
                /* Expanding image */
                contribX->n = 0;
                contribX->p = (CONTRIB *)calloc((int) (fwidth * 2 + 1), \
sizeof(CONTRIB));  center = (double) x / xscale;
                left = ceil(center - fwidth);
                right = floor(center + fwidth);

                for(int xx = (int)left; xx <= right; ++xx)
                {
                        weight = center - (double) xx;
                        weight = (this->*filterf)(weight);
                        if(xx < 0) {
                                n = -xx;
                        } else if(xx >= srcwidth) {
                                n = (srcwidth - xx) + srcwidth - 1;
                        } else {
                                n = xx;
                        }
                        k = contribX->n++;
                        contribX->p[k].m_pixel = n;
                        contribX->p[k].m_weight = weight;
                }
        }
        return 0;
} /* calc_x_contrib */

/* Filter function definitions */

double KisScaleVisitor::filter(double t)
{
        /* f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 */
        if(t < 0.0) t = -t;
        if(t < 1.0) return((2.0 * t - 3.0) * t * t + 1.0);
        return(0.0);
}

double KisScaleVisitor::box_filter(double t)
{
        if((t > -0.5) && (t <= 0.5)) return(1.0);
        return(0.0);
}

double KisScaleVisitor::triangle_filter(double t)
{
        if(t < 0.0) t = -t;
        if(t < 1.0) return(1.0 - t);
        return(0.0);
}

double KisScaleVisitor::bell_filter(double t)
{
        if(t < 0) t = -t;
        if(t < .5) return(.75 - (t * t));
        if(t < 1.5) {
                t = (t - 1.5);
                return(.5 * (t * t));
        }
        return(0.0);
}

double KisScaleVisitor::B_spline_filter(double t)
{
        double tt;

        if(t < 0) t = -t;
        if(t < 1) {
                tt = t * t;
                return((.5 * tt * t) - tt + (2.0 / 3.0));
        } else if(t < 2) {
                t = 2 - t;
                return((1.0 / 6.0) * (t * t * t));
        }
        return(0.0);
}

double KisScaleVisitor::sinc(double x)
{
        const double pi=3.1415926535897932385;
        x *= pi;
        if(x != 0) return(sin(x) / x);
        return(1.0);
}

double KisScaleVisitor::Lanczos3_filter(double t)
{
        if(t < 0) t = -t;
        if(t < 3.0) return(sinc(t) * sinc(t/3.0));
        return(0.0);
}

double KisScaleVisitor::Mitchell_filter(double t)
{
        const double B=1.0/3.0;
        const double C=1.0/3.0;
        double tt;

        tt = t * t;
        if(t < 0) t = -t;
        if(t < 1.0) {
                t = (((12.0 - 9.0 * B - 6.0 * C) * (t * tt)) + ((-18.0 + 12.0 * B + \
6.0 * C) * tt) + (6.0 - 2 * B));  return(t / 6.0);
        } else if(t < 2.0) {
                t = (((-1.0 * B - 6.0 * C) * (t * tt)) + ((6.0 * B + 30.0 * C) * tt) \
+ ((-12.0 * B - 48.0 * C) * t) + (8.0 * B + 24 * C));  return(t / 6.0);
                }
        return(0.0);
}


["mydiff" (text/x-diff)]

? mydiff
? core/kis_scale_visitor.cc
? core/kis_scale_visitor.h
Index: core/Makefile.am
===================================================================
RCS file: /home/kde/koffice/krita/core/Makefile.am,v
retrieving revision 1.111
diff -u -3 -u -p -r1.111 Makefile.am
--- core/Makefile.am	21 Sep 2004 09:41:44 -0000	1.111
+++ core/Makefile.am	22 Sep 2004 08:22:37 -0000
@@ -72,8 +72,8 @@ libkritacore_la_SOURCES = kis_paint_devi
 	kis_filter.cc \
 	kis_plugin_registry.cc \
 	kis_filter_registry.cc \
-	kis_selection_manager.cc
-
+	kis_selection_manager.cc \
+        kis_scale_visitor.cc
 
 noinst_HEADERS = kis_paint_device.h \
 	kis_layer.h \
@@ -111,8 +111,9 @@ noinst_HEADERS = kis_paint_device.h \
 	kis_matrix.h \
 	kis_filter.h \
 	kis_filter_registry.h \
-	kis_selection_manager.h
-
+	kis_selection_manager.h \
+        kis_scale_visitor.h
+        
 libkritacore_la_METASOURCES = AUTO
 libkritacore_la_LDFLAGS = $(all_libraries)
 SUBDIRS = tiles builder strategy color_strategy paintop resources tool
Index: core/kis_paint_device.cc
===================================================================
RCS file: /home/kde/koffice/krita/core/kis_paint_device.cc,v
retrieving revision 1.98
diff -u -3 -u -p -r1.98 kis_paint_device.cc
--- core/kis_paint_device.cc	20 Sep 2004 18:21:52 -0000	1.98
+++ core/kis_paint_device.cc	22 Sep 2004 08:22:38 -0000
@@ -307,355 +307,16 @@ void KisPaintDevice::resize(Q_INT32 w, Q
         painter.end();
 }
 
-void KisPaintDevice::scale(double xscale, double yscale) 
+void KisPaintDevice::accept(KisScaleVisitor& visitor)
 {
-        
-        //define filter supports
-        const double filter_support=1.0;
-        const double box_support=0.5;
-        const double triangle_support=1.0;
-        const double bell_support=1.5;
-        const double B_spline_support=2.0;
-        const double Lanczos3_support=3.0;
-        const double Mitchell_support=2.0;
-       
-        double (KisPaintDevice::*filterf)(double) = \
                &KisPaintDevice::Mitchell_filter; //pointer to filter function
-        double fwidth;
-        
-        // target image data
-        Q_INT32 targetW;
-        Q_INT32 targetH;
-        
-        // compute size of target image
-        // (this bit seems to be mostly from QImage.xForm)
-        QWMatrix scale_matrix;
-	scale_matrix.scale(xscale, yscale);
-        scale_matrix = QPixmap::trueMatrix( scale_matrix, width(), height() );
-        if ( scale_matrix.m11() == 1.0F && scale_matrix.m22() == 1.0F ) {
-                kdDebug() << "Identity matrix, do nothing.\n";
-                return;
-        }
-        targetW = qRound( scale_matrix.m11() * width() );
-        targetH = qRound( scale_matrix.m22() * height() );
-        targetW = QABS( targetW );
-        targetH = QABS( targetH );
-
-        //set filter type
-        enum filterType {
-                BOX_FILTER,
-                TRIANGLE_FILTER,
-                BELL_FILTER,
-                B_SPLINE_FILTER,
-                FILTER,
-                LANCZOS3_FILTER,
-                MITCHELL_FILTER
-        };
-        filterType filter=MITCHELL_FILTER;
-        switch(filter){
-                case BOX_FILTER: filterf=&KisPaintDevice::box_filter; \
                fwidth=box_support; break;
-                case TRIANGLE_FILTER: filterf=&KisPaintDevice::triangle_filter; \
                fwidth=triangle_support; break;
-                case BELL_FILTER: filterf=&KisPaintDevice::bell_filter; \
                fwidth=bell_support; break;
-                case B_SPLINE_FILTER: filterf=&KisPaintDevice::B_spline_filter; \
                fwidth=B_spline_support; break;
-                case FILTER: filterf=&KisPaintDevice::filter; fwidth=filter_support; \
                break;
-                case LANCZOS3_FILTER: filterf=&KisPaintDevice::Lanczos3_filter; \
                fwidth=Lanczos3_support; break;
-                case MITCHELL_FILTER: filterf=&KisPaintDevice::Mitchell_filter; \
                fwidth=Mitchell_support; break;
-        }
-         
-        KisTileMgrSP tm = new KisTileMgr(colorStrategy() -> depth(), targetW, \
                targetH);
-        QUANTUM * newData = new QUANTUM[targetW * targetH * depth() * \
                sizeof(QUANTUM)];
-        int n;				/* pixel number */
-        double center, left, right;	/* filter calculation variables */
-        double m_width, fscale, weight[depth()];	/* filter calculation variables */
-        QUANTUM *pel = new QUANTUM[depth() * sizeof(QUANTUM)];
-        QUANTUM *pel2 = new QUANTUM[depth() * sizeof(QUANTUM)];
-        bool bPelDelta[depth()];
-        CLIST	*contribY;		/* array of contribution lists */
-        CLIST	contribX;
-        int		nRet = -1;
-        const Q_INT32 BLACK_PIXEL=0;
-        const Q_INT32 WHITE_PIXEL=255;
-        
-        
-        // create intermediate column to hold horizontal dst column zoom
-        QUANTUM * tmp = new QUANTUM[height() * depth() * sizeof(QUANTUM)];
-        
-        /* Build y weights */
-        /* pre-calculate filter contributions for a column */
-        contribY = (CLIST *)calloc(targetH, sizeof(CLIST));
-        int k;
-        if(yscale < 1.0)
-        {
-                m_width = fwidth / yscale;
-                fscale = 1.0 / yscale;
-                for(int y = 0; y < targetH; y++)
-                {
-                        contribY[y].n = 0;
-                        contribY[y].p = (CONTRIB *)calloc((int) (m_width * 2 + 1), \
                sizeof(CONTRIB));
-                        center = (double) y / yscale;
-                        left = ceil(center - m_width);
-                        right = floor(center + m_width);
-                        for(int xx = (int)left; xx <= right; xx++) {
-                                weight[0] = center - (double) xx;
-                                weight[0] = (this->*filterf)(weight[0] / fscale) / \
                fscale;
-                                if(xx < 0) {
-                                        n = -xx;
-                                } else if(xx >= height()) {
-                                        n = (height() - xx) + height() - 1;
-                                } else {
-                                        n = xx;
-                                }
-                                k = contribY[y].n++;
-                                contribY[y].p[k].m_pixel = n;
-                                contribY[y].p[k].m_weight = weight[0];
-                        }
-                }
-        } else {
-                for(int y = 0; y < targetH; y++) {
-                        contribY[y].n = 0;
-                        contribY[y].p = (CONTRIB *)calloc((int) (fwidth * 2 + 1), \
                sizeof(CONTRIB));
-                        center = (double) y / yscale;
-                        left = ceil(center - fwidth);
-                        right = floor(center + fwidth);
-                        for(int xx = (int)left; xx <= right; xx++) {
-                                weight[0] = center - (double) xx;
-                                weight[0] = (this->*filterf)(weight[0]);
-                                if(xx < 0) {
-                                        n = -xx;
-                                } else if(xx >= height()) {
-                                        n = (height() - xx) + height() - 1;
-                                } else {
-                                        n = xx;
-                                }
-                                k = contribY[y].n++;
-                                contribY[y].p[k].m_pixel = n;
-                                contribY[y].p[k].m_weight = weight[0];
-                        }
-                }
-        }
-
-
-        for(int x = 0; x < targetW; x++)
-        {
-                calc_x_contrib(&contribX, xscale, fwidth, targetW, width(), filterf, \
                x);
-                /* Apply horz filter to make dst column in tmp. */
-                for(int y = 0; y < height(); y++)
-                {
-                        for(int channel = 0; channel < depth(); channel++){
-                                weight[channel] = 0.0;
-                                bPelDelta[channel] = FALSE;
-                        }
-                        tiles()->readPixelData(contribX.p[0].m_pixel, y, \
                contribX.p[0].m_pixel, y, pel, depth());
-                        for(int xx = 0; xx < contribX.n; xx++)
-                        {
-                                if (!(contribX.p[xx].m_pixel < 0 || \
                contribX.p[xx].m_pixel >= width())){
-                                        \
tiles()->readPixelData(contribX.p[xx].m_pixel, y, contribX.p[xx].m_pixel, y, pel2, \
                depth());
-                                        for(int channel = 0; channel < depth(); \
                channel++)
-                                        {
-                                                if(pel2[channel] != pel[channel]) \
                bPelDelta[channel] = TRUE;
-                                                weight[channel] += pel2[channel] * \
                contribX.p[xx].m_weight;
-                                        }
-                                }
-                        }
-                        
-                        for(int channel = 0; channel < depth(); channel++){
-                                weight[channel] = bPelDelta[channel] ? \
                static_cast<int>(qRound(weight[channel])) : pel[channel];
-                                tmp[y*depth()+channel] = \
                static_cast<QUANTUM>(CLAMP(weight[channel], BLACK_PIXEL, \
                WHITE_PIXEL));
-                        }
-                } /* next row in temp column */
-                free(contribX.p);
-
-                /* The temp column has been built. Now stretch it 
-                vertically into dst column. */
-                for(int y = 0; y < targetH; y++)
-                {
-                        for(int channel = 0; channel < depth(); channel++){
-                                weight[channel] = 0.0;
-                                bPelDelta[channel] = FALSE;
-                                pel[channel] = \
                tmp[contribY[y].p[0].m_pixel*depth()+channel];
-                        }
-                        for(int xx = 0; xx < contribY[y].n; xx++)
-                        {
-                                for(int channel = 0; channel < depth(); channel++){
-                                        pel2[channel] = \
                tmp[contribY[y].p[xx].m_pixel*depth()+channel];
-                                        if(pel2[channel] != pel[channel]) \
                bPelDelta[channel] = TRUE;
-                                        weight[channel] += pel2[channel] * \
                contribY[y].p[xx].m_weight;
-                                }
-                        }
-                        for(int channel = 0; channel < depth(); channel++){
-                                weight[channel] = bPelDelta[channel] ? \
                static_cast<int>(qRound(weight[channel])) : pel[channel];
-                                int currentPos = (y*targetW+x) * depth(); // try to \
                be at least a little efficient
-                                if (weight[channel]<0) newData[currentPos + channel] \
                = 0;
-                                else if (weight[channel]>255) newData[currentPos + \
                channel] = 255;
-                                else newData[currentPos + channel] = \
                (uchar)weight[channel];
-                       }
-                } /* next dst row */
-        } /* next dst column */
-        tm -> writePixelData(0, 0, targetW - 1, targetH - 1, newData, targetW * \
                depth());
-        setTiles(tm); // Also sets width and height correctly
-        nRet = 0; /* success */
-
-        free(tmp);
-
-        /* free the memory allocated for vertical filter weights */
-        for(int y = 0; y < targetH; y++)
-                free(contribY[y].p);
-        free(contribY);
-
-        //return nRet;
-        return;
-}
-
-int KisPaintDevice::calc_x_contrib(CLIST *contribX, double xscale, double fwidth, \
                int /*dstwidth*/, int srcwidth, double \
                (KisPaintDevice::*filterf)(double), Q_INT32 x)
-{
-        //CLIST* contribX: receiver of contrib info
-        //double xscale: horizontal zooming scale
-        //double fwidth: Filter sampling width
-        //int dstwidth: Target bitmap width
-        //int srcwidth: Source bitmap width
-        //double (*filterf)(double): Filter proc
-        //int i: Pixel column in source bitmap being processed
-        
-        double width;
-        double fscale;
-        double center, left, right;
-        double weight;
-        Q_INT32 k, n;
-
-        if(xscale < 1.0)
-        {
-                /* Shrinking image */
-                width = fwidth / xscale;
-                fscale = 1.0 / xscale;
-
-                contribX->n = 0;
-                contribX->p = (CONTRIB *)calloc((int) (width * 2 + 1), \
                sizeof(CONTRIB));
-                center = (double) x / xscale;
-                left = ceil(center - width);
-                right = floor(center + width);
-                for(int xx = (int)left; xx <= right; ++xx)
-                {
-                        weight = center - (double) xx;
-                        weight = (this->*filterf)(weight / fscale) / fscale;
-                        if(xx < 0)
-                                n = -xx;
-                        else if(xx >= srcwidth)
-                                n = (srcwidth - xx) + srcwidth - 1;
-                        else                                                         \
                
-                                n = xx;
-
-                        k = contribX->n++;
-                        contribX->p[k].m_pixel = n;
-                        contribX->p[k].m_weight = weight;
-                }
-        }
-        else
-        {
-                /* Expanding image */
-                contribX->n = 0;
-                contribX->p = (CONTRIB *)calloc((int) (fwidth * 2 + 1), \
                sizeof(CONTRIB));
-                center = (double) x / xscale;
-                left = ceil(center - fwidth);
-                right = floor(center + fwidth);
-
-                for(int xx = (int)left; xx <= right; ++xx)
-                {
-                        weight = center - (double) xx;
-                        weight = (this->*filterf)(weight);
-                        if(xx < 0) {
-                                n = -xx;
-                        } else if(xx >= srcwidth) {
-                                n = (srcwidth - xx) + srcwidth - 1;
-                        } else {
-                                n = xx;
-                        }
-                        k = contribX->n++;
-                        contribX->p[k].m_pixel = n;
-                        contribX->p[k].m_weight = weight;
-                }
-        }
-        return 0;
-} /* calc_x_contrib */
-
-/* Filter function definitions */
-
-double KisPaintDevice::filter(double t)
-{
-        /* f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 */
-        if(t < 0.0) t = -t;
-        if(t < 1.0) return((2.0 * t - 3.0) * t * t + 1.0);
-        return(0.0);
+        visitor.visitKisPaintDevice(this);
 }
 
-double KisPaintDevice::box_filter(double t)
+void KisPaintDevice::scale(double xscale, double yscale)
 {
-        if((t > -0.5) && (t <= 0.5)) return(1.0);
-        return(0.0);
-}
-
-double KisPaintDevice::triangle_filter(double t)
-{
-        if(t < 0.0) t = -t;
-        if(t < 1.0) return(1.0 - t);
-        return(0.0);
-}
-
-double KisPaintDevice::bell_filter(double t)
-{
-        if(t < 0) t = -t;
-        if(t < .5) return(.75 - (t * t));
-        if(t < 1.5) {
-                t = (t - 1.5);
-                return(.5 * (t * t));
-        }
-        return(0.0);
-}
-
-double KisPaintDevice::B_spline_filter(double t)
-{
-        double tt;
-
-        if(t < 0) t = -t;
-        if(t < 1) {
-                tt = t * t;
-                return((.5 * tt * t) - tt + (2.0 / 3.0));
-        } else if(t < 2) {
-                t = 2 - t;
-                return((1.0 / 6.0) * (t * t * t));
-        }
-        return(0.0);
-}
-
-double KisPaintDevice::sinc(double x)
-{
-        const double pi=3.1415926535897932385;
-        x *= pi;
-        if(x != 0) return(sin(x) / x);
-        return(1.0);
-}
-
-double KisPaintDevice::Lanczos3_filter(double t)
-{
-        if(t < 0) t = -t;
-        if(t < 3.0) return(sinc(t) * sinc(t/3.0));
-        return(0.0);
-}
-
-double KisPaintDevice::Mitchell_filter(double t)
-{
-        const double B=1.0/3.0;
-        const double C=1.0/3.0;
-        double tt;
-
-        tt = t * t;
-        if(t < 0) t = -t;
-        if(t < 1.0) {
-                t = (((12.0 - 9.0 * B - 6.0 * C) * (t * tt)) + ((-18.0 + 12.0 * B + \
                6.0 * C) * tt) + (6.0 - 2 * B));
-                return(t / 6.0);
-        } else if(t < 2.0) {
-                t = (((-1.0 * B - 6.0 * C) * (t * tt)) + ((6.0 * B + 30.0 * C) * tt) \
                + ((-12.0 * B - 48.0 * C) * t) + (8.0 * B + 24 * C));
-                return(t / 6.0);
-                }
-        return(0.0);
+        KisScaleVisitor visitor;
+        accept(visitor);
+        visitor.scale(xscale,yscale);
 }
 
 void KisPaintDevice::rotate(double angle) 
Index: core/kis_paint_device.h
===================================================================
RCS file: /home/kde/koffice/krita/core/kis_paint_device.h,v
retrieving revision 1.77
diff -u -3 -u -p -r1.77 kis_paint_device.h
--- core/kis_paint_device.h	20 Sep 2004 18:21:52 -0000	1.77
+++ core/kis_paint_device.h	22 Sep 2004 08:22:38 -0000
@@ -34,6 +34,7 @@
 #include "kistilemgr.h"
 #include "kis_strategy_colorspace.h"
 #include "kispixeldata.h"
+#include "kis_scale_visitor.h"
 
 class QImage;
 class QSize;
@@ -44,6 +45,7 @@ class QWMatrix;
 class KisTileCommand;
 class KisIteratorLineQuantum;
 class KisIteratorLinePixel;
+class KisScaleVisitor;
 
 /**
  * Class modelled on QPaintDevice.
@@ -52,19 +54,6 @@ class KisPaintDevice : public QObject, p
         Q_OBJECT
         typedef KisRenderInterface super;
 
-	/* Structs for the image rescaling routine */
-	struct CONTRIB {
-		Q_INT32 m_pixel;
-		double m_weight;
-	};
- 
-	struct CLIST {
-		Q_INT32  n;  //number of contributors
-		CONTRIB *p; //pointer to list of contributions
-	};
-
-
-
 public:
 	KisPaintDevice(Q_INT32 width, Q_INT32 height,
 			KisStrategyColorSpaceSP colorStrategy,
@@ -290,26 +279,6 @@ private:
         KisPaintDevice& operator=(const KisPaintDevice&);
         void init();
 
-	/**
-	 * calc_x_contrib()
-	 *       
-	 * Calculates the filter weights for a single target column.
-	 * contribX->p must be freed afterwards.
-	 *
-	 * Returns -1 if error, 0 otherwise.
-	 */
-	int calc_x_contrib(CLIST *contribX, double xcale, double fwidth, int dstwidth, int \
                srcwidth, double (KisPaintDevice::*filterf)(double), Q_INT32 i);
-
-	/* scaling filter function definitions */
-	double filter(double t);
-	double box_filter(double t);
-	double triangle_filter(double t);
-	double bell_filter(double t);
-	double B_spline_filter(double t);
-	double sinc(double x);
-	double Lanczos3_filter(double t);
-	double Mitchell_filter(double t);
-
 private:
         KisImage *m_owner;
         KisTileMgrSP m_tiles;
@@ -327,10 +296,7 @@ private:
 	CompositeOp m_compositeOp;
 	KisStrategyColorSpaceSP m_colorStrategy; 
 
-        
-	CLIST * contrib;  //array of contribution lists
-
-
+        void accept(KisScaleVisitor &);
 
 };
 



_______________________________________________
kimageshop mailing list
kimageshop@kde.org
https://mail.kde.org/mailman/listinfo/kimageshop


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic