can't get the image to rotate in center in Qt - image

i am trying to rotate a 89x89 image inside the QLabel Widge.
#include "header.h"
disc::disc(QWidget *Parent) : QWidget(Parent)
{
orig_pixmap = new QPixmap();
rotate = new QLabel(this);
showDegrees = new QLabel(this);
orig_pixmap->load("pic.png");
degrees = 0;
rotate->resize(89,89);
rotate->move(100,10);
rotate->setStyleSheet("QLabel{background-color:red;}");
showDegrees->resize(100,100);
showDegrees->move(400,0);
}
void disc::rotate_disc()
{
QString string;
degrees++;
if(degrees == 360) degrees = 0;
QTransform rotate_disc;
rotate_disc.translate( (orig_pixmap->width()-rotate->width())/2 , (orig_pixmap->width()-rotate->height())/2);
rotate_disc.rotate(degrees,Qt::ZAxis);
QPixmap pixmap;
//pixmap = orig_disc->scaled(89,89,Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
pixmap = orig_pixmap->transformed(rotate_disc,Qt::SmoothTransformation);
rotate->setPixmap(pixmap);
string.append("Degrees: " + QString::number(degrees) + "*");
showDegrees->setText(string);
}
Even though it rotates. The image's half gets rolled outside the QLabel and hence that side is not visible.How can i make it center rotate at origin(0,0) of the image center.
Here is the file
http://www65.zippyshare.com/v/85775455/file.html
if you look at it you can see that image is like bouncing to the left.how can i make it rotate inside the black area.
i setup a signal timeout at every 10ms to the rotate_disc() function. I am using this to learn Qt indepth.
Thank You!

I've done it like this...
//Move windows's coordinate system to center.
QTransform transform_centerOfWindow( 1, 0, 0, 1, width()/2, height()/2 );
//Rotate coordinate system.
transform_centerOfWindow.rotate( m_LoadingDisk_degrees );
//Draw image with offset to center of image.
QPainter painter( this );
//Transform coordinate system.
painter.setTransform( transform_centerOfWindow );
//Load image.
//Notice: As coordinate system is set at center of window, we have to center the image also... so the minus offset to come to center of image.
painter.drawPixmap( -loadingDisk.width()/2, -loadingDisk.height()/2, loadingDisk );

I think all you're really missing is the initial translation to do the rotation around the centre of the pixmap.
Move it to the origin, rotate, then move it back. And remember, transformations are applied in reverse order from how you'd expect, given how you specify them in the code.
QTransform rotate_disc;
rotate_disc.translate(orig_pixmap->width()/2.0 , orig_pixmap->height()/2.0);
rotate_disc.rotate(degrees);
rotate_disc.translate(-orig_pixmap->width()/2.0 , -orig_pixmap->height()/2.0);

If you are making a loading indicator, animated gif would be much easier. See GIF animation in Qt

Related

Solving Overlapping Images when zooming in Codenameone

I have an imageviewer with a couple images, When i zoom in the first image and wanna see the right side of the image. The folowing image is overlapping the inzooming image. This is very annoying. Is there a way how i can set the zoom in image on the front.
How can i set the zoomed image always on front.
See picture https://i.stack.imgur.com/5f5JZ.jpg
My imageviewer is in a container
Image red ;
red = EncodedImage.create("/HW_Delfzijl_Waddenzee_Oost.jpg");
Image blue = Image.createImage(500, 500, 0xff0000ff);
Image red2 = Image.createImage(500, 500, 0xffff0000);
Image List1[]= new Image [3];
List1[0] = red;
List1[1] = blue;
List1[2] = red2;
iv = new ImageViewer();
iv.setWidth(500);
iv.setHeight(500);
iv.setImageList(new DefaultListModel<>(List1));
Container1 = BoxLayout.encloseY( Kaarten.AuvHW, AdvSpr,iv,
Up,progressbar);
I was able to reproduce this with the following code:
Form hi = new Form("ImageViewer", BoxLayout.y());
Image red = Image.createImage(2000, 800, 0xffff0000);
Image blue = Image.createImage(2000, 500, 0xff0000ff);
ImageViewer viewer = new ImageViewer();
viewer.setImageList(new DefaultListModel<>(red, blue));
hi.add(BoxLayout.encloseY(viewer, new Label("Dummy")));
hi.show();
The problem only happens if I stand on the blue image (the second one) scale it up and then try to move. It doesn't happen when moving from the red image to the blue.
I believe this is due to this method in the ImagaViewer code. Since background isn't painted the old image isn't cleaned up. We need to add a condition that disables that while dragging. I think changing the code in that method to this will fix the problem but it's a bit risky and might trigger flickering:
protected void paintBackground(Graphics g) {
// disable background painting for performance when zooming
if(imageDrawWidth < getWidth() || imageDrawHeight < getHeight() || panPositionX != 0) {
super.paintBackground(g);
}
}
I would suggest filing an issue so we can consider the options here as this isn't trivial. One partial workaround is to use:
viewer.setImageInitialPosition(ImageViewer.IMAGE_FILL);
Which minimizes the impact of the issue.

