Skip to content
Merged

Dev #233

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ yarn-error.log*

# sst
.sst
sst-env.d.ts
sst.pyi

# opennext
.open-next
Expand Down
28 changes: 14 additions & 14 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions apps/web/sst-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/* This file is auto-generated by SST. Do not edit. */
/* tslint:disable */
/* eslint-disable */
/* deno-fmt-ignore-file */
/* biome-ignore-all lint: auto-generated */

/// <reference path="../../sst-env.d.ts" />

import "sst"
export {}
10 changes: 10 additions & 0 deletions packages/ducdxf/sst-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/* This file is auto-generated by SST. Do not edit. */
/* tslint:disable */
/* eslint-disable */
/* deno-fmt-ignore-file */
/* biome-ignore-all lint: auto-generated */

/// <reference path="../../sst-env.d.ts" />

import "sst"
export {}
13 changes: 13 additions & 0 deletions packages/ducdxf/sst.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Automatically generated by SST
# pylint: disable=all
# ruff: noqa
from typing import Any

class Resource:
class App:
name: str
stage: str
class MyWeb:
type: str
url: str

967 changes: 477 additions & 490 deletions packages/ducdxf/uv.lock

Large diffs are not rendered by default.

41 changes: 35 additions & 6 deletions packages/ducjs/src/restore/restoreDataState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,8 @@ export const restore = (
);

const restoredVersionGraph = restoreVersionGraph(data?.versionGraph);
const restoredFilesData = restoreFilesData(data?.filesData, data?.files);
const restoredFiles = restoreFiles(data?.files, restoredFilesData);

// Generate a new ID if none exists or if it's empty
const parsedId = data?.id;
Expand All @@ -210,13 +212,39 @@ export const restore = (

localState: restoredLocalState,
globalState: restoredGlobalState,
files: restoreFiles(data?.files),
filesData: restoreFilesData(data?.filesData, data?.files),
files: restoredFiles,
filesData: restoredFilesData,
id: restoredId,
};
};

