flxzt/rnote · error

Make piet image in BitmapImage draw impl failed, Err

Error message

Make piet image in BitmapImage draw impl failed, Err: {e:?}

What it means

During BitmapImage's piet draw, creating the piet Image from the raw PNG/JPEG pixel data (via PietContext::make_image with the stored width, height, and byte buffer) failed. This is a rendering-time failure: the embedded image bytes are invalid or incompatible with the piet/cairo backend, so the stroke cannot be rasterized onto the target surface.

Solutions

  1. Validate the embedded image bytes (decode with an image library) before/while loading the document and repair or drop broken strokes.
  2. Re-export or re-embed the image and re-save the document.
  3. Check that pixel_width/pixel_height match the data buffer length and expected format (piet_image_format).
  4. Update piet/cairo backend crates in case of a known make_image bug.

Example fix

// before
cx.make_image(w, h, &self.image.data, piet_image_format)?;
// after
let piet_image = cx.make_image(w, h, &self.image.data, piet_image_format)
    .with_context(|| format!("bad bitmap image {}x{} ({} bytes)", w, h, self.image.data.len()))?;
Defensive patterns

Strategy: try-catch

Validate before calling

// Rust: sanity-check the embedded image before rendering
fn bitmap_image_renderable(img: &BitmapImage) -> bool {
    !img.image.data.is_empty()
        && img.image.pixel_width > 0
        && img.image.pixel_height > 0
        && image::load_from_memory(&img.image.data).is_ok()
}

Type guard

fn has_valid_bitmap_data(img: &BitmapImage) -> bool {
    matches!(image::load_from_memory(&img.image.data), Ok(_))
}

Try / catch

match stroke.draw(&mut cx) {
    Ok(()) => {},
    Err(e) => log::warn!("skipping unrenderable bitmap stroke: {e:#}"),
}

Prevention

When it happens

Trigger: Rendering a BitmapImage stroke whose `image.data` bytes are corrupt, truncated, in an unexpected format, or whose pixel dimensions mismatch the buffer size; rendering after deserializing a document with a damaged embedded image; backend make_image limitations.

Common situations: Opening an .rnote document whose embedded PNG data was corrupted by a partial save/transfer; rendering to an unusual piet backend that rejects the image format; memory pressure producing truncated buffers.

Related errors


AI-assisted analysis of flxzt/rnote@bbc5354502 (2026-09-08). Data as JSON: /api/errors/ecf52c05fc3f4415. Report an issue: GitHub.

Appendix: source

Thrown at crates/rnote-engine/src/strokes/bitmapimage.rs:64

    fn update_geometry(&mut self) {}
}

impl Drawable for BitmapImage {
    fn draw(&self, cx: &mut impl piet::RenderContext, _image_scale: f64) -> anyhow::Result<()> {
        let piet_image_format = piet::ImageFormat::from(self.image.memory_format);

        cx.save().map_err(|e| anyhow::anyhow!("{e:?}"))?;
        cx.transform(self.rectangle.affine.to_kurbo());

        let piet_image = cx
            .make_image(
                self.image.pixel_width as usize,
                self.image.pixel_height as usize,
                &self.image.data,
                piet_image_format,
            )
            .map_err(|e| {
                anyhow::anyhow!("Make piet image in BitmapImage draw impl failed, Err: {e:?}")
            })?;
        let dest_rect = self.rectangle.cuboid.local_aabb().to_kurbo_rect();
        cx.draw_image(&piet_image, dest_rect, piet::InterpolationMode::Bilinear);
        cx.restore().map_err(|e| anyhow::anyhow!("{e:?}"))?;

        Ok(())
    }
}

impl Shapeable for BitmapImage {
    fn bounds(&self) -> Aabb {
        self.rectangle.bounds()
    }

    fn hitboxes(&self) -> Vec<Aabb> {
        vec![self.bounds()]
    }

View on GitHub (pinned to bbc5354502)