krita
kis_scale_visitor.cc00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <qdatetime.h>
00019
00020 #include <kdebug.h>
00021 #include <klocale.h>
00022
00023 #include "kis_paint_device.h"
00024 #include "kis_scale_visitor.h"
00025 #include "kis_filter_strategy.h"
00026
00027
00028 void KisScaleWorker::run()
00029 {
00030 double fwidth = m_filterStrategy->support();
00031
00032 QRect rect = m_dev -> exactBounds();
00033 Q_INT32 width = rect.width();
00034 Q_INT32 height = rect.height();
00035 m_pixelSize=m_dev -> pixelSize();
00036
00037
00038 if ( m_sx == 1.0F && m_sy == 1.0F ) {
00039 return;
00040 }
00041 Q_INT32 targetW = QABS( qRound( m_sx * width ) );
00042 Q_INT32 targetH = QABS( qRound( m_sy * height ) );
00043
00044 Q_UINT8* newData = new Q_UINT8[targetW * targetH * m_pixelSize ];
00045 Q_CHECK_PTR(newData);
00046
00047 double* weight = new double[ m_pixelSize ];
00048
00049 Q_UINT8* pel = new Q_UINT8[ m_pixelSize ];
00050 Q_CHECK_PTR(pel);
00051
00052 Q_UINT8 *pel2 = new Q_UINT8[ m_pixelSize ];
00053 Q_CHECK_PTR(pel2);
00054
00055 bool* bPelDelta = new bool[ m_pixelSize ];
00056 ContribList *contribX;
00057 ContribList contribY;
00058 const Q_INT32 BLACK_PIXEL=0;
00059 const Q_INT32 WHITE_PIXEL=255;
00060
00061
00062
00063 Q_UINT8 * tmp = new Q_UINT8[ width * m_pixelSize ];
00064 Q_CHECK_PTR(tmp);
00065
00066
00067 Q_UINT8 **tmpRows = new Q_UINT8*[ height ];
00068
00069
00070 Q_UINT8 **tmpRowsMem;
00071 if(m_sy < 1.0)
00072 {
00073 tmpRowsMem = new Q_UINT8*[ (int)(fwidth / m_sy * 2 + 1) ];
00074 for(int i = 0; i < (int)(fwidth / m_sy * 2 + 1); i++)
00075 {
00076 tmpRowsMem[i] = new Q_UINT8[ width * m_pixelSize ];
00077 Q_CHECK_PTR(tmpRowsMem[i]);
00078 }
00079 }
00080 else
00081 {
00082 tmpRowsMem = new Q_UINT8*[ (int)(fwidth * 2 + 1) ];
00083 for(int i = 0; i < (int)(fwidth * 2 + 1); i++)
00084 {
00085 tmpRowsMem[i] = new Q_UINT8[ width * m_pixelSize ];
00086 Q_CHECK_PTR(tmpRowsMem[i]);
00087 }
00088 }
00089
00090
00091 contribX = new ContribList[ targetW ];
00092 for(int x = 0; x < targetW; x++)
00093 {
00094 calcContrib(&contribX[x], m_sx, fwidth, width, m_filterStrategy, x);
00095 }
00096
00097 QTime starttime = QTime::currentTime ();
00098
00099 for(int y = 0; y < targetH; y++)
00100 {
00101
00102 calcContrib(&contribY, m_sy, fwidth, height, m_filterStrategy, y);
00103
00104
00105 for(int srcpos = 0; srcpos < contribY.n; srcpos++)
00106 {
00107 if (!(contribY.p[srcpos].m_pixel < 0 || contribY.p[srcpos].m_pixel >= height))
00108 {
00109 tmpRows[contribY.p[srcpos].m_pixel] = new Q_UINT8[ width * m_pixelSize ];
00110
00111 m_dev ->readBytes(tmpRows[contribY.p[srcpos].m_pixel], 0, contribY.p[srcpos].m_pixel, width, 1);
00112 }
00113 }
00114
00115
00116 for(int x = 0; x < width; x++)
00117 {
00118 for(int channel = 0; channel < m_pixelSize; channel++){
00119 weight[channel] = 0.0;
00120 bPelDelta[channel] = FALSE;
00121 pel[channel]=tmpRows[contribY.p[0].m_pixel][ x * m_pixelSize + channel ];
00122 }
00123 for(int srcpos = 0; srcpos < contribY.n; srcpos++)
00124 {
00125 if (!(contribY.p[srcpos].m_pixel < 0 || contribY.p[srcpos].m_pixel >= height)){
00126 for(int channel = 0; channel < m_pixelSize; channel++)
00127 {
00128 pel2[channel]=tmpRows[contribY.p[srcpos].m_pixel][ x * m_pixelSize + channel ];
00129 if(pel2[channel] != pel[channel]) bPelDelta[channel] = TRUE;
00130 weight[channel] += pel2[channel] * contribY.p[srcpos].m_weight;
00131 }
00132 }
00133 }
00134
00135 for(int channel = 0; channel < m_pixelSize; channel++){
00136 weight[channel] = bPelDelta[channel] ? static_cast<int>(qRound(weight[channel])) : pel[channel];
00137 tmp[ x * m_pixelSize + channel ] = static_cast<Q_UINT8>(CLAMP(weight[channel], BLACK_PIXEL, WHITE_PIXEL));
00138 }
00139 }
00140 delete[] contribY.p;
00141
00142 for(int x = 0; x < targetW; x++)
00143 {
00144 for(int channel = 0; channel < m_pixelSize; channel++){
00145 weight[channel] = 0.0;
00146 bPelDelta[channel] = FALSE;
00147 pel[channel] = tmp[ contribX[x].p[0].m_pixel * m_pixelSize + channel ];
00148 }
00149 for(int srcpos = 0; srcpos < contribX[x].n; srcpos++)
00150 {
00151 for(int channel = 0; channel < m_pixelSize; channel++){
00152 pel2[channel] = tmp[ contribX[x].p[srcpos].m_pixel * m_pixelSize + channel ];
00153 if(pel2[channel] != pel[channel])
00154 bPelDelta[channel] = TRUE;
00155 weight[channel] += pel2[channel] * contribX[x].p[srcpos].m_weight;
00156 }
00157 }
00158 for(int channel = 0; channel < m_pixelSize; channel++){
00159 weight[channel] = bPelDelta[channel] ? static_cast<int>(qRound(weight[channel])) : pel[channel];
00160 int currentPos = (y*targetW+x) * m_pixelSize;
00161 if (weight[channel]<0)
00162 newData[currentPos + channel] = 0;
00163 else if (weight[channel]>255)
00164 newData[currentPos + channel] = 255;
00165 else
00166 newData[currentPos + channel] = (uchar)weight[channel];
00167 }
00168 }
00169 }
00170
00171
00172 if(!isCanceled()){
00173 m_dev -> writeBytes( newData, 0, 0, targetW, targetH);
00174 m_dev -> crop(0, 0, targetW, targetH);
00175 }
00176
00177
00178 for(int x = 0; x < targetW; x++)
00179 delete[] contribX[x].p;
00180 delete[] contribX;
00181
00182 delete[] newData;
00183 delete[] pel;
00184 delete[] pel2;
00185 delete[] tmp;
00186 delete[] weight;
00187 delete[] bPelDelta;
00188
00189 if(m_sy < 1.0)
00190 {
00191 for(int i = 0; i < (int)(fwidth / m_sy * 2 + 1); i++)
00192 {
00193 delete[] tmpRowsMem[i];
00194 }
00195 }
00196 else
00197 {
00198 for(int i = 0; i < (int)(fwidth * 2 + 1); i++)
00199 {
00200 delete[] tmpRowsMem[i];
00201 }
00202 }
00203
00204 QTime stoptime = QTime::currentTime ();
00205 return;
00206 }
00207
00208 int KisScaleWorker::calcContrib(ContribList *contrib, double scale, double fwidth, int srcwidth, KisFilterStrategy* filterStrategy, Q_INT32 i)
00209 {
00210
00211
00212
00213
00214
00215
00216
00217
00218 double width;
00219 double fscale;
00220 double center, begin, end;
00221 double weight;
00222 Q_INT32 k, n;
00223
00224 if(scale < 1.0)
00225 {
00226
00227 width = fwidth / scale;
00228 fscale = 1.0 / scale;
00229
00230 contrib->n = 0;
00231 contrib->p = new Contrib[ (int)(width * 2 + 1) ];
00232
00233 center = (double) i / scale;
00234 begin = ceil(center - width);
00235 end = floor(center + width);
00236 for(int srcpos = (int)begin; srcpos <= end; ++srcpos)
00237 {
00238 weight = center - (double) srcpos;
00239 weight = filterStrategy->valueAt(weight / fscale) / fscale;
00240 if(srcpos < 0)
00241 n = -srcpos;
00242 else if(srcpos >= srcwidth)
00243 n = (srcwidth - srcpos) + srcwidth - 1;
00244 else
00245 n = srcpos;
00246
00247 k = contrib->n++;
00248 contrib->p[k].m_pixel = n;
00249 contrib->p[k].m_weight = weight;
00250 }
00251 }
00252 else
00253 {
00254
00255 contrib->n = 0;
00256 contrib->p = new Contrib[ (int)(fwidth * 2 + 1) ];
00257
00258 center = (double) i / scale;
00259 begin = ceil(center - fwidth);
00260 end = floor(center + fwidth);
00261
00262 for(int srcpos = (int)begin; srcpos <= end; ++srcpos)
00263 {
00264 weight = center - (double) srcpos;
00265 weight = filterStrategy->valueAt(weight);
00266 if(srcpos < 0) {
00267 n = -srcpos;
00268 } else if(srcpos >= srcwidth) {
00269 n = (srcwidth - srcpos) + srcwidth - 1;
00270 } else {
00271 n = srcpos;
00272 }
00273 k = contrib->n++;
00274 contrib->p[k].m_pixel = n;
00275 contrib->p[k].m_weight = weight;
00276 }
00277 }
00278 return 0;
00279 }
|