27#ifdef HAVE_SYS_TYPES_H
31#include <netinet/in.h>
39#include <tqvaluevector.h>
44#include <kis_meta_registry.h>
45#include "kis_paint_device.h"
46#include "kis_global.h"
48#include "kis_alpha_mask.h"
49#include "kis_colorspace_factory_registry.h"
50#include "kis_iterators_pixel.h"
55 struct GimpBrushV1Header {
56 TQ_UINT32 header_size;
64 struct GimpBrushHeader {
65 TQ_UINT32 header_size;
72 TQ_UINT32 magic_number;
77 TQ_UINT32
const GimpV2BrushMagic = (
'G' << 24) + (
'I' << 16) + (
'M' << 8) + (
'P' << 0);
80#define DEFAULT_SPACING 0.25
81#define MAXIMUM_SCALE 2
83KisBrush::KisBrush(
const TQString& filename) : super(filename)
85 m_brushType = INVALID;
87 m_useColorAsMask =
false;
89 m_spacing = DEFAULT_SPACING;
93KisBrush::KisBrush(
const TQString& filename,
94 const TQByteArray& data,
95 TQ_UINT32 & dataPos) : super(filename)
97 m_brushType = INVALID;
99 m_useColorAsMask =
false;
101 m_spacing = DEFAULT_SPACING;
104 m_data.setRawData(data.data() + dataPos, data.size() - dataPos);
106 m_data.resetRawData(data.data() + dataPos, data.size() - dataPos);
107 dataPos += m_header_size + (width() * height() * m_bytes);
110KisBrush::KisBrush(
KisPaintDevice* image,
int x,
int y,
int w,
int h)
111 : super(TQString(
""))
113 m_brushType = INVALID;
115 m_useColorAsMask =
false;
117 m_spacing = DEFAULT_SPACING;
120 initFromPaintDev(image, x, y, w, h);
123KisBrush::KisBrush(
const TQImage& image,
const TQString& name)
124 : super(TQString(
""))
127 m_useColorAsMask =
false;
129 m_spacing = DEFAULT_SPACING;
140 m_scaledBrushes.clear();
147 TQFile file(filename());
148 file.open(IO_ReadOnly);
149 m_data = file.readAll();
159 if (
sizeof(GimpBrushHeader) > m_data.size()) {
163 memcpy(&bh, &m_data[0],
sizeof(GimpBrushHeader));
164 bh.header_size = ntohl(bh.header_size);
165 m_header_size = bh.header_size;
167 bh.version = ntohl(bh.version);
168 m_version = bh.version;
170 bh.width = ntohl(bh.width);
171 bh.height = ntohl(bh.height);
173 bh.bytes = ntohl(bh.bytes);
176 bh.magic_number = ntohl(bh.magic_number);
177 m_magic_number = bh.magic_number;
179 if (bh.version == 1) {
181 bh.spacing =
static_cast<int>(DEFAULT_SPACING * 100);
184 bh.spacing = ntohl(bh.spacing);
186 if (bh.spacing > 1000) {
191 setSpacing(bh.spacing / 100.0);
193 if (bh.header_size > m_data.size() || bh.header_size == 0) {
199 if (bh.version == 1) {
202 const char *text = &m_data[
sizeof(GimpBrushV1Header)];
203 name = TQString::fromAscii(text, bh.header_size -
sizeof(GimpBrushV1Header));
207 name = TQString::fromUtf8(&m_data[
sizeof(GimpBrushHeader)],
208 bh.header_size -
sizeof(GimpBrushHeader));
211 setName(i18n(name.ascii()));
213 if (bh.width == 0 || bh.height == 0 || !m_img.create(bh.width, bh.height, 32)) {
217 TQ_INT32 k = bh.header_size;
222 if (
static_cast<TQ_UINT32
>(k + bh.width * bh.height) > m_data.size()) {
229 for (TQ_UINT32 y = 0; y < bh.height; y++) {
230 for (TQ_UINT32 x = 0; x < bh.width; x++, k++) {
231 TQ_INT32 val = 255 -
static_cast<uchar
>(m_data[k]);
232 m_img.setPixel(x, y, tqRgb(val, val, val));
235 }
else if (bh.bytes == 4) {
238 if (
static_cast<TQ_UINT32
>(k + (bh.width * bh.height * 4)) > m_data.size()) {
243 m_img.setAlphaBuffer(
true);
246 for (TQ_UINT32 y = 0; y < bh.height; y++) {
247 for (TQ_UINT32 x = 0; x < bh.width; x++, k += 4) {
248 m_img.setPixel(x, y, tqRgba(m_data[k],
258 setWidth(m_img.width());
259 setHeight(m_img.height());
266 if (m_img.width() == 0 || m_img.height() == 0)
274bool KisBrush::initFromPaintDev(
KisPaintDevice* image,
int x,
int y,
int w,
int h) {
277 setImage(image->convertToTQImage(0, x, y, w, h));
278 setName(image->name());
288 TQFile file(filename());
289 file.open(IO_WriteOnly | IO_Truncate);
290 bool ok = saveToDevice(&file);
295bool KisBrush::saveToDevice(TQIODevice* dev)
const
298 TQCString utf8Name = name().utf8();
299 char const* name = utf8Name.data();
300 int nameLength = tqstrlen(name);
303 bh.header_size = htonl(
sizeof(GimpBrushHeader) + nameLength);
304 bh.version = htonl(2);
305 bh.width = htonl(width());
306 bh.height = htonl(height());
312 bh.magic_number = htonl(GimpV2BrushMagic);
313 bh.spacing = htonl(
static_cast<TQ_UINT32
>(spacing() * 100.0));
317 bytes.setRawData(
reinterpret_cast<char*
>(&bh),
sizeof(GimpBrushHeader));
318 wrote = dev->writeBlock(bytes);
319 bytes.resetRawData(
reinterpret_cast<char*
>(&bh),
sizeof(GimpBrushHeader));
324 wrote = dev->writeBlock(name, nameLength);
331 bytes.resize(width() * height());
332 for (TQ_INT32 y = 0; y < height(); y++) {
333 for (TQ_INT32 x = 0; x < width(); x++) {
334 TQRgb c = m_img.pixel(x, y);
335 bytes[k++] =
static_cast<char>(255 - tqRed(c));
339 bytes.resize(width() * height() * 4);
340 for (TQ_INT32 y = 0; y < height(); y++) {
341 for (TQ_INT32 x = 0; x < width(); x++) {
343 TQRgb pixel = m_img.pixel(x,y);
344 bytes[k++] =
static_cast<char>(tqRed(pixel));
345 bytes[k++] =
static_cast<char>(tqGreen(pixel));
346 bytes[k++] =
static_cast<char>(tqBlue(pixel));
347 bytes[k++] =
static_cast<char>(tqAlpha(pixel));
352 wrote = dev->writeBlock(bytes);
361 TQImage image = m_img;
363 if (hasColor() && useColorAsMask()) {
366 for (
int x = 0; x < image.width(); x++) {
367 for (
int y = 0; y < image.height(); y++) {
368 TQRgb c = image.pixel(x, y);
369 int a = (tqGray(c) * tqAlpha(c)) / 255;
370 image.setPixel(x, y, tqRgba(a, 0, a, a));
378KisAlphaMaskSP KisBrush::mask(
const KisPaintInformation& info,
double subPixelX,
double subPixelY)
const
380 if (m_scaledBrushes.isEmpty()) {
381 createScaledBrushes();
384 double scale = scaleForPressure(info.pressure);
386 const ScaledBrush *aboveBrush = 0;
387 const ScaledBrush *belowBrush = 0;
389 findScaledBrushes(scale, &aboveBrush, &belowBrush);
390 Q_ASSERT(aboveBrush != 0);
392 KisAlphaMaskSP outputMask = 0;
394 if (belowBrush != 0) {
397 KisAlphaMaskSP scaledAboveMask = scaleMask(aboveBrush, scale, subPixelX, subPixelY);
398 KisAlphaMaskSP scaledBelowMask = scaleMask(belowBrush, scale, subPixelX, subPixelY);
400 double t = (scale - belowBrush->scale()) / (aboveBrush->scale() - belowBrush->scale());
402 outputMask = KisAlphaMask::interpolate(scaledBelowMask, scaledAboveMask, t);
404 if (fabs(scale - aboveBrush->scale()) < DBL_EPSILON) {
406 outputMask = scaleMask(aboveBrush, scale, subPixelX, subPixelY);
409 double s = scale / aboveBrush->scale();
410 outputMask = scaleSinglePixelMask(s, aboveBrush->mask()->alphaAt(0, 0), subPixelX, subPixelY);
419 if (m_scaledBrushes.isEmpty()) {
420 createScaledBrushes();
423 double scale = scaleForPressure(info.pressure);
425 const ScaledBrush *aboveBrush = 0;
426 const ScaledBrush *belowBrush = 0;
428 findScaledBrushes(scale, &aboveBrush, &belowBrush);
429 Q_ASSERT(aboveBrush != 0);
433 if (belowBrush != 0) {
436 TQImage scaledAboveImage = scaleImage(aboveBrush, scale, subPixelX, subPixelY);
437 TQImage scaledBelowImage = scaleImage(belowBrush, scale, subPixelX, subPixelY);
439 double t = (scale - belowBrush->scale()) / (aboveBrush->scale() - belowBrush->scale());
441 outputImage = interpolate(scaledBelowImage, scaledAboveImage, t);
443 if (fabs(scale - aboveBrush->scale()) < DBL_EPSILON) {
445 outputImage = scaleImage(aboveBrush, scale, subPixelX, subPixelY);
448 double s = scale / aboveBrush->scale();
449 outputImage = scaleSinglePixelImage(s, aboveBrush->image().pixel(0, 0), subPixelX, subPixelY);
453 int outputWidth = outputImage.width();
454 int outputHeight = outputImage.height();
456 KisPaintDevice *layer =
new KisPaintDevice(KisMetaRegistry::instance()->csRegistry()->getRGB8(),
"brush");
460 for (
int y = 0; y < outputHeight; y++) {
462 for (
int x = 0; x < outputWidth; x++) {
463 TQ_UINT8 * p = iter.rawData();
465 TQRgb pixel = outputImage.pixel(x, y);
466 int red = tqRed(pixel);
467 int green = tqGreen(pixel);
468 int blue = tqBlue(pixel);
469 int alpha = tqAlpha(pixel);
475 p[2] = (red * 255) / alpha;
476 p[1] = (green * 255) / alpha;
477 p[0] = (blue * 255) / alpha;
488void KisBrush::setHotSpot(
KisPoint pt)
495 else if (x >= width())
500 else if (y >= height())
503 m_hotSpot = KisPoint(x, y);
508 double scale = scaleForPressure(info.pressure);
509 double w = width() * scale;
510 double h = height() * scale;
524 KisPoint p(w / 2, h / 2);
528enumBrushType KisBrush::brushType()
const
530 if (m_brushType == IMAGE && useColorAsMask()) {
538bool KisBrush::hasColor()
const
543void KisBrush::createScaledBrushes()
const
545 if (!m_scaledBrushes.isEmpty())
546 m_scaledBrushes.clear();
550 int width = m_img.width() * MAXIMUM_SCALE;
551 int height = m_img.height() * MAXIMUM_SCALE;
557 if (width >= m_img.width() && height >= m_img.height()) {
558 scaledImage = scaleImage(m_img, width, height);
562 scaledImage = scaleImage(scaledImage, width, height);
565 KisAlphaMaskSP scaledMask =
new KisAlphaMask(scaledImage, hasColor());
566 TQ_CHECK_PTR(scaledMask);
568 double xScale =
static_cast<double>(width) / m_img.width();
569 double yScale =
static_cast<double>(height) / m_img.height();
570 double scale = xScale;
572 m_scaledBrushes.append(ScaledBrush(scaledMask, hasColor() ? scaledImage : TQImage(), scale, xScale, yScale));
574 if (width == 1 && height == 1) {
579 width = (width + 1) / 2;
580 height = (height + 1) / 2;
586double KisBrush::xSpacing(
double pressure)
const
588 return width() * scaleForPressure(pressure) * m_spacing;
591double KisBrush::ySpacing(
double pressure)
const
593 return height() * scaleForPressure(pressure) * m_spacing;
596double KisBrush::scaleForPressure(
double pressure)
598 double scale = pressure / PRESSURE_DEFAULT;
604 if (scale > MAXIMUM_SCALE) {
605 scale = MAXIMUM_SCALE;
614 return static_cast<TQ_INT32
>(ceil(width() * scaleForPressure(info.pressure)) + 1);
620 return static_cast<TQ_INT32
>(ceil(height() * scaleForPressure(info.pressure)) + 1);
623KisAlphaMaskSP KisBrush::scaleMask(
const ScaledBrush *srcBrush,
double scale,
double subPixelX,
double subPixelY)
const
626 int dstWidth =
static_cast<int>(ceil(scale * width())) + 1;
627 int dstHeight =
static_cast<int>(ceil(scale * height())) + 1;
629 KisAlphaMaskSP dstMask =
new KisAlphaMask(dstWidth, dstHeight);
630 TQ_CHECK_PTR(dstMask);
632 KisAlphaMaskSP srcMask = srcBrush->mask();
635 double xScale = srcBrush->xScale() / scale;
636 double yScale = srcBrush->yScale() / scale;
638 int srcWidth = srcMask->width();
639 int srcHeight = srcMask->height();
641 for (
int dstY = 0; dstY < dstHeight; dstY++) {
642 for (
int dstX = 0; dstX < dstWidth; dstX++) {
644 double srcX = (dstX - subPixelX + 0.5) * xScale;
645 double srcY = (dstY - subPixelY + 0.5) * yScale;
650 int leftX =
static_cast<int>(srcX);
656 double xInterp = srcX - leftX;
658 int topY =
static_cast<int>(srcY);
664 double yInterp = srcY - topY;
666 TQ_UINT8 topLeft = (leftX >= 0 && leftX < srcWidth && topY >= 0 && topY < srcHeight) ? srcMask->alphaAt(leftX, topY) : OPACITY_TRANSPARENT;
667 TQ_UINT8 bottomLeft = (leftX >= 0 && leftX < srcWidth && topY + 1 >= 0 && topY + 1 < srcHeight) ? srcMask->alphaAt(leftX, topY + 1) : OPACITY_TRANSPARENT;
668 TQ_UINT8 topRight = (leftX + 1 >= 0 && leftX + 1 < srcWidth && topY >= 0 && topY < srcHeight) ? srcMask->alphaAt(leftX + 1, topY) : OPACITY_TRANSPARENT;
669 TQ_UINT8 bottomRight = (leftX + 1 >= 0 && leftX + 1 < srcWidth && topY + 1 >= 0 && topY + 1 < srcHeight) ? srcMask->alphaAt(leftX + 1, topY + 1) : OPACITY_TRANSPARENT;
671 double a = 1 - xInterp;
672 double b = 1 - yInterp;
675 int d =
static_cast<int>(a * b * topLeft
676 + a * (1 - b) * bottomLeft
677 + (1 - a) * b * topRight
678 + (1 - a) * (1 - b) * bottomRight + 0.5);
680 if (d < OPACITY_TRANSPARENT) {
681 d = OPACITY_TRANSPARENT;
684 if (d > OPACITY_OPAQUE) {
688 dstMask->setAlphaAt(dstX, dstY,
static_cast<TQ_UINT8
>(d));
695TQImage KisBrush::scaleImage(
const ScaledBrush *srcBrush,
double scale,
double subPixelX,
double subPixelY)
const
698 int dstWidth =
static_cast<int>(ceil(scale * width())) + 1;
699 int dstHeight =
static_cast<int>(ceil(scale * height())) + 1;
701 TQImage dstImage(dstWidth, dstHeight, 32);
702 dstImage.setAlphaBuffer(
true);
704 const TQImage srcImage = srcBrush->image();
707 double xScale = srcBrush->xScale() / scale;
708 double yScale = srcBrush->yScale() / scale;
710 int srcWidth = srcImage.width();
711 int srcHeight = srcImage.height();
713 for (
int dstY = 0; dstY < dstHeight; dstY++) {
714 for (
int dstX = 0; dstX < dstWidth; dstX++) {
716 double srcX = (dstX - subPixelX + 0.5) * xScale;
717 double srcY = (dstY - subPixelY + 0.5) * yScale;
722 int leftX =
static_cast<int>(srcX);
728 double xInterp = srcX - leftX;
730 int topY =
static_cast<int>(srcY);
736 double yInterp = srcY - topY;
738 TQRgb topLeft = (leftX >= 0 && leftX < srcWidth && topY >= 0 && topY < srcHeight) ? srcImage.pixel(leftX, topY) : tqRgba(0, 0, 0, 0);
739 TQRgb bottomLeft = (leftX >= 0 && leftX < srcWidth && topY + 1 >= 0 && topY + 1 < srcHeight) ? srcImage.pixel(leftX, topY + 1) : tqRgba(0, 0, 0, 0);
740 TQRgb topRight = (leftX + 1 >= 0 && leftX + 1 < srcWidth && topY >= 0 && topY < srcHeight) ? srcImage.pixel(leftX + 1, topY) : tqRgba(0, 0, 0, 0);
741 TQRgb bottomRight = (leftX + 1 >= 0 && leftX + 1 < srcWidth && topY + 1 >= 0 && topY + 1 < srcHeight) ? srcImage.pixel(leftX + 1, topY + 1) : tqRgba(0, 0, 0, 0);
743 double a = 1 - xInterp;
744 double b = 1 - yInterp;
747 int red =
static_cast<int>(a * b * tqRed(topLeft)
748 + a * (1 - b) * tqRed(bottomLeft)
749 + (1 - a) * b * tqRed(topRight)
750 + (1 - a) * (1 - b) * tqRed(bottomRight) + 0.5);
751 int green =
static_cast<int>(a * b * tqGreen(topLeft)
752 + a * (1 - b) * tqGreen(bottomLeft)
753 + (1 - a) * b * tqGreen(topRight)
754 + (1 - a) * (1 - b) * tqGreen(bottomRight) + 0.5);
755 int blue =
static_cast<int>(a * b * tqBlue(topLeft)
756 + a * (1 - b) * tqBlue(bottomLeft)
757 + (1 - a) * b * tqBlue(topRight)
758 + (1 - a) * (1 - b) * tqBlue(bottomRight) + 0.5);
759 int alpha =
static_cast<int>(a * b * tqAlpha(topLeft)
760 + a * (1 - b) * tqAlpha(bottomLeft)
761 + (1 - a) * b * tqAlpha(topRight)
762 + (1 - a) * (1 - b) * tqAlpha(bottomRight) + 0.5);
796 dstImage.setPixel(dstX, dstY, tqRgba(red, green, blue, alpha));
803TQImage KisBrush::scaleImage(
const TQImage& srcImage,
int width,
int height)
808 int srcWidth = srcImage.width();
809 int srcHeight = srcImage.height();
811 double xScale =
static_cast<double>(srcWidth) / width;
812 double yScale =
static_cast<double>(srcHeight) / height;
814 if (xScale > 2 + DBL_EPSILON || yScale > 2 + DBL_EPSILON || xScale < 1 - DBL_EPSILON || yScale < 1 - DBL_EPSILON) {
817 scaledImage = srcImage.smoothScale(width, height);
822 scaledImage.create(width, height, 32);
823 scaledImage.setAlphaBuffer(srcImage.hasAlphaBuffer());
825 for (
int dstY = 0; dstY < height; dstY++) {
826 for (
int dstX = 0; dstX < width; dstX++) {
828 double srcX = (dstX + 0.5) * xScale;
829 double srcY = (dstY + 0.5) * yScale;
834 int leftX =
static_cast<int>(srcX);
840 double xInterp = srcX - leftX;
842 int topY =
static_cast<int>(srcY);
848 double yInterp = srcY - topY;
850 TQRgb topLeft = (leftX >= 0 && leftX < srcWidth && topY >= 0 && topY < srcHeight) ? srcImage.pixel(leftX, topY) : tqRgba(0, 0, 0, 0);
851 TQRgb bottomLeft = (leftX >= 0 && leftX < srcWidth && topY + 1 >= 0 && topY + 1 < srcHeight) ? srcImage.pixel(leftX, topY + 1) : tqRgba(0, 0, 0, 0);
852 TQRgb topRight = (leftX + 1 >= 0 && leftX + 1 < srcWidth && topY >= 0 && topY < srcHeight) ? srcImage.pixel(leftX + 1, topY) : tqRgba(0, 0, 0, 0);
853 TQRgb bottomRight = (leftX + 1 >= 0 && leftX + 1 < srcWidth && topY + 1 >= 0 && topY + 1 < srcHeight) ? srcImage.pixel(leftX + 1, topY + 1) : tqRgba(0, 0, 0, 0);
855 double a = 1 - xInterp;
856 double b = 1 - yInterp;
863 if (srcImage.hasAlphaBuffer()) {
864 red =
static_cast<int>(a * b * tqRed(topLeft) * tqAlpha(topLeft)
865 + a * (1 - b) * tqRed(bottomLeft) * tqAlpha(bottomLeft)
866 + (1 - a) * b * tqRed(topRight) * tqAlpha(topRight)
867 + (1 - a) * (1 - b) * tqRed(bottomRight) * tqAlpha(bottomRight) + 0.5);
868 green =
static_cast<int>(a * b * tqGreen(topLeft) * tqAlpha(topLeft)
869 + a * (1 - b) * tqGreen(bottomLeft) * tqAlpha(bottomLeft)
870 + (1 - a) * b * tqGreen(topRight) * tqAlpha(topRight)
871 + (1 - a) * (1 - b) * tqGreen(bottomRight) * tqAlpha(bottomRight) + 0.5);
872 blue =
static_cast<int>(a * b * tqBlue(topLeft) * tqAlpha(topLeft)
873 + a * (1 - b) * tqBlue(bottomLeft) * tqAlpha(bottomLeft)
874 + (1 - a) * b * tqBlue(topRight) * tqAlpha(topRight)
875 + (1 - a) * (1 - b) * tqBlue(bottomRight) * tqAlpha(bottomRight) + 0.5);
876 alpha =
static_cast<int>(a * b * tqAlpha(topLeft)
877 + a * (1 - b) * tqAlpha(bottomLeft)
878 + (1 - a) * b * tqAlpha(topRight)
879 + (1 - a) * (1 - b) * tqAlpha(bottomRight) + 0.5);
888 red =
static_cast<int>(a * b * tqRed(topLeft)
889 + a * (1 - b) * tqRed(bottomLeft)
890 + (1 - a) * b * tqRed(topRight)
891 + (1 - a) * (1 - b) * tqRed(bottomRight) + 0.5);
892 green =
static_cast<int>(a * b * tqGreen(topLeft)
893 + a * (1 - b) * tqGreen(bottomLeft)
894 + (1 - a) * b * tqGreen(topRight)
895 + (1 - a) * (1 - b) * tqGreen(bottomRight) + 0.5);
896 blue =
static_cast<int>(a * b * tqBlue(topLeft)
897 + a * (1 - b) * tqBlue(bottomLeft)
898 + (1 - a) * b * tqBlue(topRight)
899 + (1 - a) * (1 - b) * tqBlue(bottomRight) + 0.5);
935 scaledImage.setPixel(dstX, dstY, tqRgba(red, green, blue, alpha));
947void KisBrush::findScaledBrushes(
double scale,
const ScaledBrush **aboveBrush,
const ScaledBrush **belowBrush)
const
952 *aboveBrush = &(m_scaledBrushes[current]);
954 if (fabs((*aboveBrush)->scale() - scale) < DBL_EPSILON) {
959 if (current == m_scaledBrushes.count() - 1) {
964 if (scale > m_scaledBrushes[current + 1].scale() + DBL_EPSILON) {
966 *belowBrush = &(m_scaledBrushes[current + 1]);
974KisAlphaMaskSP KisBrush::scaleSinglePixelMask(
double scale, TQ_UINT8 maskValue,
double subPixelX,
double subPixelY)
980 KisAlphaMaskSP outputMask =
new KisAlphaMask(dstWidth, dstHeight);
981 TQ_CHECK_PTR(outputMask);
983 double a = subPixelX;
984 double b = subPixelY;
986 for (
int y = 0; y < dstHeight; y++) {
987 for (
int x = 0; x < dstWidth; x++) {
989 TQ_UINT8 topLeft = (x > 0 && y > 0) ? maskValue : OPACITY_TRANSPARENT;
990 TQ_UINT8 bottomLeft = (x > 0 && y < srcHeight) ? maskValue : OPACITY_TRANSPARENT;
991 TQ_UINT8 topRight = (x < srcWidth && y > 0) ? maskValue : OPACITY_TRANSPARENT;
992 TQ_UINT8 bottomRight = (x < srcWidth && y < srcHeight) ? maskValue : OPACITY_TRANSPARENT;
995 int d =
static_cast<int>(a * b * topLeft
996 + a * (1 - b) * bottomLeft
997 + (1 - a) * b * topRight
998 + (1 - a) * (1 - b) * bottomRight + 0.5);
1002 d =
static_cast<int>(d * scale * scale + 0.5);
1004 if (d < OPACITY_TRANSPARENT) {
1005 d = OPACITY_TRANSPARENT;
1008 if (d > OPACITY_OPAQUE) {
1012 outputMask->setAlphaAt(x, y,
static_cast<TQ_UINT8
>(d));
1019TQImage KisBrush::scaleSinglePixelImage(
double scale, TQRgb pixel,
double subPixelX,
double subPixelY)
1026 TQImage outputImage(dstWidth, dstHeight, 32);
1027 outputImage.setAlphaBuffer(
true);
1029 double a = subPixelX;
1030 double b = subPixelY;
1032 for (
int y = 0; y < dstHeight; y++) {
1033 for (
int x = 0; x < dstWidth; x++) {
1035 TQRgb topLeft = (x > 0 && y > 0) ? pixel : tqRgba(0, 0, 0, 0);
1036 TQRgb bottomLeft = (x > 0 && y < srcHeight) ? pixel : tqRgba(0, 0, 0, 0);
1037 TQRgb topRight = (x < srcWidth && y > 0) ? pixel : tqRgba(0, 0, 0, 0);
1038 TQRgb bottomRight = (x < srcWidth && y < srcHeight) ? pixel : tqRgba(0, 0, 0, 0);
1041 int red =
static_cast<int>(a * b * tqRed(topLeft)
1042 + a * (1 - b) * tqRed(bottomLeft)
1043 + (1 - a) * b * tqRed(topRight)
1044 + (1 - a) * (1 - b) * tqRed(bottomRight) + 0.5);
1045 int green =
static_cast<int>(a * b * tqGreen(topLeft)
1046 + a * (1 - b) * tqGreen(bottomLeft)
1047 + (1 - a) * b * tqGreen(topRight)
1048 + (1 - a) * (1 - b) * tqGreen(bottomRight) + 0.5);
1049 int blue =
static_cast<int>(a * b * tqBlue(topLeft)
1050 + a * (1 - b) * tqBlue(bottomLeft)
1051 + (1 - a) * b * tqBlue(topRight)
1052 + (1 - a) * (1 - b) * tqBlue(bottomRight) + 0.5);
1053 int alpha =
static_cast<int>(a * b * tqAlpha(topLeft)
1054 + a * (1 - b) * tqAlpha(bottomLeft)
1055 + (1 - a) * b * tqAlpha(topRight)
1056 + (1 - a) * (1 - b) * tqAlpha(bottomRight) + 0.5);
1060 alpha =
static_cast<int>(alpha * scale * scale + 0.5);
1064 red =
static_cast<int>(red * scale * scale + 0.5);
1065 green =
static_cast<int>(green * scale * scale + 0.5);
1066 blue =
static_cast<int>(blue * scale * scale + 0.5);
1100 outputImage.setPixel(x, y, tqRgba(red, green, blue, alpha));
1107TQImage KisBrush::interpolate(
const TQImage& image1,
const TQImage& image2,
double t)
1109 Q_ASSERT((image1.width() == image2.width()) && (image1.height() == image2.height()));
1110 Q_ASSERT(t > -DBL_EPSILON && t < 1 + DBL_EPSILON);
1112 int width = image1.width();
1113 int height = image1.height();
1115 TQImage outputImage(width, height, 32);
1116 outputImage.setAlphaBuffer(
true);
1118 for (
int x = 0; x < width; x++) {
1119 for (
int y = 0; y < height; y++) {
1120 TQRgb image1pixel = image1.pixel(x, y);
1121 TQRgb image2pixel = image2.pixel(x, y);
1124 int red =
static_cast<int>((1 - t) * tqRed(image1pixel) + t * tqRed(image2pixel) + 0.5);
1125 int green =
static_cast<int>((1 - t) * tqGreen(image1pixel) + t * tqGreen(image2pixel) + 0.5);
1126 int blue =
static_cast<int>((1 - t) * tqBlue(image1pixel) + t * tqBlue(image2pixel) + 0.5);
1127 int alpha =
static_cast<int>((1 - t) * tqAlpha(image1pixel) + t * tqAlpha(image2pixel) + 0.5);
1161 outputImage.setPixel(x, y, tqRgba(red, green, blue, alpha));
1168KisBrush::ScaledBrush::ScaledBrush()
1171 m_image = TQImage();
1177KisBrush::ScaledBrush::ScaledBrush(KisAlphaMaskSP scaledMask,
const TQImage& scaledImage,
double scale,
double xScale,
double yScale)
1179 m_mask = scaledMask;
1180 m_image = scaledImage;
1185 if (!m_image.isNull()) {
1190 for (
int y = 0; y < m_image.height(); y++) {
1191 for (
int x = 0; x < m_image.width(); x++) {
1193 TQRgb pixel = m_image.pixel(x, y);
1195 int red = tqRed(pixel);
1196 int green = tqGreen(pixel);
1197 int blue = tqBlue(pixel);
1198 int alpha = tqAlpha(pixel);
1200 red = (red * alpha) / 255;
1201 green = (green * alpha) / 255;
1202 blue = (blue * alpha) / 255;
1204 m_image.setPixel(x, y, tqRgba(red, green, blue, alpha));
1210void KisBrush::setImage(
const TQImage& img)
1215 setWidth(img.width());
1216 setHeight(img.height());
1218 m_scaledBrushes.clear();
1223TQ_INT32 KisBrush::width()
const
1228void KisBrush::setWidth(TQ_INT32 w)
1233TQ_INT32 KisBrush::height()
const
1238void KisBrush::setHeight(TQ_INT32 h)
1257void KisBrush::generateBoundary() {
1258 KisPaintDeviceSP dev;
1259 int w = maskWidth(KisPaintInformation());
1260 int h = maskHeight(KisPaintInformation());
1262 if (brushType() == IMAGE || brushType() == PIPE_IMAGE) {
1263 dev = image(KisMetaRegistry::instance()->csRegistry() ->getColorSpace(KisID(
"RGBA",
""),
""), KisPaintInformation());
1265 KisAlphaMaskSP amask = mask(KisPaintInformation());
1266 KisColorSpace* cs = KisMetaRegistry::instance()->csRegistry()->
getColorSpace(KisID(
"RGBA",
""),
"");
1267 dev =
new KisPaintDevice(cs,
"tmp for generateBoundary");
1268 for (
int y = 0; y < h; y++) {
1269 KisHLineIteratorPixel it = dev->createHLineIterator(0, y, w,
true);
1272 while(!it.isDone()) {
1273 cs->
setAlpha(it.rawData(), amask->alphaAt(x++, y), 1);
1279 m_boundary =
new KisBoundary(dev);
1280 m_boundary->generateBoundary(w, h);
1283KisBoundary KisBrush::boundary() {
1289void KisBrush::makeMaskImage() {
1294 img.create(width(), height(), 32);
1296 if (m_img.width() == img.width() && m_img.height() == img.height()) {
1297 for (
int x = 0; x < width(); x++) {
1298 for (
int y = 0; y < height(); y++) {
1299 TQRgb c = m_img.pixel(x, y);
1300 int a = (tqGray(c) * tqAlpha(c)) / 255;
1301 img.setPixel(x, y, tqRgba(a, a, a, 255));
1310 m_useColorAsMask =
false;
1313 m_scaledBrushes.clear();
1316KisBrush* KisBrush::clone()
const {
1317 KisBrush* c =
new KisBrush(
"");
1318 c->m_spacing = m_spacing;
1319 c->m_useColorAsMask = m_useColorAsMask;
1320 c->m_hasColor = m_useColorAsMask;
1322 c->m_width = m_width;
1323 c->m_height = m_height;
1324 c->m_ownData =
false;
1325 c->m_hotSpot = m_hotSpot;
1326 c->m_brushType = m_brushType;
1332#include "kis_brush.moc"
KisColorSpace * getColorSpace(const KisID &csID, const TQString &profileName)
Return the colorspace + profile as named, or NULL if impossible combination.
A colorspace is the definition of a certain color model in Chalk.
virtual void setAlpha(TQ_UINT8 *pixels, TQ_UINT8 alpha, TQ_INT32 nPixels) const =0
Set the alpha channel of the given run of pixels to the given value.
A paint device contains the actual pixel data and offers methods to read and write pixels.
KisHLineIteratorPixel createHLineIterator(TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, bool writable)
This function return an iterator which points to the first pixel of a horizontal line.
A double-based point class that can return it's coordinates approximated to integers.
virtual TQImage img()=0
Returns a TQImage representing this resource.
virtual bool save()=0
Save this resource asynchronously.
virtual bool load()=0
Load this resource.