jwharm/cairo-java-bindings

ImageSurface.getData() Method Fails to Retrieve Data

Closed this issue · 2 comments

Hello,

I am experiencing a problem with specifically with the ImageSurface.getData() method. The issue is that the function does not seem to work as expected.

The getData() function, which is supposed to return a pointer to the image data of a surface, is not functioning correctly in my example. When I call getData(), the returned MemorySegment shows a byteSize() of 0 which is incorrect.

public class CairoPngExample {

    public static void main(String[] args) throws IOException {
        int width = 400;
        int height = 300;
        try (var surface = ImageSurface.create(Format.RGB24, width, height)) {
            var cr = Context.create(surface);
            cr.setSourceRGB(1, 0, 0);
            cr.rectangle(0, 0, width, height);
            cr.fill();
            cr.setSourceRGB(1, 1, 0);
            cr.moveTo(100, 200);
            cr.setFontSize(100);
            cr.selectFontFace("Segoe UI", FontSlant.NORMAL, FontWeight.BOLD);
            cr.showText("Hello");
            
            surface.flush();
            
            System.out.println(surface.getData().byteSize()); // prints 0
            
            surface.writeToPNG("example.png");
        }
    }
}

As a workaround, I provided my custom allocated buffer and was able to read the data. However, the problem still exists when using getData(). It continues to return 0, which is incorrect.

public class CairoPngExampleCustomSurface {

    public static void main(String[] args) throws IOException {
        int width = 400;
        int height = 300;
        
        int stride = ImageSurface.formatStrideForWidth(Format.RGB24, width);
        MemorySegment data = Arena.ofAuto().allocate(stride * height);

        try (var surface = ImageSurface.create(data, Format.RGB24, width, height, stride)) {
            var cr = Context.create(surface);
            cr.setSourceRGB(1, 0, 0);
            cr.rectangle(0, 0, width, height);
            cr.fill();
            cr.setSourceRGB(1, 1, 0);
            cr.moveTo(100, 200);
            cr.setFontSize(100);
            cr.selectFontFace("Segoe UI", FontSlant.NORMAL, FontWeight.BOLD);
            cr.showText("Hello");
            
            surface.flush();

            System.out.println(surface.getData().byteSize()); // prints 0
            System.out.println(data.byteSize()); // prints 480000

            surface.writeToPNG("example.png");
        }
    }
}
jwharm commented

Hi,

ImageSurface.getData() returns a zero-length memory segment, which is basically a pointer with unknown size. You can resize it with: surface.getData().reinterpret(stride * height);

In the next release of the bindings, I will change ImageSurface.getData() to do this automatically.

Thank you for your guidance regarding the zero-length memory segment. I wasn't familiar with this reinterpret method, and your suggestion worked perfectly.