00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026
00027 #ifdef HAVE_SYS_TYPES_H
00028 #include <sys/types.h>
00029 #endif
00030
00031 #include <netinet/in.h>
00032 #include <limits.h>
00033 #include <stdlib.h>
00034 #include <cfloat>
00035
00036 #include <qfile.h>
00037 #include <qimage.h>
00038 #include <qpoint.h>
00039 #include <qvaluevector.h>
00040
00041 #include <kdebug.h>
00042 #include <klocale.h>
00043
00044 #include <kis_meta_registry.h>
00045 #include "kis_paint_device.h"
00046 #include "kis_global.h"
00047 #include "kis_brush.h"
00048 #include "kis_alpha_mask.h"
00049 #include "kis_colorspace_factory_registry.h"
00050 #include "kis_iterators_pixel.h"
00051 #include "kis_image.h"
00052
00053
00054 namespace {
00055 struct GimpBrushV1Header {
00056 Q_UINT32 header_size;
00057 Q_UINT32 version;
00058 Q_UINT32 width;
00059 Q_UINT32 height;
00060 Q_UINT32 bytes;
00061 };
00062
00064 struct GimpBrushHeader {
00065 Q_UINT32 header_size;
00066 Q_UINT32 version;
00067 Q_UINT32 width;
00068 Q_UINT32 height;
00069 Q_UINT32 bytes;
00070
00071
00072 Q_UINT32 magic_number;
00073 Q_UINT32 spacing;
00074 };
00075
00076
00077 Q_UINT32 const GimpV2BrushMagic = ('G' << 24) + ('I' << 16) + ('M' << 8) + ('P' << 0);
00078 }
00079
00080 #define DEFAULT_SPACING 0.25
00081 #define MAXIMUM_SCALE 2
00082
00083 KisBrush::KisBrush(const QString& filename) : super(filename)
00084 {
00085 m_brushType = INVALID;
00086 m_ownData = true;
00087 m_useColorAsMask = false;
00088 m_hasColor = false;
00089 m_spacing = DEFAULT_SPACING;
00090 m_boundary = 0;
00091 }
00092
00093 KisBrush::KisBrush(const QString& filename,
00094 const QByteArray& data,
00095 Q_UINT32 & dataPos) : super(filename)
00096 {
00097 m_brushType = INVALID;
00098 m_ownData = false;
00099 m_useColorAsMask = false;
00100 m_hasColor = false;
00101 m_spacing = DEFAULT_SPACING;
00102 m_boundary = 0;
00103
00104 m_data.setRawData(data.data() + dataPos, data.size() - dataPos);
00105 init();
00106 m_data.resetRawData(data.data() + dataPos, data.size() - dataPos);
00107 dataPos += m_header_size + (width() * height() * m_bytes);
00108 }
00109
00110 KisBrush::KisBrush(KisPaintDevice* image, int x, int y, int w, int h)
00111 : super(QString(""))
00112 {
00113 m_brushType = INVALID;
00114 m_ownData = true;
00115 m_useColorAsMask = false;
00116 m_hasColor = true;
00117 m_spacing = DEFAULT_SPACING;
00118 m_boundary = 0;
00119
00120 initFromPaintDev(image, x, y, w, h);
00121 }
00122
00123 KisBrush::KisBrush(const QImage& image, const QString& name)
00124 : super(QString(""))
00125 {
00126 m_ownData = false;
00127 m_useColorAsMask = false;
00128 m_hasColor = true;
00129 m_spacing = DEFAULT_SPACING;
00130 m_boundary = 0;
00131
00132 setImage(image);
00133 setName(name);
00134 setBrushType(IMAGE);
00135 }
00136
00137
00138 KisBrush::~KisBrush()
00139 {
00140 m_scaledBrushes.clear();
00141 delete m_boundary;
00142 }
00143
00144 bool KisBrush::load()
00145 {
00146 if (m_ownData) {
00147 QFile file(filename());
00148 file.open(IO_ReadOnly);
00149 m_data = file.readAll();
00150 file.close();
00151 }
00152 return init();
00153 }
00154
00155 bool KisBrush::init()
00156 {
00157 GimpBrushHeader bh;
00158
00159 if (sizeof(GimpBrushHeader) > m_data.size()) {
00160 return false;
00161 }
00162
00163 memcpy(&bh, &m_data[0], sizeof(GimpBrushHeader));
00164 bh.header_size = ntohl(bh.header_size);
00165 m_header_size = bh.header_size;
00166
00167 bh.version = ntohl(bh.version);
00168 m_version = bh.version;
00169
00170 bh.width = ntohl(bh.width);
00171 bh.height = ntohl(bh.height);
00172
00173 bh.bytes = ntohl(bh.bytes);
00174 m_bytes = bh.bytes;
00175
00176 bh.magic_number = ntohl(bh.magic_number);
00177 m_magic_number = bh.magic_number;
00178
00179 if (bh.version == 1) {
00180
00181 bh.spacing = static_cast<int>(DEFAULT_SPACING * 100);
00182 }
00183 else {
00184 bh.spacing = ntohl(bh.spacing);
00185
00186 if (bh.spacing > 1000) {
00187 return false;
00188 }
00189 }
00190
00191 setSpacing(bh.spacing / 100.0);
00192
00193 if (bh.header_size > m_data.size() || bh.header_size == 0) {
00194 return false;
00195 }
00196
00197 QString name;
00198
00199 if (bh.version == 1) {
00200
00201
00202 const char *text = &m_data[sizeof(GimpBrushV1Header)];
00203 name = QString::fromAscii(text, bh.header_size - sizeof(GimpBrushV1Header));
00204 } else {
00205
00206
00207 name = QString::fromUtf8(&m_data[sizeof(GimpBrushHeader)],
00208 bh.header_size - sizeof(GimpBrushHeader));
00209 }
00210
00211 setName(i18n(name.ascii()));
00212
00213 if (bh.width == 0 || bh.height == 0 || !m_img.create(bh.width, bh.height, 32)) {
00214 return false;
00215 }
00216
00217 Q_INT32 k = bh.header_size;
00218
00219 if (bh.bytes == 1) {
00220
00221
00222 if (static_cast<Q_UINT32>(k + bh.width * bh.height) > m_data.size()) {
00223 return false;
00224 }
00225
00226 m_brushType = MASK;
00227 m_hasColor = false;
00228
00229 for (Q_UINT32 y = 0; y < bh.height; y++) {
00230 for (Q_UINT32 x = 0; x < bh.width; x++, k++) {
00231 Q_INT32 val = 255 - static_cast<uchar>(m_data[k]);
00232 m_img.setPixel(x, y, qRgb(val, val, val));
00233 }
00234 }
00235 } else if (bh.bytes == 4) {
00236
00237
00238 if (static_cast<Q_UINT32>(k + (bh.width * bh.height * 4)) > m_data.size()) {
00239 return false;
00240 }
00241
00242 m_brushType = IMAGE;
00243 m_img.setAlphaBuffer(true);
00244 m_hasColor = true;
00245
00246 for (Q_UINT32 y = 0; y < bh.height; y++) {
00247 for (Q_UINT32 x = 0; x < bh.width; x++, k += 4) {
00248 m_img.setPixel(x, y, qRgba(m_data[k],
00249 m_data[k+1],
00250 m_data[k+2],
00251 m_data[k+3]));
00252 }
00253 }
00254 } else {
00255 return false;
00256 }
00257
00258 setWidth(m_img.width());
00259 setHeight(m_img.height());
00260
00261 if (m_ownData) {
00262 m_data.resize(0);
00263 }
00264
00265
00266 if (m_img.width() == 0 || m_img.height() == 0)
00267 setValid(false);
00268 else
00269 setValid(true);
00270
00271 return true;
00272 }
00273
00274 bool KisBrush::initFromPaintDev(KisPaintDevice* image, int x, int y, int w, int h) {
00275
00276
00277 setImage(image->convertToQImage(0, x, y, w, h));
00278 setName(image->name());
00279
00280 m_brushType = IMAGE;
00281 m_hasColor = true;
00282
00283 return true;
00284 }
00285
00286 bool KisBrush::save()
00287 {
00288 QFile file(filename());
00289 file.open(IO_WriteOnly | IO_Truncate);
00290 bool ok = saveToDevice(&file);
00291 file.close();
00292 return ok;
00293 }
00294
00295 bool KisBrush::saveToDevice(QIODevice* dev) const
00296 {
00297 GimpBrushHeader bh;
00298 QCString utf8Name = name().utf8();
00299 char const* name = utf8Name.data();
00300 int nameLength = qstrlen(name);
00301 int wrote;
00302
00303 bh.header_size = htonl(sizeof(GimpBrushHeader) + nameLength);
00304 bh.version = htonl(2);
00305 bh.width = htonl(width());
00306 bh.height = htonl(height());
00307
00308 if (!hasColor())
00309 bh.bytes = htonl(1);
00310 else
00311 bh.bytes = htonl(4);
00312 bh.magic_number = htonl(GimpV2BrushMagic);
00313 bh.spacing = htonl(static_cast<Q_UINT32>(spacing() * 100.0));
00314
00315
00316 QByteArray bytes;
00317 bytes.setRawData(reinterpret_cast<char*>(&bh), sizeof(GimpBrushHeader));
00318 wrote = dev->writeBlock(bytes);
00319 bytes.resetRawData(reinterpret_cast<char*>(&bh), sizeof(GimpBrushHeader));
00320
00321 if (wrote == -1)
00322 return false;
00323
00324 wrote = dev->writeBlock(name, nameLength);
00325 if (wrote == -1)
00326 return false;
00327
00328 int k = 0;
00329
00330 if (!hasColor()) {
00331 bytes.resize(width() * height());
00332 for (Q_INT32 y = 0; y < height(); y++) {
00333 for (Q_INT32 x = 0; x < width(); x++) {
00334 QRgb c = m_img.pixel(x, y);
00335 bytes[k++] = static_cast<char>(255 - qRed(c));
00336 }
00337 }
00338 } else {
00339 bytes.resize(width() * height() * 4);
00340 for (Q_INT32 y = 0; y < height(); y++) {
00341 for (Q_INT32 x = 0; x < width(); x++) {
00342
00343 QRgb pixel = m_img.pixel(x,y);
00344 bytes[k++] = static_cast<char>(qRed(pixel));
00345 bytes[k++] = static_cast<char>(qGreen(pixel));
00346 bytes[k++] = static_cast<char>(qBlue(pixel));
00347 bytes[k++] = static_cast<char>(qAlpha(pixel));
00348 }
00349 }
00350 }
00351
00352 wrote = dev->writeBlock(bytes);
00353 if (wrote == -1)
00354 return false;
00355
00356 return true;
00357 }
00358
00359 QImage KisBrush::img()
00360 {
00361 QImage image = m_img;
00362
00363 if (hasColor() && useColorAsMask()) {
00364 image.detach();
00365
00366 for (int x = 0; x < image.width(); x++) {
00367 for (int y = 0; y < image.height(); y++) {
00368 QRgb c = image.pixel(x, y);
00369 int a = (qGray(c) * qAlpha(c)) / 255;
00370 image.setPixel(x, y, qRgba(a, 0, a, a));
00371 }
00372 }
00373 }
00374
00375 return image;
00376 }
00377
00378 KisAlphaMaskSP KisBrush::mask(const KisPaintInformation& info, double subPixelX, double subPixelY) const
00379 {
00380 if (m_scaledBrushes.isEmpty()) {
00381 createScaledBrushes();
00382 }
00383
00384 double scale = scaleForPressure(info.pressure);
00385
00386 const ScaledBrush *aboveBrush = 0;
00387 const ScaledBrush *belowBrush = 0;
00388
00389 findScaledBrushes(scale, &aboveBrush, &belowBrush);
00390 Q_ASSERT(aboveBrush != 0);
00391
00392 KisAlphaMaskSP outputMask = 0;
00393
00394 if (belowBrush != 0) {
00395
00396
00397 KisAlphaMaskSP scaledAboveMask = scaleMask(aboveBrush, scale, subPixelX, subPixelY);
00398 KisAlphaMaskSP scaledBelowMask = scaleMask(belowBrush, scale, subPixelX, subPixelY);
00399
00400 double t = (scale - belowBrush->scale()) / (aboveBrush->scale() - belowBrush->scale());
00401
00402 outputMask = KisAlphaMask::interpolate(scaledBelowMask, scaledAboveMask, t);
00403 } else {
00404 if (fabs(scale - aboveBrush->scale()) < DBL_EPSILON) {
00405
00406 outputMask = scaleMask(aboveBrush, scale, subPixelX, subPixelY);
00407 } else {
00408
00409 double s = scale / aboveBrush->scale();
00410 outputMask = scaleSinglePixelMask(s, aboveBrush->mask()->alphaAt(0, 0), subPixelX, subPixelY);
00411 }
00412 }
00413
00414 return outputMask;
00415 }
00416
00417 KisPaintDeviceSP KisBrush::image(KisColorSpace * , const KisPaintInformation& info, double subPixelX, double subPixelY) const
00418 {
00419 if (m_scaledBrushes.isEmpty()) {
00420 createScaledBrushes();
00421 }
00422
00423 double scale = scaleForPressure(info.pressure);
00424
00425 const ScaledBrush *aboveBrush = 0;
00426 const ScaledBrush *belowBrush = 0;
00427
00428 findScaledBrushes(scale, &aboveBrush, &belowBrush);
00429 Q_ASSERT(aboveBrush != 0);
00430
00431 QImage outputImage;
00432
00433 if (belowBrush != 0) {
00434
00435
00436 QImage scaledAboveImage = scaleImage(aboveBrush, scale, subPixelX, subPixelY);
00437 QImage scaledBelowImage = scaleImage(belowBrush, scale, subPixelX, subPixelY);
00438
00439 double t = (scale - belowBrush->scale()) / (aboveBrush->scale() - belowBrush->scale());
00440
00441 outputImage = interpolate(scaledBelowImage, scaledAboveImage, t);
00442 } else {
00443 if (fabs(scale - aboveBrush->scale()) < DBL_EPSILON) {
00444
00445 outputImage = scaleImage(aboveBrush, scale, subPixelX, subPixelY);
00446 } else {
00447
00448 double s = scale / aboveBrush->scale();
00449 outputImage = scaleSinglePixelImage(s, aboveBrush->image().pixel(0, 0), subPixelX, subPixelY);
00450 }
00451 }
00452
00453 int outputWidth = outputImage.width();
00454 int outputHeight = outputImage.height();
00455
00456 KisPaintDevice *layer = new KisPaintDevice(KisMetaRegistry::instance()->csRegistry()->getRGB8(), "brush");
00457
00458 Q_CHECK_PTR(layer);
00459
00460 for (int y = 0; y < outputHeight; y++) {
00461 KisHLineIterator iter = layer->createHLineIterator( 0, y, outputWidth, true);
00462 for (int x = 0; x < outputWidth; x++) {
00463 Q_UINT8 * p = iter.rawData();
00464
00465 QRgb pixel = outputImage.pixel(x, y);
00466 int red = qRed(pixel);
00467 int green = qGreen(pixel);
00468 int blue = qBlue(pixel);
00469 int alpha = qAlpha(pixel);
00470
00471
00472
00473
00474 if (alpha != 0) {
00475 p[2] = (red * 255) / alpha;
00476 p[1] = (green * 255) / alpha;
00477 p[0] = (blue * 255) / alpha;
00478 p[3] = alpha;
00479 }
00480
00481 ++iter;
00482 }
00483 }
00484
00485 return layer;
00486 }
00487
00488 void KisBrush::setHotSpot(KisPoint pt)
00489 {
00490 double x = pt.x();
00491 double y = pt.y();
00492
00493 if (x < 0)
00494 x = 0;
00495 else if (x >= width())
00496 x = width() - 1;
00497
00498 if (y < 0)
00499 y = 0;
00500 else if (y >= height())
00501 y = height() - 1;
00502
00503 m_hotSpot = KisPoint(x, y);
00504 }
00505
00506 KisPoint KisBrush::hotSpot(const KisPaintInformation& info) const
00507 {
00508 double scale = scaleForPressure(info.pressure);
00509 double w = width() * scale;
00510 double h = height() * scale;
00511
00512
00513 if (w < 1) {
00514 w = 1;
00515 }
00516
00517 if (h < 1) {
00518 h = 1;
00519 }
00520
00521
00522
00523
00524 KisPoint p(w / 2, h / 2);
00525 return p;
00526 }
00527
00528 enumBrushType KisBrush::brushType() const
00529 {
00530 if (m_brushType == IMAGE && useColorAsMask()) {
00531 return MASK;
00532 }
00533 else {
00534 return m_brushType;
00535 }
00536 }
00537
00538 bool KisBrush::hasColor() const
00539 {
00540 return m_hasColor;
00541 }
00542
00543 void KisBrush::createScaledBrushes() const
00544 {
00545 if (!m_scaledBrushes.isEmpty())
00546 m_scaledBrushes.clear();
00547
00548
00549
00550 int width = m_img.width() * MAXIMUM_SCALE;
00551 int height = m_img.height() * MAXIMUM_SCALE;
00552
00553 QImage scaledImage;
00554
00555 while (true) {
00556
00557 if (width >= m_img.width() && height >= m_img.height()) {
00558 scaledImage = scaleImage(m_img, width, height);
00559 }
00560 else {
00561
00562 scaledImage = scaleImage(scaledImage, width, height);
00563 }
00564
00565 KisAlphaMaskSP scaledMask = new KisAlphaMask(scaledImage, hasColor());
00566 Q_CHECK_PTR(scaledMask);
00567
00568 double xScale = static_cast<double>(width) / m_img.width();
00569 double yScale = static_cast<double>(height) / m_img.height();
00570 double scale = xScale;
00571
00572 m_scaledBrushes.append(ScaledBrush(scaledMask, hasColor() ? scaledImage : QImage(), scale, xScale, yScale));
00573
00574 if (width == 1 && height == 1) {
00575 break;
00576 }
00577
00578
00579 width = (width + 1) / 2;
00580 height = (height + 1) / 2;
00581
00582 }
00583
00584 }
00585
00586 double KisBrush::xSpacing(double pressure) const
00587 {
00588 return width() * scaleForPressure(pressure) * m_spacing;
00589 }
00590
00591 double KisBrush::ySpacing(double pressure) const
00592 {
00593 return height() * scaleForPressure(pressure) * m_spacing;
00594 }
00595
00596 double KisBrush::scaleForPressure(double pressure)
00597 {
00598 double scale = pressure / PRESSURE_DEFAULT;
00599
00600 if (scale < 0) {
00601 scale = 0;
00602 }
00603
00604 if (scale > MAXIMUM_SCALE) {
00605 scale = MAXIMUM_SCALE;
00606 }
00607
00608 return scale;
00609 }
00610
00611 Q_INT32 KisBrush::maskWidth(const KisPaintInformation& info) const
00612 {
00613
00614 return static_cast<Q_INT32>(ceil(width() * scaleForPressure(info.pressure)) + 1);
00615 }
00616
00617 Q_INT32 KisBrush::maskHeight(const KisPaintInformation& info) const
00618 {
00619
00620 return static_cast<Q_INT32>(ceil(height() * scaleForPressure(info.pressure)) + 1);
00621 }
00622
00623 KisAlphaMaskSP KisBrush::scaleMask(const ScaledBrush *srcBrush, double scale, double subPixelX, double subPixelY) const
00624 {
00625
00626 int dstWidth = static_cast<int>(ceil(scale * width())) + 1;
00627 int dstHeight = static_cast<int>(ceil(scale * height())) + 1;
00628
00629 KisAlphaMaskSP dstMask = new KisAlphaMask(dstWidth, dstHeight);
00630 Q_CHECK_PTR(dstMask);
00631
00632 KisAlphaMaskSP srcMask = srcBrush->mask();
00633
00634
00635 double xScale = srcBrush->xScale() / scale;
00636 double yScale = srcBrush->yScale() / scale;
00637
00638 int srcWidth = srcMask->width();
00639 int srcHeight = srcMask->height();
00640
00641 for (int dstY = 0; dstY < dstHeight; dstY++) {
00642 for (int dstX = 0; dstX < dstWidth; dstX++) {
00643
00644 double srcX = (dstX - subPixelX + 0.5) * xScale;
00645 double srcY = (dstY - subPixelY + 0.5) * yScale;
00646
00647 srcX -= 0.5;
00648 srcY -= 0.5;
00649
00650 int leftX = static_cast<int>(srcX);
00651
00652 if (srcX < 0) {
00653 leftX--;
00654 }
00655
00656 double xInterp = srcX - leftX;
00657
00658 int topY = static_cast<int>(srcY);
00659
00660 if (srcY < 0) {
00661 topY--;
00662 }
00663
00664 double yInterp = srcY - topY;
00665
00666 Q_UINT8 topLeft = (leftX >= 0 && leftX < srcWidth && topY >= 0 && topY < srcHeight) ? srcMask->alphaAt(leftX, topY) : OPACITY_TRANSPARENT;
00667 Q_UINT8 bottomLeft = (leftX >= 0 && leftX < srcWidth && topY + 1 >= 0 && topY + 1 < srcHeight) ? srcMask->alphaAt(leftX, topY + 1) : OPACITY_TRANSPARENT;
00668 Q_UINT8 topRight = (leftX + 1 >= 0 && leftX + 1 < srcWidth && topY >= 0 && topY < srcHeight) ? srcMask->alphaAt(leftX + 1, topY) : OPACITY_TRANSPARENT;
00669 Q_UINT8 bottomRight = (leftX + 1 >= 0 && leftX + 1 < srcWidth && topY + 1 >= 0 && topY + 1 < srcHeight) ? srcMask->alphaAt(leftX + 1, topY + 1) : OPACITY_TRANSPARENT;
00670
00671 double a = 1 - xInterp;
00672 double b = 1 - yInterp;
00673
00674
00675 int d = static_cast<int>(a * b * topLeft
00676 + a * (1 - b) * bottomLeft
00677 + (1 - a) * b * topRight
00678 + (1 - a) * (1 - b) * bottomRight + 0.5);
00679
00680 if (d < OPACITY_TRANSPARENT) {
00681 d = OPACITY_TRANSPARENT;
00682 }
00683 else
00684 if (d > OPACITY_OPAQUE) {
00685 d = OPACITY_OPAQUE;
00686 }
00687
00688 dstMask->setAlphaAt(dstX, dstY, static_cast<Q_UINT8>(d));
00689 }
00690 }
00691
00692 return dstMask;
00693 }
00694
00695 QImage KisBrush::scaleImage(const ScaledBrush *srcBrush, double scale, double subPixelX, double subPixelY) const
00696 {
00697
00698 int dstWidth = static_cast<int>(ceil(scale * width())) + 1;
00699 int dstHeight = static_cast<int>(ceil(scale * height())) + 1;
00700
00701 QImage dstImage(dstWidth, dstHeight, 32);
00702 dstImage.setAlphaBuffer(true);
00703
00704 const QImage srcImage = srcBrush->image();
00705
00706
00707 double xScale = srcBrush->xScale() / scale;
00708 double yScale = srcBrush->yScale() / scale;
00709
00710 int srcWidth = srcImage.width();
00711 int srcHeight = srcImage.height();
00712
00713 for (int dstY = 0; dstY < dstHeight; dstY++) {
00714 for (int dstX = 0; dstX < dstWidth; dstX++) {
00715
00716 double srcX = (dstX - subPixelX + 0.5) * xScale;
00717 double srcY = (dstY - subPixelY + 0.5) * yScale;
00718
00719 srcX -= 0.5;
00720 srcY -= 0.5;
00721
00722 int leftX = static_cast<int>(srcX);
00723
00724 if (srcX < 0) {
00725 leftX--;
00726 }
00727
00728 double xInterp = srcX - leftX;
00729
00730 int topY = static_cast<int>(srcY);
00731
00732 if (srcY < 0) {
00733 topY--;
00734 }
00735
00736 double yInterp = srcY - topY;
00737
00738 QRgb topLeft = (leftX >= 0 && leftX < srcWidth && topY >= 0 && topY < srcHeight) ? srcImage.pixel(leftX, topY) : qRgba(0, 0, 0, 0);
00739 QRgb bottomLeft = (leftX >= 0 && leftX < srcWidth && topY + 1 >= 0 && topY + 1 < srcHeight) ? srcImage.pixel(leftX, topY + 1) : qRgba(0, 0, 0, 0);
00740 QRgb topRight = (leftX + 1 >= 0 && leftX + 1 < srcWidth && topY >= 0 && topY < srcHeight) ? srcImage.pixel(leftX + 1, topY) : qRgba(0, 0, 0, 0);
00741 QRgb bottomRight = (leftX + 1 >= 0 && leftX + 1 < srcWidth && topY + 1 >= 0 && topY + 1 < srcHeight) ? srcImage.pixel(leftX + 1, topY + 1) : qRgba(0, 0, 0, 0);
00742
00743 double a = 1 - xInterp;
00744 double b = 1 - yInterp;
00745
00746
00747 int red = static_cast<int>(a * b * qRed(topLeft)
00748 + a * (1 - b) * qRed(bottomLeft)
00749 + (1 - a) * b * qRed(topRight)
00750 + (1 - a) * (1 - b) * qRed(bottomRight) + 0.5);
00751 int green = static_cast<int>(a * b * qGreen(topLeft)
00752 + a * (1 - b) * qGreen(bottomLeft)
00753 + (1 - a) * b * qGreen(topRight)
00754 + (1 - a) * (1 - b) * qGreen(bottomRight) + 0.5);
00755 int blue = static_cast<int>(a * b * qBlue(topLeft)
00756 + a * (1 - b) * qBlue(bottomLeft)
00757 + (1 - a) * b * qBlue(topRight)
00758 + (1 - a) * (1 - b) * qBlue(bottomRight) + 0.5);
00759 int alpha = static_cast<int>(a * b * qAlpha(topLeft)
00760 + a * (1 - b) * qAlpha(bottomLeft)
00761 + (1 - a) * b * qAlpha(topRight)
00762 + (1 - a) * (1 - b) * qAlpha(bottomRight) + 0.5);
00763
00764 if (red < 0) {
00765 red = 0;
00766 }
00767 else
00768 if (red > 255) {
00769 red = 255;
00770 }
00771
00772 if (green < 0) {
00773 green = 0;
00774 }
00775 else
00776 if (green > 255) {
00777 green = 255;
00778 }
00779
00780 if (blue < 0) {
00781 blue = 0;
00782 }
00783 else
00784 if (blue > 255) {
00785 blue = 255;
00786 }
00787
00788 if (alpha < 0) {
00789 alpha = 0;
00790 }
00791 else
00792 if (alpha > 255) {
00793 alpha = 255;
00794 }
00795
00796 dstImage.setPixel(dstX, dstY, qRgba(red, green, blue, alpha));
00797 }
00798 }
00799
00800 return dstImage;
00801 }
00802
00803 QImage KisBrush::scaleImage(const QImage& srcImage, int width, int height)
00804 {
00805 QImage scaledImage;
00806
00807
00808 int srcWidth = srcImage.width();
00809 int srcHeight = srcImage.height();
00810
00811 double xScale = static_cast<double>(srcWidth) / width;
00812 double yScale = static_cast<double>(srcHeight) / height;
00813
00814 if (xScale > 2 + DBL_EPSILON || yScale > 2 + DBL_EPSILON || xScale < 1 - DBL_EPSILON || yScale < 1 - DBL_EPSILON) {
00815
00816
00817 scaledImage = srcImage.smoothScale(width, height);
00818
00819
00820 }
00821 else {
00822 scaledImage.create(width, height, 32);
00823 scaledImage.setAlphaBuffer(srcImage.hasAlphaBuffer());
00824
00825 for (int dstY = 0; dstY < height; dstY++) {
00826 for (int dstX = 0; dstX < width; dstX++) {
00827
00828 double srcX = (dstX + 0.5) * xScale;
00829 double srcY = (dstY + 0.5) * yScale;
00830
00831 srcX -= 0.5;
00832 srcY -= 0.5;
00833
00834 int leftX = static_cast<int>(srcX);
00835
00836 if (srcX < 0) {
00837 leftX--;
00838 }
00839
00840 double xInterp = srcX - leftX;
00841
00842 int topY = static_cast<int>(srcY);
00843
00844 if (srcY < 0) {
00845 topY--;
00846 }
00847
00848 double yInterp = srcY - topY;
00849
00850 QRgb topLeft = (leftX >= 0 && leftX < srcWidth && topY >= 0 && topY < srcHeight) ? srcImage.pixel(leftX, topY) : qRgba(0, 0, 0, 0);
00851 QRgb bottomLeft = (leftX >= 0 && leftX < srcWidth && topY + 1 >= 0 && topY + 1 < srcHeight) ? srcImage.pixel(leftX, topY + 1) : qRgba(0, 0, 0, 0);
00852 QRgb topRight = (leftX + 1 >= 0 && leftX + 1 < srcWidth && topY >= 0 && topY < srcHeight) ? srcImage.pixel(leftX + 1, topY) : qRgba(0, 0, 0, 0);
00853 QRgb bottomRight = (leftX + 1 >= 0 && leftX + 1 < srcWidth && topY + 1 >= 0 && topY + 1 < srcHeight) ? srcImage.pixel(leftX + 1, topY + 1) : qRgba(0, 0, 0, 0);
00854
00855 double a = 1 - xInterp;
00856 double b = 1 - yInterp;
00857
00858 int red;
00859 int green;
00860 int blue;
00861 int alpha;
00862
00863 if (srcImage.hasAlphaBuffer()) {
00864 red = static_cast<int>(a * b * qRed(topLeft) * qAlpha(topLeft)
00865 + a * (1 - b) * qRed(bottomLeft) * qAlpha(bottomLeft)
00866 + (1 - a) * b * qRed(topRight) * qAlpha(topRight)
00867 + (1 - a) * (1 - b) * qRed(bottomRight) * qAlpha(bottomRight) + 0.5);
00868 green = static_cast<int>(a * b * qGreen(topLeft) * qAlpha(topLeft)
00869 + a * (1 - b) * qGreen(bottomLeft) * qAlpha(bottomLeft)
00870 + (1 - a) * b * qGreen(topRight) * qAlpha(topRight)
00871 + (1 - a) * (1 - b) * qGreen(bottomRight) * qAlpha(bottomRight) + 0.5);
00872 blue = static_cast<int>(a * b * qBlue(topLeft) * qAlpha(topLeft)
00873 + a * (1 - b) * qBlue(bottomLeft) * qAlpha(bottomLeft)
00874 + (1 - a) * b * qBlue(topRight) * qAlpha(topRight)
00875 + (1 - a) * (1 - b) * qBlue(bottomRight) * qAlpha(bottomRight) + 0.5);
00876 alpha = static_cast<int>(a * b * qAlpha(topLeft)
00877 + a * (1 - b) * qAlpha(bottomLeft)
00878 + (1 - a) * b * qAlpha(topRight)
00879 + (1 - a) * (1 - b) * qAlpha(bottomRight) + 0.5);
00880
00881 if (alpha != 0) {
00882 red /= alpha;
00883 green /= alpha;
00884 blue /= alpha;
00885 }
00886 }
00887 else {
00888 red = static_cast<int>(a * b * qRed(topLeft)
00889 + a * (1 - b) * qRed(bottomLeft)
00890 + (1 - a) * b * qRed(topRight)
00891 + (1 - a) * (1 - b) * qRed(bottomRight) + 0.5);
00892 green = static_cast<int>(a * b * qGreen(topLeft)
00893 + a * (1 - b) * qGreen(bottomLeft)
00894 + (1 - a) * b * qGreen(topRight)
00895 + (1 - a) * (1 - b) * qGreen(bottomRight) + 0.5);
00896 blue = static_cast<int>(a * b * qBlue(topLeft)
00897 + a * (1 - b) * qBlue(bottomLeft)
00898 + (1 - a) * b * qBlue(topRight)
00899 + (1 - a) * (1 - b) * qBlue(bottomRight) + 0.5);
00900 alpha = 255;
00901 }
00902
00903 if (red < 0) {
00904 red = 0;
00905 }
00906 else
00907 if (red > 255) {
00908 red = 255;
00909 }
00910
00911 if (green < 0) {
00912 green = 0;
00913 }
00914 else
00915 if (green > 255) {
00916 green = 255;
00917 }
00918
00919 if (blue < 0) {
00920 blue = 0;
00921 }
00922 else
00923 if (blue > 255) {
00924 blue = 255;
00925 }
00926
00927 if (alpha < 0) {
00928 alpha = 0;
00929 }
00930 else
00931 if (alpha > 255) {
00932 alpha = 255;
00933 }
00934
00935 scaledImage.setPixel(dstX, dstY, qRgba(red, green, blue, alpha));
00936 }
00937 }
00938
00939
00940 }
00941
00942
00943
00944 return scaledImage;
00945 }
00946
00947 void KisBrush::findScaledBrushes(double scale, const ScaledBrush **aboveBrush, const ScaledBrush **belowBrush) const
00948 {
00949 uint current = 0;
00950
00951 while (true) {
00952 *aboveBrush = &(m_scaledBrushes[current]);
00953
00954 if (fabs((*aboveBrush)->scale() - scale) < DBL_EPSILON) {
00955
00956 break;
00957 }
00958
00959 if (current == m_scaledBrushes.count() - 1) {
00960
00961 break;
00962 }
00963
00964 if (scale > m_scaledBrushes[current + 1].scale() + DBL_EPSILON) {
00965
00966 *belowBrush = &(m_scaledBrushes[current + 1]);
00967 break;
00968 }
00969
00970 current++;
00971 }
00972 }
00973
00974 KisAlphaMaskSP KisBrush::scaleSinglePixelMask(double scale, Q_UINT8 maskValue, double subPixelX, double subPixelY)
00975 {
00976 int srcWidth = 1;
00977 int srcHeight = 1;
00978 int dstWidth = 2;
00979 int dstHeight = 2;
00980 KisAlphaMaskSP outputMask = new KisAlphaMask(dstWidth, dstHeight);
00981 Q_CHECK_PTR(outputMask);
00982
00983 double a = subPixelX;
00984 double b = subPixelY;
00985
00986 for (int y = 0; y < dstHeight; y++) {
00987 for (int x = 0; x < dstWidth; x++) {
00988
00989 Q_UINT8 topLeft = (x > 0 && y > 0) ? maskValue : OPACITY_TRANSPARENT;
00990 Q_UINT8 bottomLeft = (x > 0 && y < srcHeight) ? maskValue : OPACITY_TRANSPARENT;
00991 Q_UINT8 topRight = (x < srcWidth && y > 0) ? maskValue : OPACITY_TRANSPARENT;
00992 Q_UINT8 bottomRight = (x < srcWidth && y < srcHeight) ? maskValue : OPACITY_TRANSPARENT;
00993
00994
00995 int d = static_cast<int>(a * b * topLeft
00996 + a * (1 - b) * bottomLeft
00997 + (1 - a) * b * topRight
00998 + (1 - a) * (1 - b) * bottomRight + 0.5);
00999
01000
01001
01002 d = static_cast<int>(d * scale * scale + 0.5);
01003
01004 if (d < OPACITY_TRANSPARENT) {
01005 d = OPACITY_TRANSPARENT;
01006 }
01007 else
01008 if (d > OPACITY_OPAQUE) {
01009 d = OPACITY_OPAQUE;
01010 }
01011
01012 outputMask->setAlphaAt(x, y, static_cast<Q_UINT8>(d));
01013 }
01014 }
01015
01016 return outputMask;
01017 }
01018
01019 QImage KisBrush::scaleSinglePixelImage(double scale, QRgb pixel, double subPixelX, double subPixelY)
01020 {
01021 int srcWidth = 1;
01022 int srcHeight = 1;
01023 int dstWidth = 2;
01024 int dstHeight = 2;
01025
01026 QImage outputImage(dstWidth, dstHeight, 32);
01027 outputImage.setAlphaBuffer(true);
01028
01029 double a = subPixelX;
01030 double b = subPixelY;
01031
01032 for (int y = 0; y < dstHeight; y++) {
01033 for (int x = 0; x < dstWidth; x++) {
01034
01035 QRgb topLeft = (x > 0 && y > 0) ? pixel : qRgba(0, 0, 0, 0);
01036 QRgb bottomLeft = (x > 0 && y < srcHeight) ? pixel : qRgba(0, 0, 0, 0);
01037 QRgb topRight = (x < srcWidth && y > 0) ? pixel : qRgba(0, 0, 0, 0);
01038 QRgb bottomRight = (x < srcWidth && y < srcHeight) ? pixel : qRgba(0, 0, 0, 0);
01039
01040
01041 int red = static_cast<int>(a * b * qRed(topLeft)
01042 + a * (1 - b) * qRed(bottomLeft)
01043 + (1 - a) * b * qRed(topRight)
01044 + (1 - a) * (1 - b) * qRed(bottomRight) + 0.5);
01045 int green = static_cast<int>(a * b * qGreen(topLeft)
01046 + a * (1 - b) * qGreen(bottomLeft)
01047 + (1 - a) * b * qGreen(topRight)
01048 + (1 - a) * (1 - b) * qGreen(bottomRight) + 0.5);
01049 int blue = static_cast<int>(a * b * qBlue(topLeft)
01050 + a * (1 - b) * qBlue(bottomLeft)
01051 + (1 - a) * b * qBlue(topRight)
01052 + (1 - a) * (1 - b) * qBlue(bottomRight) + 0.5);
01053 int alpha = static_cast<int>(a * b * qAlpha(topLeft)
01054 + a * (1 - b) * qAlpha(bottomLeft)
01055 + (1 - a) * b * qAlpha(topRight)
01056 + (1 - a) * (1 - b) * qAlpha(bottomRight) + 0.5);
01057
01058
01059
01060 alpha = static_cast<int>(alpha * scale * scale + 0.5);
01061
01062
01063
01064 red = static_cast<int>(red * scale * scale + 0.5);
01065 green = static_cast<int>(green * scale * scale + 0.5);
01066 blue = static_cast<int>(blue * scale * scale + 0.5);
01067
01068 if (red < 0) {
01069 red = 0;
01070 }
01071 else
01072 if (red > 255) {
01073 red = 255;
01074 }
01075
01076 if (green < 0) {
01077 green = 0;
01078 }
01079 else
01080 if (green > 255) {
01081 green = 255;
01082 }
01083
01084 if (blue < 0) {
01085 blue = 0;
01086 }
01087 else
01088 if (blue > 255) {
01089 blue = 255;
01090 }
01091
01092 if (alpha < 0) {
01093 alpha = 0;
01094 }
01095 else
01096 if (alpha > 255) {
01097 alpha = 255;
01098 }
01099
01100 outputImage.setPixel(x, y, qRgba(red, green, blue, alpha));
01101 }
01102 }
01103
01104 return outputImage;
01105 }
01106
01107 QImage KisBrush::interpolate(const QImage& image1, const QImage& image2, double t)
01108 {
01109 Q_ASSERT((image1.width() == image2.width()) && (image1.height() == image2.height()));
01110 Q_ASSERT(t > -DBL_EPSILON && t < 1 + DBL_EPSILON);
01111
01112 int width = image1.width();
01113 int height = image1.height();
01114
01115 QImage outputImage(width, height, 32);
01116 outputImage.setAlphaBuffer(true);
01117
01118 for (int x = 0; x < width; x++) {
01119 for (int y = 0; y < height; y++) {
01120 QRgb image1pixel = image1.pixel(x, y);
01121 QRgb image2pixel = image2.pixel(x, y);
01122
01123
01124 int red = static_cast<int>((1 - t) * qRed(image1pixel) + t * qRed(image2pixel) + 0.5);
01125 int green = static_cast<int>((1 - t) * qGreen(image1pixel) + t * qGreen(image2pixel) + 0.5);
01126 int blue = static_cast<int>((1 - t) * qBlue(image1pixel) + t * qBlue(image2pixel) + 0.5);
01127 int alpha = static_cast<int>((1 - t) * qAlpha(image1pixel) + t * qAlpha(image2pixel) + 0.5);
01128
01129 if (red < 0) {
01130 red = 0;
01131 }
01132 else
01133 if (red > 255) {
01134 red = 255;
01135 }
01136
01137 if (green < 0) {
01138 green = 0;
01139 }
01140 else
01141 if (green > 255) {
01142 green = 255;
01143 }
01144
01145 if (blue < 0) {
01146 blue = 0;
01147 }
01148 else
01149 if (blue > 255) {
01150 blue = 255;
01151 }
01152
01153 if (alpha < 0) {
01154 alpha = 0;
01155 }
01156 else
01157 if (alpha > 255) {
01158 alpha = 255;
01159 }
01160
01161 outputImage.setPixel(x, y, qRgba(red, green, blue, alpha));
01162 }
01163 }
01164
01165 return outputImage;
01166 }
01167
01168 KisBrush::ScaledBrush::ScaledBrush()
01169 {
01170 m_mask = 0;
01171 m_image = QImage();
01172 m_scale = 1;
01173 m_xScale = 1;
01174 m_yScale = 1;
01175 }
01176
01177 KisBrush::ScaledBrush::ScaledBrush(KisAlphaMaskSP scaledMask, const QImage& scaledImage, double scale, double xScale, double yScale)
01178 {
01179 m_mask = scaledMask;
01180 m_image = scaledImage;
01181 m_scale = scale;
01182 m_xScale = xScale;
01183 m_yScale = yScale;
01184
01185 if (!m_image.isNull()) {
01186
01187
01188 m_image.detach();
01189
01190 for (int y = 0; y < m_image.height(); y++) {
01191 for (int x = 0; x < m_image.width(); x++) {
01192
01193 QRgb pixel = m_image.pixel(x, y);
01194
01195 int red = qRed(pixel);
01196 int green = qGreen(pixel);
01197 int blue = qBlue(pixel);
01198 int alpha = qAlpha(pixel);
01199
01200 red = (red * alpha) / 255;
01201 green = (green * alpha) / 255;
01202 blue = (blue * alpha) / 255;
01203
01204 m_image.setPixel(x, y, qRgba(red, green, blue, alpha));
01205 }
01206 }
01207 }
01208 }
01209
01210 void KisBrush::setImage(const QImage& img)
01211 {
01212 m_img = img;
01213 m_img.detach();
01214
01215 setWidth(img.width());
01216 setHeight(img.height());
01217
01218 m_scaledBrushes.clear();
01219
01220 setValid(true);
01221 }
01222
01223 Q_INT32 KisBrush::width() const
01224 {
01225 return m_width;
01226 }
01227
01228 void KisBrush::setWidth(Q_INT32 w)
01229 {
01230 m_width = w;
01231 }
01232
01233 Q_INT32 KisBrush::height() const
01234 {
01235 return m_height;
01236 }
01237
01238 void KisBrush::setHeight(Q_INT32 h)
01239 {
01240 m_height = h;
01241 }
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257 void KisBrush::generateBoundary() {
01258 KisPaintDeviceSP dev;
01259 int w = maskWidth(KisPaintInformation());
01260 int h = maskHeight(KisPaintInformation());
01261
01262 if (brushType() == IMAGE || brushType() == PIPE_IMAGE) {
01263 dev = image(KisMetaRegistry::instance()->csRegistry() ->getColorSpace(KisID("RGBA",""),""), KisPaintInformation());
01264 } else {
01265 KisAlphaMaskSP amask = mask(KisPaintInformation());
01266 KisColorSpace* cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA",""),"");
01267 dev = new KisPaintDevice(cs, "tmp for generateBoundary");
01268 for (int y = 0; y < h; y++) {
01269 KisHLineIteratorPixel it = dev->createHLineIterator(0, y, w, true);
01270 int x = 0;
01271
01272 while(!it.isDone()) {
01273 cs->setAlpha(it.rawData(), amask->alphaAt(x++, y), 1);
01274 ++it;
01275 }
01276 }
01277 }
01278
01279 m_boundary = new KisBoundary(dev);
01280 m_boundary->generateBoundary(w, h);
01281 }
01282
01283 KisBoundary KisBrush::boundary() {
01284 if (!m_boundary)
01285 generateBoundary();
01286 return *m_boundary;
01287 }
01288
01289 void KisBrush::makeMaskImage() {
01290 if (!hasColor())
01291 return;
01292
01293 QImage img;
01294 img.create(width(), height(), 32);
01295
01296 if (m_img.width() == img.width() && m_img.height() == img.height()) {
01297 for (int x = 0; x < width(); x++) {
01298 for (int y = 0; y < height(); y++) {
01299 QRgb c = m_img.pixel(x, y);
01300 int a = (qGray(c) * qAlpha(c)) / 255;
01301 img.setPixel(x, y, qRgba(a, a, a, 255));
01302 }
01303 }
01304
01305 m_img = img;
01306 }
01307
01308 m_brushType = MASK;
01309 m_hasColor = false;
01310 m_useColorAsMask = false;
01311 delete m_boundary;
01312 m_boundary = 0;
01313 m_scaledBrushes.clear();
01314 }
01315
01316 KisBrush* KisBrush::clone() const {
01317 KisBrush* c = new KisBrush("");
01318 c->m_spacing = m_spacing;
01319 c->m_useColorAsMask = m_useColorAsMask;
01320 c->m_hasColor = m_useColorAsMask;
01321 c->m_img = m_img;
01322 c->m_width = m_width;
01323 c->m_height = m_height;
01324 c->m_ownData = false;
01325 c->m_hotSpot = m_hotSpot;
01326 c->m_brushType = m_brushType;
01327 c->setValid(true);
01328
01329 return c;
01330 }
01331
01332 #include "kis_brush.moc"
01333