I am writing a GameObject class for monogame(sprite's position, alpha, rotation, ect...)
And I got a problem when i've started scaling images. Is there a way to scale images without losing quality?
Here is how I am rendering everything
foreach (KeyValuePair<int, GameObject> go in RenderObjects)
{
spriteBatch.Draw(go.Value.img, go.Value.getRect(), go.Value.RenderArea, Color.White * (float)go.Value.alpha, (float)go.Value.rotation, go.Value.getCenter(), SpriteEffects.None, 0f);
}
And here is what happends if you try to scale a 16x64 image to 160x640
Click to see the image
^^^^^^^^^^^^^^^^^^
I've been messing around with monogame, and I've accidently found the solution.
You just need to add some parameters to spriteBatch.Begin();
spriteBatch.Begin(... , ... ,SamplerState.PointClamp);
foreach (KeyValuePair<int, GameObject> go in RenderObjects)
{
spriteBatch.Draw(go.Value.img, go.Value.getRect(), go.Value.RenderArea, Color.White * (float)go.Value.alpha, (float)go.Value.rotation, go.Value.getCenter(), SpriteEffects.None, 0f);
}
spriteBatch.End();
There are actualy more ways to do it, but I don't quite understand how. Something to do with graphics.GraphicsDevice
Related
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.
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.
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.
This is my set-up:
stage = new Stage(1280, 800, false);
button = new Button(drawableUp, drawableDown);
stage.add(button);
this gets rendered as following:
#Override
public void render(float delta) {
Gdx.gl.glClearColor(RED,GREEN,BLUE,ALPHA);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act(delta);
stage.draw();
}
The issue is that when the stage is shown on 1280x800 the button looks like that:
If the stage is rescaled to e.g. 1280x736, the button drawable is scaled in the following way:
Is there a way to smooth out the edges somehow? Because right now it looks to me that the scaling is simply done by removing one pixel line in the upper half and one in the lower half of the picture.
Are you using filters anywhere in your code? If not, then try this:
texture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
Where texture is the texture object that you're using.
var bd:BitmapData=new BitmapData(file.width,file.height);
bd.setPixels(new Rectangle(0,0,file.width,file.height),file.raw);
var scale_x_percents:Number = (w / bd.width);
var scale_y_percents:Number = (h / bd.height);
if(!stretch) {
if(bd.width*scale_y_percents>=w) {
scale_x_percents=scale_y_percents;
}
else if(bd.height*scale_x_percents>=h) {
scale_y_percents=scale_x_percents;
}
}
var matrix:Matrix = new Matrix();
matrix.scale(scale_x_percents,scale_y_percents);
var resizedBd:BitmapData = new BitmapData(Math.floor(bd.width*scale_x_percents), Math.floor(bd.height*scale_y_percents), true, 0x000000);
resizedBd.draw(bd, matrix, null, null, null, true); // true is smoothing option, it will blur sharpened pixels
Having problem with images resizing. Looks like smoothing is not working or something is missing in the code. Maybe Matrix should have something more?
Original image:
http://imageshack.us/a/img28/4784/dc7f2ec4b0f3323cdc4e01e.jpg
and it's result:
http://imageshack.us/a/img855/4784/dc7f2ec4b0f3323cdc4e01e.jpg
I can link a bunch of others images. Some strange pixel disposition exist.
Can it be fixed somehow?
I have tested jpeg quality 100% and stage.quality='best', but none of them give the required quality outcome.
It seems that your problem is "nearest" sampling mode when drawing a BitmapData over a BitmapData. Perhaps the following might help:
var sh:Shape=new Shape();
sh.graphics.beginBitmapFill(bd,matrix,false,true);
sh.graphics.lineStyle(0,0,0); // no lines border this shape
sh.graphics.drawRect(0,0,resizedBD.width,resizedBD.height);
sh.graphics.endFill();
resizedBD.draw(sh); // or with smoothing on
Using Flash's native graphics renderer will most likely perform at least a bilinear interpolation on a drawn bitmap, which seemingly is your desired result. Also, stage.quality applies if that shape is added to stage (BTW, you can use the shape to display an uploaded pic, then draw over a BitmapData in order to save.) But, this might not work - I can't test this right now.