is it possible in Unity to slice image from the middle?

I get an image from the backend which I want to put in a puzzle shuffle game, however right now it is cropping from left to almost middle of the image , I would like to crop the center of the image, I was trying to use another Sprite which I cropped to the middle then use it in the ImageSlicer however I am getting same results.
Here are the images :
Main Image , Cropped Image as temp , Sliced Image as imagesSlices
am I doing the right thing and maybe I'm messing something in the code or this isn't how I should crop and slice ?
Sprite temp = Sprite.Create(currentImage, new Rect(currentImage.width * 0.25f, 0, currentImage.width * 0.75f, currentImage.height),new Vector2(0.5f, 0.5f), 100.0f);
Texture2D[,] imageSlices = ImageSlicer.GetSlices(temp.texture, blocksPerLine);
So the texture was staying the same and I was trying to get a new sprite not a new texture but I need a new cropped texture to work with which is why the sliced images were taken from old texture.

Unity-3d-5 Scale images for 16:9 to other resolutions

So I created a snake game with a border created with 2d sprites. I have my game window set to 16:9, when in this resolution the images look fine. However, scaling to anything else begins to make the game look weird. I want the game window to be re-sizable. How can I make my sprites stretch and shrink based on the current resolution?
I have already tried creating a sprite that is 120 in Width and 1 in Height, then using the x,y,z scales to change the scale to 16. This produced a huge sprite.
I am experimenting with using a canvas scaler, but with no success.
My end goal isn't to have my game fit pre-defined resolutions like 16:9, but to scale according to the current window size. So that if they make the window extremely thin, the game will only make the top and bottom borders extremely thin, while still confing the game play into the borders.
Below I post the screenshots of how my sprites are setup. And how they are placed into the hierarchy.
Border sprite - this sprite's width is now 70 pixels, because this is how it was given to me.
Border in hierarchy, position, scale, and rotation are defaults. Then for example the BorderTop is moved 25 on the y axis to move it to the top of the screen.
Camera setup
Example resolutions and current output
16:9
5:4
Add a simple script to every border:
public class Border : MonoBehaviour {
enum BorderTypes
{
bottom, top, left, right
}
[SerializeField] float borderOffset = 0.1f;
[SerializeField] BorderTypes type = BorderTypes.top;
// Use this for initialization
void Start () {
switch (type)
{
case BorderTypes.bottom:
transform.position = Camera.main.ViewportToWorldPoint(new Vector3(0.5f, borderOffset, 10));
break;
case BorderTypes.top:
transform.position = Camera.main.ViewportToWorldPoint(new Vector3(0.5f, 1 - borderOffset, 10));
break;
case BorderTypes.left:
transform.position = Camera.main.ViewportToWorldPoint(new Vector3(borderOffset, 0.5f, 10));
break;
case BorderTypes.right:
transform.position = Camera.main.ViewportToWorldPoint(new Vector3(1 - borderOffset, 0.5f, 10));
break;
default:
break;
}
}
}
You can use a simple way:
First, create a Canvas
in Canvas component in Inspector, set Render Mode to Screen Space - Camera and drag your main camera to Render Camera field.
Then, in Canvas Scaler component in Inspector window, set UI Scale Mode to Scale Width Screen Size and other settings like this image
Now drag your game objects to Canvas.
First, you should not change your sprites. You problem is a game viewport. You simply cannot have 16:9 fixed aspect ratio on every device in "full-screen". You have 2 options here:
Don't care about aspect ratio and adapt your gameplay, make your canvas scalermode to "scale with screen size" and reference resolution something like 1920x1080 or 1600:900 or 800:450. Your game logic must take into account that you may have different size of screens. You can experiment in editor by switching different aspect ratios in game view.
Maintain 16:9 and therefore calculate for where to add "bars" (sides or top and down), when the game is initialized.

Is it possible to save a generated image in Codename One?

