diff --git a/crates/dwg-thumbnailer/src/lib.rs b/crates/dwg-thumbnailer/src/lib.rs index 7927002d..736b8b0c 100644 --- a/crates/dwg-thumbnailer/src/lib.rs +++ b/crates/dwg-thumbnailer/src/lib.rs @@ -41,14 +41,7 @@ pub fn extract_bytes(bytes: &[u8], max_dim: u32) -> Option { let start = usize::try_from(base).ok()?; let total = preview_container_len(bytes.get(start..start.checked_add(20)?)?)?; let container = bytes.get(start..start.checked_add(total)?)?; - extract_container(container, base, max_dim) -} - -/// Decode a preview container read from a DWG at `file_offset`. Exposing this -/// narrow entry point lets browser callers use `Blob.slice()` to migrate old -/// recent files without copying the entire drawing into memory. -pub fn extract_container(container: &[u8], file_offset: u64, max_dim: u32) -> Option { - let (format, data) = parse_preview_container(container, file_offset)?; + let (format, data) = parse_preview_container(container, base)?; let img = decode(format, data)?; Some(downscale(img, max_dim.max(1))) } diff --git a/src/io/web_recent.rs b/src/io/web_recent.rs index 6ae1f81b..5d4f1cb5 100644 --- a/src/io/web_recent.rs +++ b/src/io/web_recent.rs @@ -94,28 +94,12 @@ async fn read_blob(blob: &web_sys::Blob) -> Result, String> { Ok(js_sys::Uint8Array::new(&buffer).to_vec()) } -/// Load a cached preview. Records created before thumbnail sidecars existed are -/// migrated by slicing only the DWG header and preview container from the OPFS -/// file; the potentially large drawing body is never copied or parsed. pub async fn read_thumbnail(name: &str) -> Result, String> { let directory = recent_directory(false).await?; - if let Ok(bytes) = read_entry(&directory, &thumbnail_key(name)).await { - if let Some(thumbnail) = decode_thumbnail(bytes) { - return Ok(Some(thumbnail)); - } + match read_entry(&directory, &thumbnail_key(name)).await { + Ok(bytes) => Ok(decode_thumbnail(bytes)), + Err(_) => Ok(None), } - - let file = get_file(&directory, &cache_key(name)).await?; - let Some(image) = extract_embedded_thumbnail(&file).await? else { - return Ok(None); - }; - let encoded = encode_thumbnail(image); - let thumbnail = decode_thumbnail(encoded.clone()) - .ok_or_else(|| "generated recent thumbnail is invalid".to_string())?; - // Migration caching is best-effort: a readable drawing should still show - // its preview even if quota pressure prevents writing the sidecar. - let _ = write_entry(&directory, &thumbnail_key(name), &encoded).await; - Ok(Some(thumbnail)) } pub async fn remove(name: &str) -> Result<(), String> { @@ -196,54 +180,6 @@ fn decode_thumbnail(bytes: Vec) -> Option { }) } -async fn extract_embedded_thumbnail( - file: &web_sys::File, -) -> Result, String> { - let header = read_file_range(file, 0, 0x11).await?; - if header.get(..2) != Some(b"AC") { - return Ok(None); - } - let Some(offset) = header - .get(0x0D..0x11) - .and_then(|bytes| bytes.try_into().ok()) - .map(i32::from_le_bytes) - .filter(|offset| *offset > 0) - else { - return Ok(None); - }; - let offset = offset as u64; - let container_header = read_file_range(file, offset, offset + 20).await?; - let Some(overall) = container_header - .get(16..20) - .and_then(|bytes| bytes.try_into().ok()) - .map(u32::from_le_bytes) - .map(u64::from) - .filter(|size| *size > 0 && *size <= 64 * 1024 * 1024) - else { - return Ok(None); - }; - let Some(end) = offset - .checked_add(36) - .and_then(|end| end.checked_add(overall)) - else { - return Ok(None); - }; - let container = read_file_range(file, offset, end).await?; - Ok(dwg_thumbnailer::extract_container( - &container, - offset, - THUMBNAIL_MAX_DIM, - )) -} - -async fn read_file_range(file: &web_sys::File, start: u64, end: u64) -> Result, String> { - let blob: &web_sys::Blob = file.as_ref(); - let slice = blob - .slice_with_f64_and_f64(start as f64, end as f64) - .map_err(js_error)?; - read_blob(&slice).await -} - fn js_error(value: wasm_bindgen::JsValue) -> String { value .as_string()