mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-31 16:39:26 +08:00
1 parent
22c8a95e7c
commit
171f118a46
5 files changed
+82
-21
No files matched your search
@@ -356,7 +356,7 @@
|
||||
</div>
|
||||
<div id="createImagesRow" class="create-images-row" hidden>
|
||||
<div class="create-image-actions"><button id="createImageAdd" class="button" type="button">添加图片</button><div id="createImageOrder" class="form-options" hidden><label><input type="radio" name="imageOrder" value="name-asc" checked><span>名称升序</span></label><label><input type="radio" name="imageOrder" value="name-desc"><span>名称降序</span></label><label><input type="radio" name="imageOrder" value="time-asc"><span>时间升序</span></label><label><input type="radio" name="imageOrder" value="time-desc"><span>时间降序</span></label><label><input type="radio" name="imageOrder" value="added"><span>添加顺序</span></label></div></div>
|
||||
<span id="createImageCount">0</span><input id="createImages" type="file" accept=".png,.jpg,.jpeg,.bmp,.tif,.tiff,.jb2,.jbig2" multiple hidden disabled>
|
||||
<input id="createImages" type="file" accept=".png,.jpg,.jpeg,.bmp,.tif,.tiff,.jb2,.jbig2" multiple hidden disabled>
|
||||
</div>
|
||||
<div id="createImageQueue" hidden>
|
||||
<div id="createImageList" class="create-image-list"></div>
|
||||
|
||||
+15
-14
@@ -1666,10 +1666,6 @@ button:not(:disabled):hover {
|
||||
}
|
||||
|
||||
.create-images-row {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
@@ -1685,12 +1681,6 @@ button:not(:disabled):hover {
|
||||
}
|
||||
}
|
||||
|
||||
#createImageCount {
|
||||
align-self: start;
|
||||
line-height: var(--control-height);
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
#createImageQueue {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
@@ -1765,11 +1755,22 @@ button:not(:disabled):hover {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.create-image-preview img {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
.create-image-paper {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
box-sizing: border-box;
|
||||
background: #fff;
|
||||
box-shadow: 0 0 0 1px var(--line);
|
||||
}
|
||||
|
||||
.create-image-paper img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.create-image-paper[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.create-image-details {
|
||||
|
||||
+38
-4
@@ -508,7 +508,6 @@ const el = {
|
||||
createImageQueue: document.querySelector("#createImageQueue"),
|
||||
createImageList: document.querySelector("#createImageList"),
|
||||
createImageAdd: document.querySelector("#createImageAdd"),
|
||||
createImageCount: document.querySelector("#createImageCount"),
|
||||
createImageOrder: document.querySelector("#createImageOrder"),
|
||||
createPortrait: document.querySelector("#createPortrait"),
|
||||
createLandscape: document.querySelector("#createLandscape"),
|
||||
@@ -1681,6 +1680,7 @@ el.createMode.addEventListener("change", () => {
|
||||
});
|
||||
el.createSize.addEventListener("change", applyCreatePaper);
|
||||
for (const input of [el.createWidth, el.createHeight]) input.addEventListener("input", () => updateCreateDirection(true));
|
||||
el.createMargin.addEventListener("input", updateCreateImagePreviews);
|
||||
for (const radio of [el.createPortrait, el.createLandscape]) radio.addEventListener("change", () => {
|
||||
[el.createWidth.value, el.createHeight.value] = [el.createHeight.value, el.createWidth.value];
|
||||
updateCreateDirection();
|
||||
@@ -3886,6 +3886,7 @@ function updateCreateDirection(matchPaper = false) {
|
||||
el.createLandscape.checked = valid && width > height;
|
||||
el.createPortrait.disabled = el.createLandscape.disabled = !valid || width === height || el.createWidth.disabled;
|
||||
if (matchPaper) el.createSize.value = Object.entries(createPaperSizes).find(([, [w, h]]) => Math.min(width, height) === w && Math.max(width, height) === h)?.[0] || "custom";
|
||||
updateCreateImagePreviews();
|
||||
}
|
||||
|
||||
function releaseCreateImages(tab) {
|
||||
@@ -3963,7 +3964,6 @@ function renderCreateImages() {
|
||||
const focused = el.createImageList.contains(document.activeElement);
|
||||
el.createImageList.replaceChildren();
|
||||
for (const input of el.createImageOrder.querySelectorAll("input")) input.checked = input.value === queue.order;
|
||||
el.createImageCount.textContent = String(queue.entries.length);
|
||||
if (!queue.entries.some(entry => entry.id === queue.selected)) queue.selected = queue.entries[0]?.id ?? null;
|
||||
queue.observer = new IntersectionObserver(items => {
|
||||
for (const item of items) if (item.isIntersecting && isForegroundDocument(tab)) {
|
||||
@@ -4000,10 +4000,39 @@ function renderCreateImages() {
|
||||
}
|
||||
|
||||
function showCreateImagePreview(entry, row) {
|
||||
const image = document.createElement("img");
|
||||
const paper = document.createElement("span"), image = document.createElement("img");
|
||||
paper.className = "create-image-paper";
|
||||
image.src = entry.url;
|
||||
image.draggable = false;
|
||||
row.querySelector(".create-image-preview").replaceChildren(image);
|
||||
paper.append(image);
|
||||
row.querySelector(".create-image-preview").replaceChildren(paper);
|
||||
layoutCreateImagePreview(entry, row);
|
||||
}
|
||||
|
||||
function updateCreateImagePreviews() {
|
||||
const queue = state.createImageQueue;
|
||||
if (!queue) return;
|
||||
const entries = new Map(queue.entries.map(entry => [entry.id, entry]));
|
||||
for (const row of el.createImageList.children) {
|
||||
const entry = entries.get(Number(row.dataset.imageId));
|
||||
if (entry?.url && row.querySelector(".create-image-paper")) layoutCreateImagePreview(entry, row);
|
||||
}
|
||||
}
|
||||
|
||||
function layoutCreateImagePreview(entry, row) {
|
||||
const paper = row.querySelector(".create-image-paper"), image = paper.firstElementChild;
|
||||
const margin = Number(el.createMargin.value), follow = el.createSize.value === "image";
|
||||
const width = follow ? entry.width + 2 * margin : Number(el.createWidth.value);
|
||||
const height = follow ? entry.height + 2 * margin : Number(el.createHeight.value);
|
||||
const valid = Number.isFinite(width + height + margin) && margin >= 0 && width > 2 * margin && height > 2 * margin;
|
||||
paper.hidden = !valid;
|
||||
if (!valid) return;
|
||||
const scale = 46 / Math.max(width, height);
|
||||
const fit = follow ? 1 : Math.min((width - 2 * margin) / entry.width, (height - 2 * margin) / entry.height);
|
||||
paper.style.width = `${width * scale}px`;
|
||||
paper.style.height = `${height * scale}px`;
|
||||
image.style.width = `${entry.width * fit * scale}px`;
|
||||
image.style.height = `${entry.height * fit * scale}px`;
|
||||
}
|
||||
|
||||
async function loadCreateImagePreview(tab, queue, entry) {
|
||||
@@ -4014,6 +4043,11 @@ async function loadCreateImagePreview(tab, queue, entry) {
|
||||
const source = entry.file instanceof Blob ? entry.file : new Blob([await entry.file.arrayBuffer()]);
|
||||
if (tab.state.createImageQueue !== queue || !queue.entries.includes(entry)) return;
|
||||
bitmap = await createImageBitmap(source, { resizeWidth: 64 });
|
||||
if (tab.closed || tab.state.createImageQueue !== queue || !queue.entries.includes(entry)) return;
|
||||
const size = await callTabWASM(tab, "ofdgoImagePageSize", new Uint8Array(await source.arrayBuffer()));
|
||||
if (tab.state.createImageQueue !== queue || !queue.entries.includes(entry)) return;
|
||||
entry.width = size.width;
|
||||
entry.height = size.height;
|
||||
const canvas = document.createElement("canvas"), scale = Math.min(64 / bitmap.width, 64 / bitmap.height, 1);
|
||||
canvas.width = Math.max(1, Math.round(bitmap.width * scale));
|
||||
canvas.height = Math.max(1, Math.round(bitmap.height * scale));
|
||||
|
||||
@@ -478,7 +478,7 @@ class BrowserEngine {
|
||||
"ofdgoLoadPDF", "ofdgoDocumentInfo", "ofdgoDocumentVersions", "ofdgoDocumentNavigation", "ofdgoOpenLinks", "ofdgoOutlineLinks", "ofdgoRenderBackends", "ofdgoSVGFontData",
|
||||
"ofdgoSearchPage", "ofdgoPageTextString", "ofdgoResources", "ofdgoResourceReferences", "ofdgoResourceTargets",
|
||||
"ofdgoResourceLocations", "ofdgoFontPreview", "ofdgoFontFaces", "ofdgoFontFace", "ofdgoMatchFontFiles",
|
||||
"ofdgoImages", "ofdgoStructureTargets", "ofdgoStructureObjects", "ofdgoPackageDocuments", "ofdgoVerifySignatures",
|
||||
"ofdgoImages", "ofdgoImagePageSize", "ofdgoStructureTargets", "ofdgoStructureObjects", "ofdgoPackageDocuments", "ofdgoVerifySignatures",
|
||||
"ofdgoAnnotationInfos", "ofdgoInvoices", "ofdgoInvoice", "ofdgoExportInvoice", "ofdgoValidateInvoice",
|
||||
"ofdgoActionList", "ofdgoPageSettings", "ofdgoReadAnnotation", "ofdgoPreviewSignatureSeal",
|
||||
"ofdgoExportFormats", "ofdgoOutputFormats", "ofdgoParsePageRange", "ofdgoExportPage", "ofdgoExportDocument",
|
||||
|
||||
+27
-1
@@ -36,6 +36,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/xiaoqidun/ofdgo"
|
||||
baseimage "github.com/xiaoqidun/ofdgo/internal/base/image"
|
||||
)
|
||||
|
||||
// sessionTextCacheBytes 限制会话文字索引的内存预算
|
||||
@@ -1622,7 +1623,7 @@ func (e *businessEngine) checkDocument(name string) error {
|
||||
return nil
|
||||
}
|
||||
switch name {
|
||||
case "ofdgoFontFaces", "ofdgoFontMenu", "ofdgoFontPreferenceOrder", "ofdgoFontFace", "ofdgoCheckTextFont":
|
||||
case "ofdgoFontFaces", "ofdgoFontMenu", "ofdgoFontPreferenceOrder", "ofdgoFontFace", "ofdgoCheckTextFont", "ofdgoImagePageSize":
|
||||
return nil
|
||||
case "ofdgoDiscardObjects", "ofdgoExportObjects", "ofdgoCheckDocument", "ofdgoPDFContext", "ofdgoOpenPDF", "ofdgoOpen", "ofdgoLoadPDF", "ofdgoConfigure", "ofdgoDocumentInfo", "ofdgoSVGFontData", "ofdgoRenderBackends", "ofdgoOutputFormats", "ofdgoExportFormats", "ofdgoParsePageRange", "ofdgoMatchFontFiles", "ofdgoOutlineLinks", "ofdgoDocumentNavigation", "ofdgoInvoices", "ofdgoRenderPage", "ofdgoSearchPage", "ofdgoPageTextString", "ofdgoOpenLinks", "ofdgoDiscardPrint", "ofdgoDiscardSave", "ofdgoDetectFormat", "ofdgoConvertFile", "ofdgoPackFiles", "ofdgoLoadImport", "ofdgoCreateDocument", "ofdgoLayoutPrint", "ofdgoPrintSide", "ofdgoPrintPDF":
|
||||
return nil
|
||||
@@ -6260,6 +6261,30 @@ func (e *businessEngine) importImages(args []platformValue) (any, error) {
|
||||
return editorPageInfo{info, position}, err
|
||||
}
|
||||
|
||||
// imagePageSize 读取图片建页使用的物理尺寸和方向,不改变文档状态
|
||||
// 入参: args 图片数据
|
||||
// 返回: any 图片宽高,单位为毫米, error 错误信息
|
||||
func (e *businessEngine) imagePageSize(args []platformValue) (any, error) {
|
||||
data, err := e.bytesFromJS(args[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ctx := e.operationContext()
|
||||
config, format, err := baseimage.DecodeConfigDataContext(ctx, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
metadata, err := baseimage.PageMetadataContext(ctx, data, format, 96)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
width, height := float64(config.Width)*25.4/metadata.XDPI, float64(config.Height)*25.4/metadata.YDPI
|
||||
if metadata.Orientation >= 5 {
|
||||
width, height = height, width
|
||||
}
|
||||
return successResult(map[string]any{"width": width, "height": height}), nil
|
||||
}
|
||||
|
||||
// createDocument 新建单页文档
|
||||
// 入参: args 标题、纸张宽高和注解设置
|
||||
// 返回: any 文档信息, error 错误信息
|
||||
@@ -8111,6 +8136,7 @@ func (e *businessEngine) businessCommands() map[string]func([]platformValue) (an
|
||||
"ofdgoFontFace": e.fontFace,
|
||||
"ofdgoCreateDocument": e.createDocument,
|
||||
"ofdgoImportImages": e.importImages,
|
||||
"ofdgoImagePageSize": e.imagePageSize,
|
||||
"ofdgoEditDocument": e.editDocument,
|
||||
"ofdgoUpdateInfo": e.updateInfo,
|
||||
"ofdgoChangeAttachment": e.changeAttachment,
|
||||
|
||||
Reference in new issue
Block a user