My question is related to this previous question. What I want to achieve is to stack images (they have transparency), write a string on top, and save the photomontage / photocollage with full resolution.
#Override
protected void beforeMain(Form f) {
Image photoBase = fetchResourceFile().getImage("Voiture_4_3.jpg");
Image watermark = fetchResourceFile().getImage("Watermark.png");
f.setLayout(new LayeredLayout());
final Label drawing = new Label();
f.addComponent(drawing);
// Image mutable dans laquelle on va dessiner (fond blanc)
Image mutableImage = Image.createImage(photoBase.getWidth(), photoBase.getHeight());
drawing.getUnselectedStyle().setBgImage(mutableImage);
drawing.getUnselectedStyle().setBackgroundType(Style.BACKGROUND_IMAGE_SCALED_FIT);
// Paint all the stuff
paints(mutableImage.getGraphics(), photoBase, watermark, photoBase.getWidth(), photoBase.getHeight());
// Save the collage
Image screenshot = Image.createImage(photoBase.getWidth(), photoBase.getHeight());
f.revalidate();
f.setVisible(true);
drawing.paintComponent(screenshot.getGraphics(), true);
String imageFile = FileSystemStorage.getInstance().getAppHomePath() + "screenshot.png";
try(OutputStream os = FileSystemStorage.getInstance().openOutputStream(imageFile)) {
ImageIO.getImageIO().save(screenshot, os, ImageIO.FORMAT_PNG, 1);
} catch(IOException err) {
err.printStackTrace();
}
}
public void paints(Graphics g, Image background, Image watermark, int width, int height) {
g.drawImage(background, 0, 0);
g.drawImage(watermark, 0, 0);
g.setColor(0xFF0000);
// Upper left corner
g.fillRect(0, 0, 10, 10);
// Lower right corner
g.setColor(0x00FF00);
g.fillRect(width - 10, height - 10, 10, 10);
g.setColor(0xFF0000);
Font f = Font.createTrueTypeFont("Geometos", "Geometos.ttf").derive(220, Font.STYLE_BOLD);
g.setFont(f);
// Draw a string right below the M from Mercedes on the car windscreen (measured in Gimp)
g.drawString("HelloWorld",
(int) (848 ),
(int) (610)
);
}
This is the saved screenshot I get if I use the Iphone6 skin (the payload image is smaller than the original one and is centered). If I use the Xoom skin this is what I get (the payload image is still smaller than the original image but it has moved to the left).
So to sum it all up : why is the saved screenshot with Xoom skin different from the one I get with Iphone skin ? Is there anyway to directly save the graphics on which I paint in the paints method so that the saved image would have the original dimensions ?
Thanks a lot to anyone that could help me :-)!
Cheers,
You can save an image in Codename one using the ImageIO class. Notice that you can draw a container hierarchy into a mutable image using the paintComponent(Graphics) method.
You can do both approaches with draw image on mutable or via layouts. Personally I always prefer layouts as I like the abstraction but I wouldn't say the mutable image approach is right/wrong.
Notice that if you change/repaint a lot then mutable images are slower (this will not be noticeable for regular code or on the simulator) as they are forced to use the software renderer and can't use the GPU fully.
In the previous question it seems you placed the image with a "FIT" style which naturally drew it smaller than the containing container and then drew the image on top of it manually... This is problematic.
One solution is to draw everything manually but then you will need to do the "fit" aspect of drawing yourself. If you use layouts you should position everything based on the layouts including your drawing/text.

Drawing on image and saving

I guess I don't really understand how Graphics objects work in Visual C++ 2010 Express.
I am grabbing a frame from a webcam, and drawing a circle on it. It works great on the screen. I simply create a Graphics object, draw the image, and draw the ellipse.
In the pictureBox_paint function, I have
Graphics^ g = e->Graphics; // from the camera
System::Drawing::Rectangle destRect = System::Drawing::Rectangle(0,0,pbCameraMonitor->Size.Width,pbCameraMonitor->Size.Height);
double slitHeightToWidth = 3;
g->DrawImage(this->currentCamImage,destRect);
int circleX, circleY;
circleX = (int) (pbCameraMonitor->Size.Width - radius/slitHeightToWidth)/2;
circleY = (int) (pbCameraMonitor->Size.Height - radius)/2;
g->DrawEllipse(Pens::Red, circleX, circleY, (int) radius/slitHeightToWidth, (int) radius);
So far so good, my ellipse gets drawn on there nicely. The destRect bit makes sure it is scaled to the pictureBox size. I simply invalidate the pictureBox every time the camera reports a new image, and I have video.
Now, on a button click I want to save this image, with the red ellipse on it. However, I don't want the rescaled version shown on the screen, I want the full res version. So, I'll grab another frame into a Bitmap^ called "grabbedFrame" and do this:
String ^photofile = "Image_" + expRecord.timestamp.ToString("s") + ".jpg"; // get a unique filename
photofile = photofile->Replace(':', '_');
Graphics^ g = Graphics::FromImage(grabbedFrame);
g->DrawEllipse(Pens::Red, 20, 20, 20, 20); // circle size fixed just for demo
grabbedFrame->Save(photofile, System::Drawing::Imaging::ImageFormat::Jpeg);
When I do that, I get a save of the image without the red circle.
Does g->DrawEllipse actually modify the Bitmap? Or just contain the Bitmap + instructions to draw? If the latter, how does the pictureBox know the Bitmap has been modified? If the former, why doesn't my save contain the modification?
How can I save the modified Bitmap?
You need to draw the loaded image into a new Bitmap, make your modifications to that bitmap, and then save it.
Something like (pseudo-code'ish):
// create bitmap and get its graphics
Bitmap^ pBmp = gcnew Bitmap(grabbedFrame->Width, grabbedFrame->Height);
Graphics^ g = Graphics::FromImage(pBmp);
// draw grabbed frame into bitmap
g->DrawImage(grabbedFrame, 0, 0, grabbedFrame->Width, grabbedFrame->Height);
// draw other stuff
g->DrawEllipse(Pens::Red, 20, 20, 20, 20);
// save the result
pBmp->Save(photofile, System::Drawing::Imaging::ImageFormat::Jpeg);

Resources