mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-08-30 12:12:40 +08:00
@@ -33,15 +33,15 @@
|
|||||||
<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>
|
<button id="annotationButton" class="button" type="button" data-short="注" title="渲染注解" aria-label="渲染注解" aria-pressed="true">注解</button>
|
||||||
<select id="renderDPI" class="format-select dpi-select" title="渲染 DPI" aria-label="渲染 DPI">
|
</div>
|
||||||
|
<div class="tool-group">
|
||||||
|
<select id="pageExportFormat" class="format-select" title="单页格式" aria-label="单页格式" disabled></select>
|
||||||
|
<select id="imageDPI" class="format-select dpi-select" title="图片 DPI" aria-label="图片 DPI" disabled>
|
||||||
<option value="96">96</option>
|
<option value="96">96</option>
|
||||||
<option value="150">150</option>
|
<option value="150">150</option>
|
||||||
<option value="300" selected>300</option>
|
<option value="300" selected>300</option>
|
||||||
<option value="600">600</option>
|
<option value="600">600</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
|
||||||
<div class="tool-group">
|
|
||||||
<select id="pageExportFormat" class="format-select" title="单页格式" aria-label="单页格式" disabled></select>
|
|
||||||
<button id="exportPageButton" class="button" type="button" data-short="单" title="导出单页" aria-label="导出单页" disabled>单页</button>
|
<button id="exportPageButton" class="button" type="button" data-short="单" title="导出单页" aria-label="导出单页" disabled>单页</button>
|
||||||
<button id="exportButton" class="button" type="button" data-short="全" title="导出文档 PDF" aria-label="导出文档 PDF" disabled>文档</button>
|
<button id="exportButton" class="button" type="button" data-short="全" title="导出文档 PDF" aria-label="导出文档 PDF" disabled>文档</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+19
-21
@@ -18,7 +18,7 @@ const COMMON_FONT_NAMES = [
|
|||||||
];
|
];
|
||||||
const LOCAL_FONT_LOAD_LIMIT = 16;
|
const LOCAL_FONT_LOAD_LIMIT = 16;
|
||||||
const COMPACT_LAYOUT = window.matchMedia("(max-width: 900px)");
|
const COMPACT_LAYOUT = window.matchMedia("(max-width: 900px)");
|
||||||
const DEFAULT_RENDER_DPI = 300;
|
const DEFAULT_IMAGE_DPI = 300;
|
||||||
const STATUS = {
|
const STATUS = {
|
||||||
ready: "选择 OFD 文件",
|
ready: "选择 OFD 文件",
|
||||||
opening: "正在打开 OFD",
|
opening: "正在打开 OFD",
|
||||||
@@ -60,7 +60,6 @@ const state = {
|
|||||||
pageIndex: 0,
|
pageIndex: 0,
|
||||||
scale: 1,
|
scale: 1,
|
||||||
fitMode: "width",
|
fitMode: "width",
|
||||||
renderDPI: DEFAULT_RENDER_DPI,
|
|
||||||
renderAnnotations: true,
|
renderAnnotations: true,
|
||||||
pageCache: new Map(),
|
pageCache: new Map(),
|
||||||
pageInFlight: new Map(),
|
pageInFlight: new Map(),
|
||||||
@@ -94,7 +93,7 @@ const el = {
|
|||||||
fitButton: document.querySelector("#fitButton"),
|
fitButton: document.querySelector("#fitButton"),
|
||||||
fitHeightButton: document.querySelector("#fitHeightButton"),
|
fitHeightButton: document.querySelector("#fitHeightButton"),
|
||||||
annotationButton: document.querySelector("#annotationButton"),
|
annotationButton: document.querySelector("#annotationButton"),
|
||||||
renderDPI: document.querySelector("#renderDPI"),
|
imageDPI: document.querySelector("#imageDPI"),
|
||||||
pageExportFormat: document.querySelector("#pageExportFormat"),
|
pageExportFormat: document.querySelector("#pageExportFormat"),
|
||||||
exportPageButton: document.querySelector("#exportPageButton"),
|
exportPageButton: document.querySelector("#exportPageButton"),
|
||||||
exportButton: document.querySelector("#exportButton"),
|
exportButton: document.querySelector("#exportButton"),
|
||||||
@@ -139,7 +138,7 @@ 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.annotationButton.addEventListener("click", toggleAnnotations);
|
||||||
el.renderDPI.addEventListener("change", changeDPI);
|
el.pageExportFormat.addEventListener("change", () => updateDPIControl());
|
||||||
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", () => {
|
||||||
@@ -246,6 +245,7 @@ function loadExportFormats() {
|
|||||||
if (formats.length) {
|
if (formats.length) {
|
||||||
el.pageExportFormat.value = formats[0].value;
|
el.pageExportFormat.value = formats[0].value;
|
||||||
}
|
}
|
||||||
|
updateDPIControl();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function ensureWASM() {
|
async function ensureWASM() {
|
||||||
@@ -740,19 +740,6 @@ async function toggleAnnotations() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function changeDPI() {
|
|
||||||
state.renderDPI = currentRenderDPI();
|
|
||||||
if (!state.ofdBytes || !state.doc) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await openDocument({
|
|
||||||
pageIndex: state.pageIndex,
|
|
||||||
fitMode: state.fitMode,
|
|
||||||
scale: state.scale,
|
|
||||||
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);
|
||||||
@@ -896,7 +883,7 @@ async function openDocument(options = {}) {
|
|||||||
if (openSeq !== state.openSeq) {
|
if (openSeq !== state.openSeq) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const doc = callWASM("ofdgoOpen", state.ofdBytes, resetLocalFonts ? uploadedFonts() : allFonts(), state.renderAnnotations, state.renderDPI);
|
const doc = callWASM("ofdgoOpen", state.ofdBytes, resetLocalFonts ? uploadedFonts() : allFonts(), state.renderAnnotations);
|
||||||
if (openSeq !== state.openSeq) {
|
if (openSeq !== state.openSeq) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1054,7 +1041,8 @@ async function exportCurrentPage() {
|
|||||||
if (openSeq !== state.openSeq) {
|
if (openSeq !== state.openSeq) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const result = callWASM("ofdgoExportPage", state.pageIndex, format);
|
const dpi = exportFormatUsesDPI(format) ? currentImageDPI() : 0;
|
||||||
|
const result = callWASM("ofdgoExportPage", state.pageIndex, format, dpi);
|
||||||
if (openSeq !== state.openSeq) {
|
if (openSeq !== state.openSeq) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2130,6 +2118,7 @@ function updateControls() {
|
|||||||
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;
|
||||||
|
updateDPIControl();
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateAnnotationButton() {
|
function updateAnnotationButton() {
|
||||||
@@ -2142,6 +2131,7 @@ function setExportControlsDisabled(disabled) {
|
|||||||
el.exportButton.disabled = disabled;
|
el.exportButton.disabled = disabled;
|
||||||
el.exportPageButton.disabled = disabled;
|
el.exportPageButton.disabled = disabled;
|
||||||
el.pageExportFormat.disabled = disabled;
|
el.pageExportFormat.disabled = disabled;
|
||||||
|
updateDPIControl(disabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
function callWASM(name, ...args) {
|
function callWASM(name, ...args) {
|
||||||
@@ -2259,8 +2249,16 @@ function exportFormatInfo(value) {
|
|||||||
return state.exportFormats.find((format) => format.value === value) || null;
|
return state.exportFormats.find((format) => format.value === value) || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function currentRenderDPI() {
|
function exportFormatUsesDPI(value) {
|
||||||
return Number.parseFloat(el.renderDPI.value) || DEFAULT_RENDER_DPI;
|
return value === "png" || value === "jpg";
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDPIControl(disabled = false) {
|
||||||
|
el.imageDPI.disabled = disabled || !state.doc || !exportFormatUsesDPI(el.pageExportFormat.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function currentImageDPI() {
|
||||||
|
return Number.parseFloat(el.imageDPI.value) || DEFAULT_IMAGE_DPI;
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatBytes(size, fallback = "PDF") {
|
function formatBytes(size, fallback = "PDF") {
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ 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) < 4 {
|
if len(args) < 3 {
|
||||||
return nil, fmt.Errorf("missing open arguments")
|
return nil, fmt.Errorf("missing open arguments")
|
||||||
}
|
}
|
||||||
data, err := bytesFromJS(args[0])
|
data, err := bytesFromJS(args[0])
|
||||||
@@ -91,12 +91,11 @@ func openDocument(args []js.Value) (any, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
renderAnnotations := args[2].Bool()
|
renderAnnotations := args[2].Bool()
|
||||||
dpi := args[3].Float()
|
|
||||||
if currentSession != nil {
|
if currentSession != nil {
|
||||||
_ = currentSession.Close()
|
_ = currentSession.Close()
|
||||||
currentSession = nil
|
currentSession = nil
|
||||||
}
|
}
|
||||||
session, err := Open(data, OpenOptions{Fonts: fonts, DPI: dpi, RenderAnnotations: renderAnnotations})
|
session, err := Open(data, OpenOptions{Fonts: fonts, RenderAnnotations: renderAnnotations})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -131,10 +130,10 @@ func exportPage(args []js.Value) (any, error) {
|
|||||||
if currentSession == nil {
|
if currentSession == nil {
|
||||||
return nil, fmt.Errorf("ofd document is not opened")
|
return nil, fmt.Errorf("ofd document is not opened")
|
||||||
}
|
}
|
||||||
if len(args) < 2 {
|
if len(args) < 3 {
|
||||||
return nil, fmt.Errorf("missing export page arguments")
|
return nil, fmt.Errorf("missing export page arguments")
|
||||||
}
|
}
|
||||||
data, format, err := currentSession.ExportPage(args[0].Int(), args[1].String())
|
data, format, err := currentSession.ExportPage(args[0].Int(), args[1].String(), args[2].Float())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-8
@@ -30,7 +30,6 @@ import (
|
|||||||
// OpenOptions 打开OFD文档选项
|
// OpenOptions 打开OFD文档选项
|
||||||
type OpenOptions struct {
|
type OpenOptions struct {
|
||||||
Fonts []FontFile
|
Fonts []FontFile
|
||||||
DPI float64
|
|
||||||
RenderAnnotations bool
|
RenderAnnotations bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,9 +186,6 @@ func Open(data []byte, opts OpenOptions) (*Session, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var rendererOptions []ofdgo.RendererOption
|
var rendererOptions []ofdgo.RendererOption
|
||||||
if opts.DPI > 0 {
|
|
||||||
rendererOptions = append(rendererOptions, ofdgo.WithDPI(opts.DPI))
|
|
||||||
}
|
|
||||||
if len(opts.Fonts) > 0 {
|
if len(opts.Fonts) > 0 {
|
||||||
fontFS := ofdgo.NewFontFS(opts.Fonts)
|
fontFS := ofdgo.NewFontFS(opts.Fonts)
|
||||||
if fontFS.Len() == 0 {
|
if fontFS.Len() == 0 {
|
||||||
@@ -276,9 +272,9 @@ func (s *Session) RenderPageSVG(index int) (PageSVG, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ExportPage 导出单页
|
// ExportPage 导出单页
|
||||||
// 入参: index 页面索引, value 导出格式
|
// 入参: index 页面索引, value 导出格式, dpi 图片DPI
|
||||||
// 返回: []byte 文件数据, ExportFormat 导出格式, error 错误信息
|
// 返回: []byte 文件数据, ExportFormat 导出格式, error 错误信息
|
||||||
func (s *Session) ExportPage(index int, value string) ([]byte, ExportFormat, error) {
|
func (s *Session) ExportPage(index int, value string, dpi float64) ([]byte, ExportFormat, error) {
|
||||||
format, ok := exportFormat(value)
|
format, ok := exportFormat(value)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, ExportFormat{}, fmt.Errorf("unsupported export format %s", value)
|
return nil, ExportFormat{}, fmt.Errorf("unsupported export format %s", value)
|
||||||
@@ -296,13 +292,13 @@ func (s *Session) ExportPage(index int, value string) ([]byte, ExportFormat, err
|
|||||||
case "eps":
|
case "eps":
|
||||||
err = s.Renderer.RenderToEPS(page, &buf)
|
err = s.Renderer.RenderToEPS(page, &buf)
|
||||||
case "png":
|
case "png":
|
||||||
img, renderErr := s.Renderer.RenderToImage(page)
|
img, renderErr := s.renderPageImage(page, dpi)
|
||||||
if renderErr != nil {
|
if renderErr != nil {
|
||||||
return nil, ExportFormat{}, renderErr
|
return nil, ExportFormat{}, renderErr
|
||||||
}
|
}
|
||||||
err = png.Encode(&buf, img)
|
err = png.Encode(&buf, img)
|
||||||
case "jpg":
|
case "jpg":
|
||||||
img, renderErr := s.Renderer.RenderToImage(page)
|
img, renderErr := s.renderPageImage(page, dpi)
|
||||||
if renderErr != nil {
|
if renderErr != nil {
|
||||||
return nil, ExportFormat{}, renderErr
|
return nil, ExportFormat{}, renderErr
|
||||||
}
|
}
|
||||||
@@ -314,6 +310,21 @@ func (s *Session) ExportPage(index int, value string) ([]byte, ExportFormat, err
|
|||||||
return buf.Bytes(), format, nil
|
return buf.Bytes(), format, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// renderPageImage 渲染页面图片
|
||||||
|
// 入参: page 页面内容, dpi 图片DPI
|
||||||
|
// 返回: image.Image 图像对象, error 错误信息
|
||||||
|
func (s *Session) renderPageImage(page *ofdgo.PageContent, dpi float64) (image.Image, error) {
|
||||||
|
if dpi <= 0 {
|
||||||
|
return s.Renderer.RenderToImage(page)
|
||||||
|
}
|
||||||
|
oldDPI := s.Renderer.DPI
|
||||||
|
s.Renderer.DPI = dpi
|
||||||
|
defer func() {
|
||||||
|
s.Renderer.DPI = oldDPI
|
||||||
|
}()
|
||||||
|
return s.Renderer.RenderToImage(page)
|
||||||
|
}
|
||||||
|
|
||||||
// signatureInfos 获取签名验证信息
|
// signatureInfos 获取签名验证信息
|
||||||
// 返回: []SignatureInfo 签名验证信息, error 错误信息
|
// 返回: []SignatureInfo 签名验证信息, error 错误信息
|
||||||
func (s *Session) signatureInfos() ([]SignatureInfo, error) {
|
func (s *Session) signatureInfos() ([]SignatureInfo, error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user