i use a bufferedImage to load textures inside my resource folder like this:
i use ImageLoader class to load images
...
public static final BufferedImage images = loadImages("/images/images.jpg");
private static BufferedImage loadImages(String string) {
BufferedImage image = null;
try {
image = ImageIO.read(ImageLoader.class.getResourceAsStream(string));
} catch (Exception e) {
e.printStackTrace();
}
return image;
}
but when i add this to one of my objects like:
...
graphic.drawImage(ImageLoader.images.getScaledInstance(200,200.java.awt.Image.SCALE_SMOOTH), (int) objects.get(i).getX() - objects.get(i).getWidth() / 2, (int) objects.get(i).getY()
- objects.get(i).getHeight() / 2, objects.get(i).getWidth(),objects.get(i).getHeight(), null);
it slows down a lot my app , there is a way more efficent to load images, and more imporant,
is there a way to prevent slowdown of the application?
Make a list of the scaled images as field. And of course it would be nicer to use a variable:
// Field
List<Image> images = new ArrayList<>();
// Once, maybe in the constructor
... object = objects.get(i);
images.add(...);
Then in the painting method only
graphic.drawImage(images.get(i), ...);
Related
I got to that point when I have to replace all new Sprite(texture) with new Sprite(manager.get(imgPath,Texture.class)) in order to optimize sprites creating and do all the loading before starting the game.
The problem is that when I use a common AssetManager to load all textures I get black rectangles.
Still, using a new AssetManager() each time I need to load a Texture works fine (maybe because this manager is quickly garbadge-collected and doesn't have time to dispose the texture it created?) but that way there is no point of using it.
The setupBody() method below is called at the end of my sprite-body wrapper constructor.
the working code (yet useless) ─ one new AssetManager for each sprite:
protected void setupBody(String path){
BodyEditorLoader loader = new BodyEditorLoader(Gdx.files.internal(path));
BodyDef bDef = new BodyDef();
bDef.type = BodyDef.BodyType.DynamicBody;
bDef.position.set(this.position);
bDef.angle = this.rotation;
body = mWorld.createBody(bDef);
body.setUserData(this);
FixtureDef fix = new FixtureDef();
fix.density = 0.1f;
fix.friction = 0f;
fix.restitution = 0.5f;
fix.filter.categoryBits = this.getCategory();
fix.filter.maskBits = this.getMask();
origin = loader.getOrigin("base"+identifier, 1).cpy();
String imgPath = loader.getImagePath("base"+identifier);
AssetManager manager = new AssetManager();
manager.load(imgPath,Texture.class);
manager.finishLoading();
Texture baseSpriteTexture = manager.get(imgPath,Texture.class);
Texture baseSpriteTexture = new Texture(imgPath);
baseSprite = new Sprite(baseSpriteTexture);
loadHighlightedSprite(loader, identifier);
attachFixture(loader, identifier, fix);
}
the code keeping me sleepless ─ the idea is to have a single non-static manager :
protected void setupBody(String path){
/*no changes before */
String imgPath = loader.getImagePath("base"+identifier);
AssetManager manager = SmallIntestineDemoGame.getAssets();
manager.load(imgPath,Texture.class);
/* no changes after */
}
SmallIntestineDemoGame$getAssets() :
public class SmallIntestineDemoGame extends Game {
public AssetManager assets;
#Override
public void create() {
setScreen(new GameScreen());
}
public static AssetManager getAssets() {
return ((SmallIntestineDemoGame) Gdx.app.getApplicationListener()).assets;
}
public void setupAssets(){
this.assets = new AssetManager();
Texture.setAssetManager(assets);
}
}
DEBUGGING :
Debugging my asset manager got me confused. size of values of values of assets map of manager gets stuck at 33 even if I'm adding more:
(source: hostingpics.net)
I tested both cases ─ the app with a new AssetManager() (followed by finishloading and all required stuff) for each sprite creation. AND with a unique asset manager passed to all sprite creations :
I set a breakpoint at draw method and there was almost no difference between the two sprites, except for sprite.texture.glhandle !
When all sprites textures are created using the same manager their textures glhandle is set to 0 and this explains the black rectangles. But when each sprite is created using a locally newly created asset manager, the glhandle has some proper value (2269).
Texture.setAssetManager(assets);
When you set AssetManager then you need to call update() method of AssetManager each time when your game resumed.
If you don't set the AssetManager, the usual managed texture mechanism will kick in, so you don't have to worry about anything.
I am looking at a code sample that explains the proxy pattern. Here is the code:
/**
* Proxy
*/
public class ImageProxy implements Image {
/**
* Private Proxy data
*/
private String imageFilePath;
/**
* Reference to RealSubject
*/
private Image proxifiedImage;
public ImageProxy(String imageFilePath) {
this.imageFilePath= imageFilePath;
}
#Override
public void showImage() {
// create the Image Object only when the image is required to be shown
proxifiedImage = new HighResolutionImage(imageFilePath);
// now call showImage on realSubject
proxifiedImage.showImage();
}
}
/**
* RealSubject
*/
public class HighResolutionImage implements Image {
public HighResolutionImage(String imageFilePath) {
loadImage(imageFilePath);
}
private void loadImage(String imageFilePath) {
// load Image from disk into memory
// this is heavy and costly operation
}
#Override
public void showImage() {
// Actual Image rendering logic
}
}
/**
* Image Viewer program
*/
public class ImageViewer {
public static void main(String[] args) {
// assuming that the user selects a folder that has 3 images
//create the 3 images
Image highResolutionImage1 = new ImageProxy("sample/veryHighResPhoto1.jpeg");
Image highResolutionImage2 = new ImageProxy("sample/veryHighResPhoto2.jpeg");
Image highResolutionImage3 = new ImageProxy("sample/veryHighResPhoto3.jpeg");
// assume that the user clicks on Image one item in a list
// this would cause the program to call showImage() for that image only
// note that in this case only image one was loaded into memory
highResolutionImage1.showImage();
// consider using the high resolution image object directly
Image highResolutionImageNoProxy1 = new HighResolutionImage("sample/veryHighResPhoto1.jpeg");
Image highResolutionImageNoProxy2 = new HighResolutionImage("sample/veryHighResPhoto2.jpeg");
Image highResolutionImageBoProxy3 = new HighResolutionImage("sample/veryHighResPhoto3.jpeg");
// assume that the user selects image two item from images list
highResolutionImageNoProxy2.showImage();
// note that in this case all images have been loaded into memory
// and not all have been actually displayed
// this is a waste of memory resources
}
}
Assume proxy pattern is implemented correctly, and this is the main method of the program. Here is what i wonder: The comments in the code say that when we use proxy image objects, if we load a picture into memory, just that image is loaded. But if we do not use proxy and directly create real images, when we load an instance of this class, we load all instances of the class into memory. I do not understand why this is the case. Yes, the whole point of proxy pattern is to do this, but i do not understand why all 3 of the highResolutionImageNoProxy objects are loaded into memory when we call highResolutionImageNoProxy2.showImage(); . Can anyonbody explain it?
Thanks
Edit: I think i figured out why. Because the ImageProxy class calls the constructor of HighResolutionImage class only when it tries to do an operation on the object, but if we create a HighResolutionImage directly, then since its constructor creates the object, all of them are loaded into memory.
The code assumes that when you create an instance of HighResolutionImage, the image is loaded to the memory, even if showImage() isn't called.
The proxy will assure that the image is loaded to the memory only when showImage() is called.
//load veryHighResPhoto1 to memory
Image highResolutionImageNoProxy1 = new HighResolutionImage("sample/veryHighResPhoto1.jpeg");
//load veryHighResPhoto2 to memory
Image highResolutionImageNoProxy2 = new HighResolutionImage("sample/veryHighResPhoto2.jpeg");
//load veryHighResPhoto3 to memory
Image highResolutionImageBoProxy3 = new HighResolutionImage("sample/veryHighResPhoto3.jpeg");
//load just the proxys (image not loaded yet)
Image highResolutionImage1 = new ImageProxy("sample/veryHighResPhoto1.jpeg");
Image highResolutionImage2 = new ImageProxy("sample/veryHighResPhoto2.jpeg");
Image highResolutionImage3 = new ImageProxy("sample/veryHighResPhoto3.jpeg");
//trigger the load of the image into memory
highResolutionImage1.showImage();
I am using Flyingsaucer to generate PDF. I am trying to embed image in the pdf by implementing ReplacedElementFactory. I can generate pdf replaced with the image. No problem.
But what I wanted was to set the image height and width dynamically from within the class. I need to scale the image to a definite size. I will find the new scaled height and width of the image and want these scales to be set for the image embedded.
Can I add the style attribute in the Element fetched from BlockBox and update this element? Will this work? I tried using blackBox.setElement, but it does not work.
Could anyone help?
EDIT:
Peter Brant from flying saucer google group suggested the following
Override getIntrinsicHeight / getIntrinsicWidth in your ReplacedElement implementation. Note those values will be in render "dots" not pixels so you may have to scale appropriately.
But unfortunately it did not work for me. I overrode ReplaceElement of flying saucer and returned height and width. It did not work for me. The sample code I tried was here
public class MyITextImageElement implements ITextReplacedElement
{
private final FSImage fsImage;
private float[] scaledWidthAndHeight = null;
public MyITextImageElement(FSImage image)
{
fsImage = image;
try
{
ITextFSImage itextFSImage = (ITextFSImage) image;
Image itextImage = itextFSImage.getImage();
byte[] imageByteArr = itextImage.getOriginalData();
//Getting scaled image height and width
scaledWidthAndHeight = getScaledWidthAndHeight(imageByteArr);
}
catch (Exception e)
{
//Exception Handling
}
}
#Override
public int getIntrinsicWidth()
{
if (scaledWidthAndHeight != null)
{
return Math.round(scaledWidthAndHeight[0]);
}
return fsImage.getWidth();
}
#Override
public int getIntrinsicHeight()
{
if (scaledWidthAndHeight != null)
{
return Math.round(scaledWidthAndHeight[1]);
}
return fsImage.getHeight();
}
...........
...........
}
I have a getViewBitmap() method that creates a Bitmap with a 3rd party library (which is proprietary) and goes like this:
public Bitmap getViewBitmap(int index) {
Bitmap retBitmap = null;
int width = 400;
int height = 200;
try {
retBitmap = lib.createBitmap(width, height, index);
} catch(BMException e) {
e.printStacktrace();
}
return retBitmap;
}
This method is used for creating two page view bitmap in another method:
public Bitmap getTwoPageBitmap(int firstPageIndex, intSecondPageIndex) {
Bitmap first = getViewBitmap(firstPageIndex);
Bitmap second = getViewBitmap(secondPageIndex);
Bitmap retBitmap = Bitmap.create(800, 400, first.getConfig());
Canvas helperCanvas = new Canvas(splitViewBm);
helperCanvas.drawBitmap(leftPageBitmap, 0, 0, null);
helperCanvas.drawBitmap(rightPageBitmap, leftPageBitmap.getWidth(), 0, null);
return retBitmap;
}
And then finally in initiated method, I have this:
public View createView() {
MyView v = new MyView();
if(pagePortratit) {
v.setPageView(getViewBitmap(0));
} else {
// if page is landscape
v.setPageView(getTwoPageBitmap(0, 1));
}
return v;
}
Now - I wanna make the getViewBitmap(int) method Asynchronous. Since the "lib.createBitmap(int, int, int)" is pretty slow and it blocks the UI, I want the creation of the bitmap (getViewBitmap(int)) to be in another thread, with possibility to interrupt it's work.
What is the correct design for such design so that the method that is actually heavy goes async?
You likely want to subclass AsyncTask (read here) and put your getBitmapView code in the doInBackground() method (#Override). When it's done, have the onPostExecute() method update the View/UI. The logic for determining landscape or portrait will want to be outside the AsyncTask and you'll just want to farm out to the task (using .execute()) which ever view is needed.
That might be one approach.
I think the best thing that you can do is to use AysncTask which allows u to update the UI Directly without special handling for UI Thread update.
I try to use the ClientBundle implementation to manage my Images to a large File and minimize the HTTP-Requests.
I put in my gwt.xml
Generate the ClientBundle
public interface ResourceBundle extends ClientBundle {
public static final ResourceBundle INSTANCE = GWT.create(ResourceBundle.class);
#Source("tiles/smiley.png")
ImageResource smiley();
}
The Image would be found, no errors.
Here is the code
#Override
public void onModuleLoad() {
CLogger.log("Start Engine");
int width = 800;
int height = 600;
Canvas canvas = Canvas.createIfSupported();
canvas.setWidth(width + "px");
canvas.setHeight(height + "px");
canvas.setCoordinateSpaceWidth(width);
canvas.setCoordinateSpaceHeight(height);
Context2d c = canvas.getContext2d();
Image img = new Image(ResourceBundle.INSTANCE.smiley());
img.addLoadHandler(new LoadHandler() {
#Override
public void onLoad(LoadEvent event) {
CLogger.log(event.getSource() + " loaded");
}
});
CLogger.log("Visible: " + img.isVisible());
c.drawImage((ImageElement) new Image(ResourceBundle.INSTANCE.smiley()).getElement().cast(), 0, 0);
RootPanel.get().add(canvas);
}
I create a simple Canvas and set the size to 800x600. I create a new Context2D Object to draw the Image at the Context and add the Canvas to the RootPanel.
The logs shows:
[20:10:21.676] - Start Engine
[20:10:21.851] - Visible: true
[20:10:21.853] - http://127.0.0.1:8888/engine/7D39451825E9952050F44A6B8E2E15F3.cache.png
The Image exists under the logged URL so everything looks fine. But the Image would not be draw or it would draw but not display.
Anybody an idea?
I thought the ClientBundle loads the Images as the start in the backend. So if I get an Instance every Image/Css and others fill be loaded?
Regars Markus
Image contents aren't guaranteed to be loaded synchronously. Depending on the capabilities of the browser and the size of the image data, the resource may be stored as a standalone file, which appears to be the case that you're describing (i.e. cache.png). Does a formulation like this make any difference?
final Image img = new Image(ResourceBundle.INSTANCE.smiley());
img.addLoadHandler(new LoadHandler() {
public void onLoad(LoadEvent e) {
c.drawImage((ImageElement) img.getElement());
}
}
RootPanel.get().add(img);
If you use CSSResources and ImageBundles outside of UiBinder you have to make sure that the stlyesheet and images are injected properly.
See here for more information.