mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-08-30 12:12:40 +08:00
This commit is contained in:
@@ -32,6 +32,7 @@
|
|||||||
<button id="zoomInButton" class="icon-button" type="button" title="放大" disabled>+</button>
|
<button id="zoomInButton" class="icon-button" type="button" title="放大" disabled>+</button>
|
||||||
<button id="fitButton" class="button" type="button" data-short="宽" disabled>适宽</button>
|
<button id="fitButton" class="button" type="button" data-short="宽" disabled>适宽</button>
|
||||||
<button id="fitHeightButton" class="button" type="button" data-short="高" disabled>适高</button>
|
<button id="fitHeightButton" class="button" type="button" data-short="高" disabled>适高</button>
|
||||||
|
<button id="annotationButton" class="button" type="button" data-short="注" title="渲染注解" aria-label="渲染注解" aria-pressed="true">注解</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="tool-group">
|
<div class="tool-group">
|
||||||
<select id="pageExportFormat" class="format-select" title="单页格式" aria-label="单页格式" disabled></select>
|
<select id="pageExportFormat" class="format-select" title="单页格式" aria-label="单页格式" disabled></select>
|
||||||
|
|||||||
@@ -739,10 +739,6 @@ body[data-hide-meta] .meta-panel {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
body[aria-busy="true"] .viewer-panel {
|
|
||||||
cursor: progress;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-footer {
|
.app-footer {
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
border-top: 1px solid var(--line);
|
border-top: 1px solid var(--line);
|
||||||
|
|||||||
+26
-16
@@ -59,6 +59,7 @@ const state = {
|
|||||||
pageIndex: 0,
|
pageIndex: 0,
|
||||||
scale: 1,
|
scale: 1,
|
||||||
fitMode: "width",
|
fitMode: "width",
|
||||||
|
renderAnnotations: true,
|
||||||
pageCache: new Map(),
|
pageCache: new Map(),
|
||||||
pageInFlight: new Set(),
|
pageInFlight: new Set(),
|
||||||
pageObserver: null,
|
pageObserver: null,
|
||||||
@@ -88,6 +89,7 @@ const el = {
|
|||||||
zoomLabel: document.querySelector("#zoomLabel"),
|
zoomLabel: document.querySelector("#zoomLabel"),
|
||||||
fitButton: document.querySelector("#fitButton"),
|
fitButton: document.querySelector("#fitButton"),
|
||||||
fitHeightButton: document.querySelector("#fitHeightButton"),
|
fitHeightButton: document.querySelector("#fitHeightButton"),
|
||||||
|
annotationButton: document.querySelector("#annotationButton"),
|
||||||
pageExportFormat: document.querySelector("#pageExportFormat"),
|
pageExportFormat: document.querySelector("#pageExportFormat"),
|
||||||
exportPageButton: document.querySelector("#exportPageButton"),
|
exportPageButton: document.querySelector("#exportPageButton"),
|
||||||
exportButton: document.querySelector("#exportButton"),
|
exportButton: document.querySelector("#exportButton"),
|
||||||
@@ -125,6 +127,7 @@ el.zoomOutButton.addEventListener("click", () => setScale(state.scale - 0.1));
|
|||||||
el.zoomInButton.addEventListener("click", () => setScale(state.scale + 0.1));
|
el.zoomInButton.addEventListener("click", () => setScale(state.scale + 0.1));
|
||||||
el.fitButton.addEventListener("click", fitWidth);
|
el.fitButton.addEventListener("click", fitWidth);
|
||||||
el.fitHeightButton.addEventListener("click", fitHeight);
|
el.fitHeightButton.addEventListener("click", fitHeight);
|
||||||
|
el.annotationButton.addEventListener("click", toggleAnnotations);
|
||||||
el.exportPageButton.addEventListener("click", exportCurrentPage);
|
el.exportPageButton.addEventListener("click", exportCurrentPage);
|
||||||
el.exportButton.addEventListener("click", exportPDF);
|
el.exportButton.addEventListener("click", exportPDF);
|
||||||
el.pageInput.addEventListener("change", () => {
|
el.pageInput.addEventListener("change", () => {
|
||||||
@@ -524,9 +527,7 @@ function fontData(fonts) {
|
|||||||
function updateFontSummary() {
|
function updateFontSummary() {
|
||||||
const total = fontRecords().length;
|
const total = fontRecords().length;
|
||||||
const enabled = fontRecords().filter((font) => font.enabled).length;
|
const enabled = fontRecords().filter((font) => font.enabled).length;
|
||||||
if (el.availableFontSummary) {
|
el.availableFontSummary.textContent = total ? `${enabled}/${total}` : "0";
|
||||||
el.availableFontSummary.textContent = total ? `${enabled}/${total}` : "0";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function createFontRecord(name, data, source) {
|
function createFontRecord(name, data, source) {
|
||||||
@@ -660,15 +661,25 @@ async function applyFontChange(options = {}) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function toggleAnnotations() {
|
||||||
|
state.renderAnnotations = !state.renderAnnotations;
|
||||||
|
updateAnnotationButton();
|
||||||
|
if (!state.ofdBytes || !state.doc) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await openDocument({
|
||||||
|
pageIndex: state.pageIndex,
|
||||||
|
fitMode: state.fitMode,
|
||||||
|
skipAutoFonts: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function removeFont(id) {
|
function removeFont(id) {
|
||||||
state.localFonts = state.localFonts.filter((font) => font.id !== id);
|
state.localFonts = state.localFonts.filter((font) => font.id !== id);
|
||||||
state.userFonts = state.userFonts.filter((font) => font.id !== id);
|
state.userFonts = state.userFonts.filter((font) => font.id !== id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderFontList() {
|
function renderFontList() {
|
||||||
if (!el.fontList) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
el.fontList.replaceChildren();
|
el.fontList.replaceChildren();
|
||||||
const fonts = fontRecords();
|
const fonts = fontRecords();
|
||||||
if (!fonts.length) {
|
if (!fonts.length) {
|
||||||
@@ -753,9 +764,6 @@ function fontSourceText(source) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateLocalFontButton() {
|
function updateLocalFontButton() {
|
||||||
if (!el.localFontButton) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const supported = canReadLocalFonts();
|
const supported = canReadLocalFonts();
|
||||||
el.localFontButton.disabled = !supported;
|
el.localFontButton.disabled = !supported;
|
||||||
el.localFontButton.title = supported ? "授权读取浏览器可访问的系统字体" : "当前浏览器不支持读取系统字体";
|
el.localFontButton.title = supported ? "授权读取浏览器可访问的系统字体" : "当前浏览器不支持读取系统字体";
|
||||||
@@ -786,7 +794,7 @@ async function openDocument(options = {}) {
|
|||||||
if (openSeq !== state.openSeq) {
|
if (openSeq !== state.openSeq) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const doc = callWASM("ofdgoOpen", state.ofdBytes, resetLocalFonts ? uploadedFonts() : allFonts());
|
const doc = callWASM("ofdgoOpen", state.ofdBytes, resetLocalFonts ? uploadedFonts() : allFonts(), state.renderAnnotations);
|
||||||
if (openSeq !== state.openSeq) {
|
if (openSeq !== state.openSeq) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1436,14 +1444,9 @@ function renderMeta() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderDocumentFonts() {
|
function renderDocumentFonts() {
|
||||||
if (!el.docFontList) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const fonts = state.doc?.fonts || [];
|
const fonts = state.doc?.fonts || [];
|
||||||
el.docFontList.replaceChildren();
|
el.docFontList.replaceChildren();
|
||||||
if (el.docFontSummary) {
|
el.docFontSummary.textContent = fontSummary(fonts);
|
||||||
el.docFontSummary.textContent = fontSummary(fonts);
|
|
||||||
}
|
|
||||||
if (!fonts.length) {
|
if (!fonts.length) {
|
||||||
const empty = document.createElement("div");
|
const empty = document.createElement("div");
|
||||||
empty.className = "font-empty";
|
empty.className = "font-empty";
|
||||||
@@ -1594,11 +1597,18 @@ function updateControls() {
|
|||||||
el.fitHeightButton.disabled = !hasDoc;
|
el.fitHeightButton.disabled = !hasDoc;
|
||||||
el.fitButton.toggleAttribute("aria-pressed", hasDoc && state.fitMode === "width");
|
el.fitButton.toggleAttribute("aria-pressed", hasDoc && state.fitMode === "width");
|
||||||
el.fitHeightButton.toggleAttribute("aria-pressed", hasDoc && state.fitMode === "height");
|
el.fitHeightButton.toggleAttribute("aria-pressed", hasDoc && state.fitMode === "height");
|
||||||
|
updateAnnotationButton();
|
||||||
el.pageExportFormat.disabled = !hasDoc || !state.exportFormats.length;
|
el.pageExportFormat.disabled = !hasDoc || !state.exportFormats.length;
|
||||||
el.exportPageButton.disabled = !hasDoc || !state.exportFormats.length;
|
el.exportPageButton.disabled = !hasDoc || !state.exportFormats.length;
|
||||||
el.exportButton.disabled = !hasDoc;
|
el.exportButton.disabled = !hasDoc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateAnnotationButton() {
|
||||||
|
el.annotationButton.setAttribute("aria-pressed", String(state.renderAnnotations));
|
||||||
|
el.annotationButton.title = state.renderAnnotations ? "关闭注解渲染" : "开启注解渲染";
|
||||||
|
el.annotationButton.setAttribute("aria-label", el.annotationButton.title);
|
||||||
|
}
|
||||||
|
|
||||||
function setExportControlsDisabled(disabled) {
|
function setExportControlsDisabled(disabled) {
|
||||||
el.exportButton.disabled = disabled;
|
el.exportButton.disabled = disabled;
|
||||||
el.exportPageButton.disabled = disabled;
|
el.exportPageButton.disabled = disabled;
|
||||||
|
|||||||
@@ -79,22 +79,23 @@ func safeCall(fn func([]js.Value) (any, error), args []js.Value) (data any, err
|
|||||||
// 入参: args 浏览器参数
|
// 入参: args 浏览器参数
|
||||||
// 返回: any 文档信息, error 错误信息
|
// 返回: any 文档信息, error 错误信息
|
||||||
func openDocument(args []js.Value) (any, error) {
|
func openDocument(args []js.Value) (any, error) {
|
||||||
if len(args) == 0 {
|
if len(args) < 3 {
|
||||||
return nil, fmt.Errorf("missing ofd data")
|
return nil, fmt.Errorf("missing open arguments")
|
||||||
}
|
}
|
||||||
data, err := bytesFromJS(args[0])
|
data, err := bytesFromJS(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
fonts, err := fontsFromJS(jsArg(args, 1))
|
fonts, err := fontsFromJS(args[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
renderAnnotations := args[2].Bool()
|
||||||
if currentSession != nil {
|
if currentSession != nil {
|
||||||
_ = currentSession.Close()
|
_ = currentSession.Close()
|
||||||
currentSession = nil
|
currentSession = nil
|
||||||
}
|
}
|
||||||
session, err := Open(data, OpenOptions{Fonts: fonts})
|
session, err := Open(data, OpenOptions{Fonts: fonts, RenderAnnotations: renderAnnotations})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,8 @@ import (
|
|||||||
|
|
||||||
// OpenOptions 打开OFD文档选项
|
// OpenOptions 打开OFD文档选项
|
||||||
type OpenOptions struct {
|
type OpenOptions struct {
|
||||||
Fonts []FontFile
|
Fonts []FontFile
|
||||||
|
RenderAnnotations bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// FontFile 字体文件
|
// FontFile 字体文件
|
||||||
@@ -144,6 +145,7 @@ func Open(data []byte, opts OpenOptions) (*Session, error) {
|
|||||||
}
|
}
|
||||||
rendererOptions = append(rendererOptions, ofdgo.WithFontFS(fontFS))
|
rendererOptions = append(rendererOptions, ofdgo.WithFontFS(fontFS))
|
||||||
}
|
}
|
||||||
|
rendererOptions = append(rendererOptions, ofdgo.WithAnnotations(opts.RenderAnnotations))
|
||||||
return &Session{Reader: reader, Renderer: ofdgo.NewRenderer(reader, rendererOptions...), doc: doc}, nil
|
return &Session{Reader: reader, Renderer: ofdgo.NewRenderer(reader, rendererOptions...), doc: doc}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user