export const restoreFiles = (importedFiles: unknown): DucExternalFiles => {
const getRestoredRevisionSizeBytes = (
rawSizeBytes: unknown,
revisionId: string,
restoredFilesData: ExternalFilesData,
) => {
const explicitSizeBytes = isFiniteNumber(rawSizeBytes)
? (rawSizeBytes as number)
: undefined;

if (typeof explicitSizeBytes === "number" && explicitSizeBytes > 0) {
return explicitSizeBytes;
}

return restoredFilesData[revisionId]?.byteLength ?? explicitSizeBytes ?? 0;
};

const getRestoredSourceName = (fileData: Record<string, unknown>) => {
return isValidString(fileData.sourceName)
|| isValidString(fileData.fileName)
|| isValidString(fileData.name)
|| undefined;
};

export const restoreFiles = (
importedFiles: unknown,
restoredFilesData: ExternalFilesData = {},
): DucExternalFiles => {
if (!importedFiles || typeof importedFiles !== "object") {
return {};
}
Expand Down Expand Up @@ -251,9 +279,9 @@ export const restoreFiles = (importedFiles: unknown): DucExternalFiles => {

restoredRevisions[revKey] = {
id: revId,
sizeBytes: isFiniteNumber(r.sizeBytes) ? (r.sizeBytes as number) : 0,
sizeBytes: getRestoredRevisionSizeBytes(r.sizeBytes, revId, restoredFilesData),
checksum: isValidString(r.checksum) || undefined,
sourceName: isValidString(r.sourceName) || undefined,
sourceName: getRestoredSourceName(r),
mimeType,
message: isValidString(r.message) || undefined,
created: isFiniteNumber(r.created) ? (r.created as number) : Date.now(),
Expand Down Expand Up @@ -294,7 +322,8 @@ export const restoreFiles = (importedFiles: unknown): DucExternalFiles => {
revisions: {
[revId]: {
id: revId,
sizeBytes: 0,
sizeBytes: getRestoredRevisionSizeBytes(legacyData.sizeBytes, revId, restoredFilesData),
sourceName: getRestoredSourceName(legacyData),
mimeType,
created,
lastRetrieved: isFiniteNumber(legacyData.lastRetrieved)
Expand Down
2 changes: 1 addition & 1 deletion packages/ducjs/src/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ function normalizeViewer3DStateForRust(vs: any): any {
blackEdges: b(dsp.blackEdges, true),
grid: dsp.grid ?? { type: "uniform", value: false },
axesVisible: b(dsp.axesVisible, false),
axesAtOrigin: b(dsp.axesAtOrigin, true),
axesAtOrigin: b(dsp.axesAtOrigin, false),
},
material: {
metalness: n(mat.metalness, 0.3),
Expand Down
10 changes: 10 additions & 0 deletions packages/ducjs/sst-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/* This file is auto-generated by SST. Do not edit. */
/* tslint:disable */
/* eslint-disable */
/* deno-fmt-ignore-file */
/* biome-ignore-all lint: auto-generated */

/// <reference path="../../sst-env.d.ts" />

import "sst"
export {}
23 changes: 23 additions & 0 deletions packages/ducpdf/src/duc2pdf/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,29 @@ export async function convertDucToPdf(
normalizedElement = Object.assign({}, element, { svgPath });
}
}
// Ensure model element thumbnails are Uint8Array for serde_bytes compatibility.
// The normalizeForSerializationScope traversal creates plain objects by iterating
// own-keys, which can demote Uint8Array to a plain {0:…, 1:…} object.
if (element && element.type === 'model' && element.thumbnail != null) {
const tn = element.thumbnail;
if (!(tn instanceof Uint8Array)) {
try {
if (ArrayBuffer.isView(tn)) {
normalizedElement = Object.assign({}, normalizedElement, {
thumbnail: new Uint8Array((tn as ArrayBufferView).buffer, (tn as ArrayBufferView).byteOffset, (tn as ArrayBufferView).byteLength),
});
} else if (Array.isArray(tn)) {
normalizedElement = Object.assign({}, normalizedElement, { thumbnail: new Uint8Array(tn) });
} else if (typeof tn === 'object') {
normalizedElement = Object.assign({}, normalizedElement, {
thumbnail: new Uint8Array(Object.values(tn) as number[]),
});
}
} catch {
// Leave as-is if coercion fails
}
}
}
return normalizedElement;
});

Expand Down
93 changes: 89 additions & 4 deletions packages/ducpdf/src/duc2pdf/src/streaming/stream_elements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ use duc::types::{
DucEllipseElement, DucFrameElement,
DucDocElement, DucFreeDrawElement, DucImageElement, DucLine, DucLineReference, DucLinearElement,
DucLinearElementBase, DucPath, DucPdfElement, DucPlotElement, DucPoint,
DucPolygonElement, DucRectangleElement, DucTableElement, DucTextElement, ElementBackground,
DucPolygonElement, DucRectangleElement, DucTableElement, DucTextElement, DucModelElement, ElementBackground,
ElementContentBase, ElementWrapper, GeometricPoint, DucBlockInstance, DucBlockDuplicationArray,
};

use hipdf::embed_pdf::PdfEmbedder;
use hipdf::fonts::Font;
use hipdf::hatching::HatchingManager;
use hipdf::images::ImageManager;
use hipdf::images::{Image, ImageManager};
use hipdf::lopdf::content::Operation;
use hipdf::lopdf::{Dictionary, Document, Object};
use hipdf::ocg::OCGManager;
Expand Down Expand Up @@ -977,8 +977,8 @@ impl ElementStreamer {
DucElementEnum::DucDocElement(doc) => {
self.stream_doc_element(doc, document, pdf_embedder)?
}
DucElementEnum::DucModelElement(_) => {
vec![Operation::new("% DucModelElement - WIP", vec![])]
DucElementEnum::DucModelElement(model) => {
self.stream_model(model, document, image_manager)?
}
};
operations.extend(element_ops);
Expand Down Expand Up @@ -2772,6 +2772,91 @@ impl ElementStreamer {
taken
}

fn stream_model(
&mut self,
model: &DucModelElement,
document: &mut Document,
image_manager: &mut ImageManager,
) -> ConversionResult<Vec<Operation>> {
let mut ops = Vec::new();

let thumbnail = match &model.thumbnail {
Some(bytes) if !bytes.is_empty() => bytes,
_ => {
ops.push(Operation::new(
"% DucModelElement without thumbnail",
vec![],
));
return Ok(ops);
}
};

if model.base.width <= 0.0 || model.base.height <= 0.0 {
ops.push(Operation::new(
"% DucModelElement with invalid thumbnail bounds",
vec![],
));
return Ok(ops);
}

let cache_key = format!("model-thumbnail:{}", model.base.id);

let image_id = if let Some(&cached_id) = self.images.get(&cache_key) {
cached_id
} else {
let image = match Image::from_bytes(thumbnail.clone(), Some(cache_key.clone())) {
Ok(image) => image,
Err(error) => {
log::warn!(
"[duc2pdf] Failed to decode model thumbnail for {}: {}",
model.base.id,
error,
);
ops.push(Operation::new(
&format!("% Failed to decode DucModelElement thumbnail: {}", model.base.id),
vec![],
));
return Ok(ops);
}
};

let embedded_image_id = match image_manager.embed_image(document, image) {
Ok(image_id) => image_id.0,
Err(error) => {
log::warn!(
"[duc2pdf] Failed to embed model thumbnail for {}: {}",
model.base.id,
error,
);
ops.push(Operation::new(
&format!("% Failed to embed DucModelElement thumbnail: {}", model.base.id),
vec![],
));
return Ok(ops);
}
};

self.images.insert(cache_key.clone(), embedded_image_id);
embedded_image_id
};

let mut temp_resources = Dictionary::new();
let resource_name = image_manager.add_to_resources(&mut temp_resources, (image_id, 0));
self.new_xobjects
.push((resource_name.clone(), Object::Reference((image_id, 0))));

let y_offset = -(model.base.height as f32);
ops.extend(hipdf::images::ImageManager::draw_image(
&resource_name,
0.0,
y_offset,
model.base.width as f32,
model.base.height as f32,
));

Ok(ops)
}

/// Stream image element
fn stream_image(
&mut self,
Expand Down
10 changes: 10 additions & 0 deletions packages/ducpdf/src/duc2pdf/sst-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/* This file is auto-generated by SST. Do not edit. */
/* tslint:disable */
/* eslint-disable */
/* deno-fmt-ignore-file */
/* biome-ignore-all lint: auto-generated */

/// <reference path="../../../../sst-env.d.ts" />

import "sst"
export {}
10 changes: 10 additions & 0 deletions packages/ducpdf/sst-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/* This file is auto-generated by SST. Do not edit. */
/* tslint:disable */
/* eslint-disable */
/* deno-fmt-ignore-file */
/* biome-ignore-all lint: auto-generated */

/// <reference path="../../sst-env.d.ts" />

import "sst"
export {}
Loading
Loading