feat(ole): render the OLE2FRAME embedded presentation bitmap

An OLE2FRAME drew only a rectangle-with-X placeholder. AutoCAD shows the OLE
object's cached presentation image, which the DWG stores as a BMP embedded in
the OLE data blob (a BITMAPFILEHEADER "BM" + DIB).

`ImageModel::from_ole2frame` scans the blob for a self-consistent embedded BMP
(validating the DIB-header size, so a metafile/other-format OLE cleanly falls
back), decodes it with the `image` crate, and builds the textured quad at the
frame rectangle with a per-corner double-single split so it stays precise at UTM
scale. The scene's image collection now feeds OLE2FRAME entities through it
alongside RasterImage. The placeholder's diagonal X is dropped — only the frame
border is drawn now, so it no longer crosses over the bitmap.

Verified on budweiser handle 3088: the 32×32 embedded bitmap decodes to RGBA
with the expected colours (yellow upper-left, blue centre, red lower-right),
upright and positioned at the frame corners.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hakan SevenandClaude Opus 4.8 committed 2026-07-18 13:33:46 +03:00
1 parent 5e127ffa75
commit b655bd232b
3 files changed
+99 -22

No files matched your search

+7 -5
View File
@@ -289,7 +289,7 @@ pub fn build_derived_caches(doc: &CadDocument) -> DerivedCaches {
let h = e.common().handle;
match e {
EntityType::Hatch(_) | EntityType::Solid(_) => hatch_handles.push(h),
EntityType::RasterImage(_) => image_handles.push(h),
EntityType::RasterImage(_) | EntityType::Ole2Frame(_) => image_handles.push(h),
EntityType::Solid3D(_) | EntityType::Region(_) | EntityType::Body(_) | EntityType::Surface(_) => {
mesh_handles.push(h)
}
@@ -326,12 +326,14 @@ pub fn build_derived_caches(doc: &CadDocument) -> DerivedCaches {
// images
let images: HashMap<Handle, ImageModel> = image_handles
.par_iter()
.filter_map(|&handle| {
if let EntityType::RasterImage(img) = doc.get_entity(handle)? {
.filter_map(|&handle| match doc.get_entity(handle)? {
EntityType::RasterImage(img) => {
ImageModel::from_raster_image(img).map(|m| (handle, m))
} else {
None
}
EntityType::Ole2Frame(ole) => {
ImageModel::from_ole2frame(ole).map(|m| (handle, m))
}
_ => None,
})
.collect();