How can I create a translucent copy of a QPixmap? - c++

In the program I'm making, I need two images, which are exactly the same but one is translucent. For performance reasons, I want to create two separate QPixmaps instead of using just one and setting the opacity of a QPainter. Is there a straightforward way to do this?

No, there is no performant way to do this.
To modify channels of a QPixmap it must be: Converted into a QImage, modified, converted back to a QPixmap. Depending upon your application the round trip will probably make it simpler to just do this in the QPainter: http://www.qtcentre.org/threads/51158-setting-QPixmap-s-alpha-channel
However if you could do roll this into your startup time the round trip may be reasonable, preventing repeated conversions in QPainter.
Convert your QPixmap to a QImage:http://doc.qt.io/qt-5/qpixmap.html#toImage
If you didn't have an alpha channel in your QPixmap you'll need to add one: http://doc.qt.io/qt-5/qimage.html#convertToFormat
Then for each pixel in your image call setPixel: http://doc.qt.io/qt-5/qimage.html#pixel-manipulation (Note that setPixel takes a QRgb. You'll need to get the red, green, and blue channels from the pixel to be modified and use these along with your desired alpha value in qRgba: http://doc.qt.io/qt-5/qcolor.html#qRgba)
Finally you'll need to use convertFromImage: http://doc.qt.io/qt-5/qpixmap.html#convertFromImage

Maybe you should read this example. I think you will need to use the composition mode for this purpose.

Related

How to rotate an image around its centre in QT QWidgets C++?

I am trying to rotate am image around its origin(center) in QT using QWidgts in C++. I experimented a lot of things here, but no matter what I do, the image keeps rotating around some arbitrary position I have no clue of. Kindly, help me out here. I am new to QT.
void gaugeWithRedZoneImage::rotate()
{
QPixmap pixmap(*gaugeMainScreen->pixmap());
QMatrix rm;
rm.translate(0, 0);
rm.rotate(-360);
pixmap = pixmap.transformed(rm);
gaugeMainScreen->setPixmap(pixmap);
/*QTransform rotate_disc;
rotate_disc.translate(pixmap.width()/2.0 , pixmap.height()/2.0);
rotate_disc.rotate(-60);
rotate_disc.translate(-(pixmap.width()/2.0) , -(pixmap.height()/2.0));
pixmap = pixmap.transformed(rotate_disc);
gaugeMainScreen->setPixmap(pixmap);*/
}
Form the documentation of QPixmap::transformed():
The transformation transform is internally adjusted to compensate for unwanted translation; i.e. the pixmap produced is the smallest pixmap that contains all the transformed points of the original pixmap.
This means that the method ensures no clipping takes place by appending the canvas. No matter what your rotation center was, the automatic extension of canvas will almost always result in a perceived shift.
Image examples might help to further diagnose the problem.
As ypnos said, your problem isn't the rotation center. When you rotate your image, its width and height will most likely change and no longer fit your container (gaugeMainScreen) dimensions.
You have some possibilities to overcome this problem. One of them is to set your container to scale its contents (you can use the method setScaledContents()). In this case, you have to keep the original image around and use it whenever you apply a rotation, otherwise your image will appear increasingly smaller.

changing textureRect of a CCSprite created by CCRenderTexture

I have a CCSprite which gradually needs to be exhausted linearly from one end, lets say from left to right.For this purpose ,I am trying to change the textureRect property of the sprite so that the part that got exhausted from one end is 'outside' the displaying frame of the sprite.
I did this sort of thing before with a sprite that gets loaded from a spritesheet.And it worked perfectly.But I created this CCSprite using CCRenderTexture and by changing the textureRect property,the entire sprite gets disappeared.
The first image is the original CCSprite which I get from CCRenderTexture.The second image shows what I want to achieve.The black dotted rectangular portion of the Sprite needs to be omitted out.Only the blue dotted portion of the sprite needs to be displayed.Essentially,this blue dotted rectangle is my textureRect.
Is there any way how I could make my sprite reduce from one end.
Also is there any difference between a sprite created normally,and one created using CCRenderTexture.
I have done similar thing like this before using some low-level hack.
There is a work around solution if you use CCProgressTimer, that's very easy and I think it should be enough for your examples.
But you said in comment that you have some special requirements like "exhaust it from both the ends at once" then some low-level hack is needed. My solution from my last object is:
1) Get the texture image's raw data. In cocos2d you can use CCRenderTexture and in cocos2d-x you can use CCImage.
2) CCRenderTexture has a method of - (BOOL) saveToFile: (NSString *) name
format: (tCCImageFormat) format
. You can read its source code then try to save it into an 2D array instead like byte raw[1024][768]. Each element in this array represents one pixel on your picture(the type may not be byte, I'm not sure, nearly forget the details). The format MUST BE PNG since transparency will be needed.
3) Modify raw data directly, set pixel's transparency to 0x0 which you want it to disappear.
4) Re-initialize a CCRenderTexture using picture data you modified.
I can't provide the code directly since is a trade secret and core part of one of my projects. But I can share you my solution. You also need some knowledge about how PNG file works. Read:
https://en.wikipedia.org/wiki/Portable_Network_Graphics#File_header
Turns out I was making a silly mistake.While supplying values to the textureRect(CGRect),I was actually setting the textureRect.origin.y to the height of the texture which made my textureRect go beyond(above) the texture area.This explains why they were disappearing.

