Skip to content

Wrong size error when rendering PNG via CoreGraphics #481

@lily-mara

Description

@lily-mara

I'm trying to replicate the results of the example file in piet-coregraphics. I'm unable to render an empty PNG file.

use eyre::{Context, Result};
use piet::kurbo::Size;
use std::fs::File;
use std::io::BufWriter;

use core_graphics::color_space::CGColorSpace;
use core_graphics::context::CGContext;

use piet::{Color, RenderContext};
use piet_coregraphics::CoreGraphicsContext;

fn main() -> Result<()> {
    let size = Size {
        width: 1.0,
        height: 1.0,
    };

    let mut cg_ctx = make_cg_ctx(size);
    let mut piet_context = CoreGraphicsContext::new_y_up(&mut cg_ctx, size.height, None);

    draw(&mut piet_context).wrap_err("failed to draw file")?;

    piet_context
        .finish()
        .map_err(|e| eyre::eyre!("{}", e))
        .wrap_err("failed to finalize piet context")?;

    std::mem::drop(piet_context);
    let mut data = cg_ctx.data();
    let file = File::create("out.png").wrap_err("failed to create output file")?;
    let w = BufWriter::new(file);

    dbg!(data.len());

    let mut encoder = png::Encoder::new(w, dbg!(size.width as u32), dbg!(size.height as u32));
    encoder.set_color(png::ColorType::Rgba);
    encoder.set_depth(png::BitDepth::Eight);
    let mut writer = encoder
        .write_header()
        .wrap_err("failed to write png header")?;

    piet_coregraphics::unpremultiply_rgba(&mut data);
    writer
        .write_image_data(&data)
        .wrap_err("failed to write image data")?;

    Ok(())
}

fn make_cg_ctx(size: Size) -> CGContext {
    dbg!(&size);
    let cg_ctx = CGContext::create_bitmap_context(
        None,
        size.width as usize,
        size.height as usize,
        8,
        0,
        &CGColorSpace::create_device_rgb(),
        core_graphics::base::kCGImageAlphaPremultipliedLast,
    );

    cg_ctx
}

fn draw(rc: &mut impl RenderContext) -> Result<()> {
    rc.clear(None, Color::WHITE);

    Ok(())
}

I'm using these crates:

core-graphics = "0.22.3"
eyre = "0.6.5"
piet = "0.5.0"
piet-coregraphics = "0.5.0"
png = "0.17.2"

Running the above example, I get the following output:

[examples/render-test.rs:51] &size = 1.0W×1.0H
[examples/render-test.rs:33] data.len() = 64
[examples/render-test.rs:35] size.width as u32 = 1
[examples/render-test.rs:35] size.height as u32 = 1
Error: failed to write image data

Caused by:
    wrong data size, expected 4 got 64

Location:
    examples/render-test.rs:45:10

The PNG crate expects the image buffer to be 4 bytes long, which makes sense considering it's an RGBA image with 4 bytes per pixel, and it contains only one pixel. I'm not sure why piet is returning a 64-byte image buffer, and I don't really know enough about image formats to make a good guess. I opened the raw buffer in a hex editor, and it contains 0xff 0xff 0xff 0xff followed by 60 bytes of 0x00.

Screenshot of a hex editor showing contents of the buffer described above

Is there some trimming that I'm supposed to do, or is there a settings mismatch in my code between png and piet?

EDIT: it seems there may be some minimum image size that I'm not exceeding. If I change the size to 100x400, it seems to work just fine. Is this restriction coming from piet, coregraphics, or png?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions