Menu

#313 BufferedImage has 2 rendering targets at the same time.

v1.0 (example)
open
nobody
5
2016-10-28
2016-10-17
No

BufferedImage class has currently the problem that it switches rendering between:
- Java WritableRaster
- .Net Bitmap

This causes the problem that it might happen that the pixel data from the .Net Bitmap are not copied to the data array of the WritableRaster.

To reproduce this problem:
1. Create a BufferedImage with a WritableRaster using the following constructor:
bi = BufferedImage(ColorModel cm, WritableRaster raster, boolean isRasterPremultiplied,Hashtable<?,?> properties)
2. Create a Graphics2D object using the local GraphicsEnvironment.
env = GraphicsEnvironment.getLocalGraphicsEnvironment()
env.createGraphics(bi);

This causes the BufferedImage to switch to rendering on the .Net Bitmap, because the getGraphicsEnvironment calls the BufferedImage.getBitmap() method.

From that moment the image data in only copied to the Java WritableRaster data raster, when the bi.getRaster() method is called. Which is incorrect as the image data should always be available in the data raster.

Currently i am working on solving this issue. (17/10/2016)

Discussion

  • Michel van Os

    Michel van Os - 2016-10-17

    My solution for this problem will be that the IKVM BufferedImage uses the following constructor to create a .Net Bitmap:
    Bitmap(Int32, Int32, Int32, PixelFormat, IntPtr)

    That way both the Java WritableRaster and .Net Bitmap should be able to use the same data array. No getBitmap() and getRaster() calls should be needed anymore to copy the data between the objects.

     
  • Volker Berlin

    Volker Berlin - 2016-10-18

    This is not correct. This are only initial data which will be copied. The Bitmap class hold its model in native, not managed memory.

     
  • Michel van Os

    Michel van Os - 2016-10-18

    What do you mean? You replied on my first or on my second post?
    Do you think it's possible to use the constructor i mentioned to solve this problem? I currently don't see any other way to solve this issue.

    Btw i have found 2 more issues.
    1. BufferedImage.getBitmap() doesn't switch the currentBuffer variable to BUFFER_BITMAP.
    2. Something seems to go wrong in BufferedImage.copyToBitmap(int,int,int[]). What i think is going wrong is that the method doesn't use BitmapData.Stride * height to determine the size of the image. But it uses width * height.
    Like i said. I have to call BufferedImage.getRaster() before the data is copied over to the Java WritableRaster. What happens is that all the pixels are written incorrectly to the WritableRaster and all pixels are shifted. So the image looks stretched.

     

    Last edit: Michel van Os 2016-10-18
    • Volker Berlin

      Volker Berlin - 2016-10-18

      What do you mean? You replied on my first or on my second post?
      Do you think it's possible to use the constructor i mentioned to solve this problem? I currently don't see any other way to solve this issue.

      I means the constructor does not solve the problem of duplicate image data. The value in the constructor are only initial data. It will be copied to thze native Buffer.

      1. BufferedImage.getBitmap() doesn't switch the currentBuffer variable to BUFFER_BITMAP.

      If the buffer must be copied then it switch to BUFFER_BOTH. This is correct because both buffer contains then the same data.

      1. Something seems to go wrong in BufferedImage.copyToBitmap(int,int,int[]). What i think is going wrong is that the method doesn't use BitmapData.Stride * height to determine the size of the image. But it uses width * height.
        Like i said. I have to call BufferedImage.getRaster() before the data is copied over to the Java WritableRaster. What happens is that all the pixels are written incorrectly to the WritableRaster and all pixels are shifted. So the image looks stretched.

      I does not understand this. Can you create a junit test case?

       
  • Michel van Os

    Michel van Os - 2016-10-19

    I was able to make it work to share the image data between a Java WritableRaster and a .Net Bitmap without copying any data. But there is still something going wrong when rendering the BufferedImage on screen and i don't know what it is atm. Is it possible to debug the IKVM java code? Like the BufferedImage class? That would be very usefull for me.

    I provide a C# file which shows the rendering issue.
    1. The 1st example shows 3 windows. The window where the bufferedImageToRender is rendered to will remain empty. Like i said. This is caused because the getRaster() is not called for that BufferedImage.
    2. The 2nd example shows a fix to share memory between the WritableRaster and the BufferedImage. Note that i am currently not sure whether the Stride has been calculated correctly.

     
    • Volker Berlin

      Volker Berlin - 2016-10-19

      This is exactly the use case that not work and can not fix because there are two buffers. You use the Java buffer of the BufferedImage outside of the BufferedImage and then modify the .NET buffer.

      Theoretical there are 2 possible solutions to solve this:

      • Implement the Graphics interface with the usage of the Java buffer. This required a reimplementing of the native part of the Java VM. This is a Job for complettely team.
      • Sync every draw operation immediately to the Java buffer. The performance will be poor.
       

      Last edit: Volker Berlin 2016-10-22
    • Volker Berlin

      Volker Berlin - 2016-10-22

      A possible solution for this problem with shared WritableRaster can be to move the double Buffer with Bitmap from the BufferedImage into the WritableRaster. But the WritableRaster does not know any about the color model (image type). I does not know if this can be solved. But in any case it will a large amount of work.

       
  • Michel van Os

    Michel van Os - 2016-10-25

    I am currently not sure whether the company i work for wants to continue using IKVM for rendering SVG graphics. Because we currently find too many rendering issues.
    1. Rendering some SVG graphics result in pixels ending misaligned.
    At first i thought it had something to do with using an incorrect stride. But after i used shared memory between a WritableRaster and a .Net Bitmap it didn't show this error for this WritableRaster. It only shows this error for the WritableRaster that was used in a different/disconnected BufferedImage. I have no idea why this is hapening.

    1. All SVG graphics contain transparant lines. I also have no idea why this is hapening.
    2. We don't get the .Net Bitmap graphics back unless we call the getRaster() method. Which should not be required.

    All these errors occur when using Apache Batik with IKVM. None of these errors occur when we use the same SVG files directly from Java. I'll provide a screen shot which displays the errors we get.
    1. Top left image shows transparent lines.
    2. Top right image shows misaligned pixels with transparant lines.
    3. Bottom image shows SVG graphics from 1 and 2 combined.

    I've also tried the samples provided by Apache Batik with IKVM. With these example we also always get a transparant image back.

     

    Last edit: Michel van Os 2016-10-25
    • Volker Berlin

      Volker Berlin - 2016-10-25

      Can you point to the sample that you means?

      Batik is a library which use extremly the Graphics API. An emulation of this API will never produce 100% of the same result.

       
  • Michel van Os

    Michel van Os - 2016-10-28

    Using Batik 1.8 running the /batik-1.8/batik-rasterizer-1.8.jar exported transparant images.

     

Log in to post a comment.