18 #include "bitmapimage.h"
21 BitmapImage::BitmapImage()
23 mImage = std::make_shared< QImage >();
24 mBounds = QRect( 0, 0, 0, 0 );
30 mImage = std::make_shared< QImage >( *a.mImage );
33 BitmapImage::BitmapImage(
const QRect& rectangle,
const QColor& colour)
36 mImage = std::make_shared< QImage >( mBounds.size(), QImage::Format_ARGB32_Premultiplied);
37 mImage->fill(colour.rgba());
40 BitmapImage::BitmapImage(
const QRect& rectangle,
const QImage& image )
42 mBounds = rectangle.normalized();
44 mImage = std::make_shared< QImage >(image);
45 if ( mImage->width() != rectangle.width() || mImage->height() != rectangle.height())
47 qDebug() <<
"Error instancing bitmapImage.";
51 BitmapImage::BitmapImage(
const QString& path,
const QPoint& topLeft )
53 mImage = std::make_shared< QImage >(path);
54 if ( mImage->isNull() )
56 qDebug() <<
"ERROR: Image " << path <<
" not loaded";
58 mBounds = QRect( topLeft, mImage->size() );
61 BitmapImage::~BitmapImage()
65 void BitmapImage::setImage( QImage* img )
74 mImage = std::make_shared< QImage >( *a.mImage );
78 void BitmapImage::paintImage(QPainter& painter)
80 painter.drawImage(topLeft(), *mImage);
91 QRect intersection2 = rectangle.translated( -topLeft() );
98 paste( bitmapImage, QPainter::CompositionMode_SourceOver );
101 void BitmapImage::paste(
BitmapImage* bitmapImage, QPainter::CompositionMode cm)
104 if ( mImage->width() == 0 || mImage->height() == 0 )
106 newBoundaries = bitmapImage->mBounds;
110 newBoundaries = mBounds.united( bitmapImage->mBounds );
112 extend( newBoundaries );
114 QImage* image2 = bitmapImage->image();
116 QPainter painter( mImage.get() );
117 painter.setCompositionMode(cm);
118 painter.drawImage( bitmapImage->mBounds.topLeft() - mBounds.topLeft(), *image2);
124 QImage* image2 = bitmapImage->image();
127 if ( mImage->width() == 0 || mImage->height() == 0 )
129 newBoundaries = bitmapImage->mBounds;
133 newBoundaries = mBounds.united( bitmapImage->mBounds );
135 extend( newBoundaries );
136 QPoint offset = bitmapImage->mBounds.topLeft() - mBounds.topLeft();
137 for (
int y = 0; y < image2->height(); y++)
139 for (
int x = 0; x < image2->width(); x++)
141 QRgb p1 = mImage->pixel(offset.x()+x,offset.y()+y);
142 QRgb p2 = image2->pixel(x,y);
154 int a = qMax(a1, a2);
155 int r = qMax(r1, r2);
156 int g = qMax(g1, g2);
157 int b = qMax(b1, b2);
159 QRgb mix = qRgba(r, g, b, a);
162 mImage->setPixel(offset.x()+x,offset.y()+y, mix);
168 void BitmapImage::compareAlpha(
BitmapImage* bitmapImage)
170 QImage* image2 = bitmapImage->image();
173 if ( mImage->width() == 0 || mImage->height() == 0 )
175 newBoundaries = bitmapImage->mBounds;
179 newBoundaries = mBounds.united( bitmapImage->mBounds );
181 extend( newBoundaries );
182 QPoint offset = bitmapImage->mBounds.topLeft() - mBounds.topLeft();
183 for (
int y = 0; y < image2->height(); y++)
185 for (
int x = 0; x < image2->width(); x++)
187 QRgb p1 = mImage->pixel(offset.x()+x,offset.y()+y);
188 QRgb p2 = image2->pixel(x,y);
195 QRgb mix = qRgba(qRed(p2), qGreen(p2), qBlue(p2), a2);
196 mImage->setPixel(offset.x()+x,offset.y()+y, mix);
202 void BitmapImage::moveTopLeft(QPoint point)
204 mBounds.moveTopLeft(point);
207 void BitmapImage::transform(QRect newBoundaries,
bool smoothTransform)
209 mBounds = newBoundaries;
210 newBoundaries.moveTopLeft( QPoint(0,0) );
211 QImage* newImage =
new QImage( mBounds.size(), QImage::Format_ARGB32_Premultiplied);
213 QPainter painter(newImage);
214 painter.setRenderHint(QPainter::SmoothPixmapTransform, smoothTransform);
215 painter.setCompositionMode(QPainter::CompositionMode_Source);
216 painter.fillRect( newImage->rect(), QColor(0,0,0,0) );
217 painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
218 painter.drawImage(newBoundaries, *mImage );
220 mImage.reset( newImage );
223 BitmapImage BitmapImage::transformed(QRect selection, QTransform transform,
bool smoothTransform)
229 QImage transformedImage;
232 transformedImage = selectedPart.image()->transformed(transform, Qt::SmoothTransformation);
236 transformedImage = selectedPart.image()->transformed(transform);
239 return BitmapImage(transform.mapRect(selection), transformedImage);
242 BitmapImage BitmapImage::transformed(QRect newBoundaries,
bool smoothTransform)
244 BitmapImage transformedImage(newBoundaries, QColor(0,0,0,0));
245 QPainter painter(transformedImage.image());
246 painter.setRenderHint(QPainter::SmoothPixmapTransform, smoothTransform);
247 newBoundaries.moveTopLeft( QPoint(0,0) );
248 painter.drawImage(newBoundaries, *mImage );
250 return transformedImage;
254 void BitmapImage::extend(QPoint P)
256 if (mBounds.contains( P ))
262 extend( QRect(P, QSize(0,0)) );
266 void BitmapImage::extend(QRect rectangle)
268 if (!mExtendable)
return;
269 if (rectangle.width() <= 0) rectangle.setWidth(1);
270 if (rectangle.height() <= 0) rectangle.setHeight(1);
271 if (mBounds.contains( rectangle ))
277 QRect newBoundaries = mBounds.united(rectangle).normalized();
278 QImage* newImage =
new QImage( newBoundaries.size(), QImage::Format_ARGB32_Premultiplied);
279 newImage->fill(Qt::transparent);
280 if (!newImage->isNull())
282 QPainter painter(newImage);
283 painter.drawImage(mBounds.topLeft() - newBoundaries.topLeft(), *mImage);
286 mImage.reset( newImage );
287 mBounds = newBoundaries;
291 QRgb BitmapImage::pixel(
int x,
int y)
293 return pixel( QPoint(x,y) );
296 QRgb BitmapImage::pixel(QPoint P)
298 QRgb result = qRgba(0,0,0,0);
299 if ( mBounds.contains( P ) ) result = mImage->pixel(P - topLeft());
303 void BitmapImage::setPixel(
int x,
int y, QRgb colour)
305 setPixel( QPoint(x,y), colour);
308 void BitmapImage::setPixel(QPoint P, QRgb colour)
311 if ( mBounds.contains(P) )
312 mImage->setPixel(P-topLeft(), colour);
317 void BitmapImage::drawLine( QPointF P1, QPointF P2, QPen pen, QPainter::CompositionMode cm,
bool antialiasing)
319 int width = 2+pen.width();
320 extend( QRect(P1.toPoint(), P2.toPoint()).normalized().adjusted(-width,-width,width,width) );
321 if (mImage != NULL && !mImage->isNull() )
323 QPainter painter( mImage.get() );
324 painter.setCompositionMode(cm);
325 painter.setRenderHint(QPainter::Antialiasing, antialiasing);
327 painter.drawLine( P1-topLeft(), P2-topLeft());
332 void BitmapImage::drawRect( QRectF rectangle, QPen pen, QBrush brush, QPainter::CompositionMode cm,
bool antialiasing)
334 int width = pen.width();
335 extend( rectangle.adjusted(-width,-width,width,width).toRect() );
336 if (brush.style() == Qt::RadialGradientPattern)
338 QRadialGradient* gradient = (QRadialGradient*)brush.gradient();
339 gradient->setCenter( gradient->center() - topLeft() );
340 gradient->setFocalPoint( gradient->focalPoint() - topLeft() );
342 if ( mImage && !mImage->isNull() )
344 QPainter painter( mImage.get() );
345 painter.setCompositionMode(cm);
346 painter.setRenderHint(QPainter::Antialiasing, antialiasing);
348 painter.setBrush(brush);
349 painter.drawRect( rectangle.translated(-topLeft()) );
354 void BitmapImage::drawEllipse( QRectF rectangle, QPen pen, QBrush brush, QPainter::CompositionMode cm,
bool antialiasing)
356 int width = pen.width();
357 extend( rectangle.adjusted(-width,-width,width,width).toRect() );
358 if (brush.style() == Qt::RadialGradientPattern)
360 QRadialGradient* gradient = (QRadialGradient*)brush.gradient();
361 gradient->setCenter( gradient->center() - topLeft() );
362 gradient->setFocalPoint( gradient->focalPoint() - topLeft() );
364 if ( mImage && !mImage->isNull() )
366 QPainter painter( mImage.get() );
368 painter.setRenderHint(QPainter::Antialiasing, antialiasing);
370 painter.setBrush(brush);
373 painter.setCompositionMode(cm);
374 painter.drawEllipse( rectangle.translated(-topLeft()) );
380 void BitmapImage::drawPath( QPainterPath path, QPen pen, QBrush brush,
381 QPainter::CompositionMode cm,
bool antialiasing)
383 int width = pen.width();
384 qreal inc = 1.0 + width / 20.0;
386 extend( path.controlPointRect().adjusted(-width,-width,width,width).toRect() );
388 if ( mImage != NULL && !mImage->isNull() )
390 QPainter painter( mImage.get() );
391 painter.setCompositionMode(cm);
392 painter.setRenderHint( QPainter::Antialiasing, antialiasing );
394 painter.setBrush(brush);
395 painter.setTransform(QTransform().translate(-topLeft().x(), -topLeft().y()));
396 painter.setMatrixEnabled(
true);
397 if (path.length() > 0)
399 for (
int pt = 0; pt < path.elementCount() - 1; pt++ )
401 qreal dx = path.elementAt(pt+1).x - path.elementAt(pt).x;
402 qreal dy = path.elementAt(pt+1).y - path.elementAt(pt).y;
403 qreal m = sqrt(dx*dx+dy*dy);
404 qreal factorx = dx / m;
405 qreal factory = dy / m;
406 for (
float h = 0.f; h < m; h += inc )
408 qreal x = path.elementAt(pt).x + factorx * h;
409 qreal y = path.elementAt(pt).y + factory * h;
410 painter.drawPoint( QPointF( x, y ) );
419 painter.drawPoint( path.elementAt(0).x, path.elementAt(0).y );
425 void BitmapImage::clear()
427 mImage = std::make_shared< QImage >();
428 mBounds = QRect(0,0,0,0);
431 QRgb BitmapImage::constScanLine(
int x,
int y) {
432 QRgb result = qRgba( 0, 0, 0, 0 );
433 if ( mBounds.contains( QPoint( x, y ) ) ) {
434 result = *(
reinterpret_cast< const QRgb*
>( mImage->constScanLine( y - topLeft().y() ) ) + x - topLeft().x() );
440 void BitmapImage::scanLine(
int x,
int y, QRgb colour)
442 extend( QPoint( x, y ) );
443 if( mBounds.contains( QPoint( x, y ) ) ) {
446 *(
reinterpret_cast< QRgb*
>( mImage->scanLine( y - topLeft().y() ) ) + x - topLeft().x() ) =
455 void BitmapImage::clear(QRect rectangle)
457 QRect clearRectangle = mBounds.intersected( rectangle );
458 clearRectangle.moveTopLeft( clearRectangle.topLeft() - topLeft() );
460 QPainter painter( mImage.get() );
461 painter.setCompositionMode(QPainter::CompositionMode_Clear);
462 painter.fillRect( clearRectangle, QColor(0,0,0,0) );
466 int BitmapImage::pow(
int n)
471 bool BitmapImage::compareColor(QRgb color1, QRgb color2,
int tolerance)
473 if ( color1 == color2 )
return true;
475 int red1 = qRed( color1 );
476 int green1 = qGreen( color1 );
477 int blue1 = qBlue( color1 );
478 int alpha1 = qAlpha( color1 );
480 int red2 = qRed( color2 );
481 int green2 = qGreen( color2 );
482 int blue2 = qBlue( color2 );
483 int alpha2 = qAlpha( color2 );
485 int diffRed = abs( red2 - red1 );
486 int diffGreen = abs( green2 - green1 );
487 int diffBlue = abs( blue2 - blue1 );
488 int diffAlpha = abs( alpha2 - alpha1 );
490 if ( diffRed > tolerance ||
491 diffGreen > tolerance ||
492 diffBlue > tolerance ||
493 diffAlpha > tolerance )
503 void BitmapImage::floodFill(
BitmapImage* targetImage, QRect cameraRect, QPoint point, QRgb oldColor, QRgb newColor,
int tolerance)
505 if ( oldColor == newColor ){
509 oldColor = targetImage->pixel( point );
510 oldColor = qRgba( qRed( oldColor ), qGreen( oldColor ), qBlue( oldColor ), qAlpha( oldColor ) );
520 bool spanLeft, spanRight;
523 targetImage->extend( cameraRect );
524 replaceImage =
new BitmapImage( cameraRect, Qt::transparent );
526 queue.append( point );
529 while( !queue.empty() ) {
530 tempPoint = queue.takeFirst();
532 point.setX( tempPoint.x() );
533 point.setY( tempPoint.y() );
537 newPlacedColor = replaceImage->constScanLine( xTemp, point.y() );
538 while( xTemp >= targetImage->topLeft().x() &&
539 compareColor( targetImage->constScanLine( xTemp, point.y() ), oldColor, tolerance) ) xTemp--;
542 spanLeft = spanRight =
false;
543 while( xTemp <= targetImage->right() &&
544 compareColor( targetImage->constScanLine( xTemp, point.y() ), oldColor, tolerance ) &&
545 newPlacedColor != newColor ) {
548 replaceImage->scanLine( xTemp, point.y(), newColor );
550 if( !spanLeft && (point.y() > targetImage->top() ) &&
551 compareColor( targetImage->constScanLine( xTemp, point.y() - 1 ), oldColor, tolerance ) ) {
552 queue.append( QPoint( xTemp, point.y() - 1) );
554 }
else if( spanLeft && ( point.y() > targetImage->top() ) &&
555 !compareColor( targetImage->constScanLine( xTemp, point.y() - 1 ), oldColor, tolerance ) ) {
559 if( !spanRight && point.y() < targetImage->bottom() &&
560 compareColor( targetImage->constScanLine( xTemp, point.y() + 1 ), oldColor, tolerance ) ) {
561 queue.append( QPoint( xTemp, point.y() + 1 ) );
564 }
else if( spanRight && point.y() < targetImage->bottom() &&
565 !compareColor( targetImage->constScanLine( xTemp, point.y() + 1 ), oldColor, tolerance ) ) {
569 Q_ASSERT( queue.count() < ( targetImage->width() * targetImage->height() ) );
574 targetImage->paste( replaceImage );