SDL Transparent Overlay

I would like to create a fake "explosion" effect in SDL. For this, I would like the screen to go from what it is currently, and fade to white.
Originally, I thought about using SDL_FillRect like so (where explosionTick is the current alpha value):
SDL_FillRect(screen , NULL , SDL_MapRGBA(screen->format , 255, 255 , 255, explosionTick ));
But instead of a reverse fading rectangle, it shows up completely white with no alpha. The other method I tried involved using a fullscreen bitmap filled with a transparent white (with an alpha value of 1), and blit it once for each explosionTick like so:
for(int a=0; a<explosionTick; a++){
SDL_BlitSurface(boom, NULL, screen, NULL);
}
But, this ended up being to slow to run in real time.
Is there any easy way to achieve this effect without losing performance? Thank you for your time.
Well, you need blending and AFAIK the only way SDL does it is with SDL_Blitsurface. So you just need to optimize that blit. I suggest benchmarking those:
try to use SDL_SetAlpha to use per-surface alpha instead of per-pixel alpha. In theory, it's less work for SDL, so you may hope some speed gain. But I never compared it and had some problem with this in the past.
you don't really need a fullscreen bitmap, just repeat a thick row. It should be less memory intensive and maybe there is a cache gain. Also you can probably fake some smoothness by doing half the lines at each pass (less pixels to blit and should still look like a global screen effect).
for optimal performance, verify that your bitmap is at the display format. Check SDL_DisplayFormatAlpha or possibly SDL_DisplayFormat if you use per-surface alpha

Comparing Sprites?

For a game I'm working on, I'd like to compare two sprites in SFML2, such as with an if() statement. For example, I could have a large 1280x1024 image with one gray pixel among all black pixels. I would then have 2 separate sprites, one is the gray pixel alone, and the other is the map. I would crop only the gray pixel from the map and compare the two, if true, do other things.
Do you see what I'm getting at here? Is this possible? If so, how?
Im with Alex in saying there are smarter ways to check sprites.
Compare the file names not, don't reference a single pixel within an image, because you have to load the entire image into memory to do that atm you are loading 1.3MBytes into memory just to check a single pixel?
Store all of your resources in a Resource Manager and reference them via a UID, if a resource has UID then use that resource.
Number 2 is preferable above all else, but there are many other ways
Edit: As per comments, you wouldn't "crop" out the pixel, you would just load image into memory and use the Image class to get the colour of a pixel at a location. The following would be an example
sf::Image* map = MapSprite->GetTexture()->CopyToImage()
if (map->GetPixel(666,666) == sf::Color::Black)
{
//Funky stuff here
}
NOTE: You mentioned SFML2 so this is from that set of Documentation, may be different for 1.6
Edit2: Its been a while since I've used SMFL so hopefully the code snippet will at least give you direction

Converting image to pixmap using ImageMagic libraries

My assignment is to get "images read into pixmaps which you will then convert to texture maps". So for the pixmap part only, hear me out and tell me if I have the right idea and if there's an easier way. Library docs I'm using: http://www.imagemagick.org/Magick++/Documentation.html
Read in image:
Image myimage;
myimage.read( "myimage.gif" );
I think this is the pixmap I need to read 'image' into:
GLubyte pixmap[TextureSize][TextureSize][3];
So I think I need a loop that, for every 'pixmap' pixel index, assigns R,G,B values from the corresponding 'image' pixel indices. I'm thinking the loop body is like this:
pixmap[i][j][0] = myimage.pixelColor(i,j).redQuantum(void);
pixmap[i][j][1] = myimage.pixelColor(i,j).greenQuantum(void);
pixmap[i][j][2] = myimage.pixelColor(i,j).blueQuantum(void);
But I think the above functions return Quantums where I need GLubytes, so can anyone offer help here?
-- OR --
Perhaps I can take care of both the pixmap and texture map by using OpenIL (docs here: http://openil.sourceforge.net/tuts/tut_10/index.htm). Think I could simply call these in sequence?
ilutOglLoadImage(char *FileName);
ilutOglBindTexImage(ILvoid);
You can copy the quantum values returned by pixelColor(x,y) to ColorRGB and you will get normalized (0.0,1.0) color values.
If you don't have to stick with Magick++ maybe you can try OpenIL, which can load and convert your image to OpenGL texture maps without too much hassle.