@mescius/dsimageviewer
Version:
Document Solutions Image Viewer
393 lines (392 loc) • 13.7 kB
JavaScript
var s = /* @__PURE__ */ ((i) => (i[i.Default = 0] = "Default", i[i.JPEG = 1] = "JPEG", i[i.PNG = 2] = "PNG", i[i.TIFF = 3] = "TIFF", i[i.GIF = 4] = "GIF", i[i.BMP = 5] = "BMP", i[i.ICO = 6] = "ICO", i[i.SVG = 7] = "SVG", i[i.WEBP = 8] = "WEBP", i))(s || {});
navigator.userAgent.indexOf("Trident/") > -1;
let c;
function g() {
return c || (c = {}, c[s.TIFF] = ["tif", "tiff", "xif", "xiff", "image/tiff", "image/tiff-fx", "image/x-tif", "image/x-tiff", "image/vnd.xiff", "images/xif", "application/tif", "application/tiff", "application/x-tif", "application/x-tiff"], c[s.BMP] = ["bmp", "bitmap", "application/bmp", "application/x-bmp", "application/x-win-bitmap", "image/ms-bmp", "image/x-bitmap", "image/x-bmp", "image/x-ms-bmp", "image/x-win-bitmap", "image/x-windows-bmp", "image/x-xbitmap"], c[s.SVG] = ["svg", "svg+xml", "text/xml-svg", "text/xml+svg", "image/svg", "image/svg-xml", "image/svg+xml", "image/vnd.adobe.svg+xml"], c[s.ICO] = ["ico", "image/ico", "image/x-icon", "application/ico", "application/x-ico"], c[s.GIF] = ["gif", "image/gi_", "image/gif"], c[s.JPEG] = ["jpg", "jpeg", "image/jp_", "image/jpe_", "image/jpg", "image/jpeg", "image/pipeg", "image/pjpeg", "application/jpg", "application/x-jpg", "image/vnd.swiftview-jpeg"], c[s.PNG] = ["png", "image/png", "application/png", "application/x-png"], c[s.WEBP] = ["webp", "image/webp"]), c;
}
function f(i, t = s.Default) {
if (!i)
return t;
if (typeof i == "number")
return i;
const e = [];
if (typeof i == "string")
e.push(i.toLowerCase().split(".").pop() || i);
else {
if (i.buffer)
return t;
i.type && e.push(i.type.toLowerCase()), i.name && e.push(i.name.toLowerCase().split(".").pop() || i.name);
}
const a = g();
for (const o of e)
for (const n in a)
if (a[n].find((p) => p === o))
return n * 1;
return t;
}
class m {
/**
* Gets the internationalization (i18n) instance from the viewer.
* @returns {i18n} The i18n instance.
*/
get in17n() {
return this._viewer.in17n;
}
/**
* Viewer instance identifier.
* @ignore exclude from docs.
**/
get instanceId() {
return this._viewer.instanceId;
}
/**
* Returns true if the image is loaded into the viewer and the image format is supported by the plugin.
**/
get isReady() {
const t = this._viewer;
return t ? t.viewerState.session.status === 3 && t.hasImage && this.isImageFormatSupported(t.imageFormat, !0) : !1;
}
/**
* Natural image size.
**/
get naturalSize() {
return this._viewer.naturalSize;
}
/**
* Gets the paint layer containing the HTML canvas for drawing the image.
**/
get paintLayer() {
return this._paintLayer || (this._paintLayer = this.viewer.ensurePaintLayer(), this.viewer.invalidate(), this.viewer.selectionBox.invalidate()), this._paintLayer;
}
/**
* Gets the image viewer instance.
* @returns {IImageViewer} The image viewer instance.
*/
get viewer() {
return this._viewer;
}
/**
* Initializes the plugin with the given image viewer.
* @param {IImageViewer} viewer - The image viewer instance to associate with this plugin.
* @returns {void}
*/
initialize(t) {
this._viewer = t;
}
/**
* Cleans up resources and disposes the plugin.
* @returns {void}
*/
dispose() {
this._viewer = void 0;
}
/**
* Determines whether the specified image format is supported for modifications.
*
* @param {ImageFormatCode | string} imageFormat - The image format to check, either as an enum value or string.
* @param {boolean} [allowUnknown=false] - If true, allows unknown formats (ImageFormatCode.Default) to be considered supported.
* @returns {boolean} True if the format is supported for modifications, false otherwise.
*
* @remarks
* The following formats are explicitly not supported:
* - TIFF (ImageFormatCode.TIFF)
* - SVG (ImageFormatCode.SVG)
* - ICO (ImageFormatCode.ICO)
* - GIF (ImageFormatCode.GIF)
*
* @example
* // Check if PNG is supported
* const supported = isImageFormatSupported(ImageFormatCode.PNG);
*
* @example
* // Check if an unknown format is supported (returns false by default)
* const supported = isImageFormatSupported('custom-format');
*
* @example
* // Check if an unknown format is supported (returns true when allowUnknown is true)
* const supported = isImageFormatSupported('custom-format', true);
*/
isImageFormatSupported(t, e) {
return t = f(t, s.Default), !e && t === s.Default ? !1 : t !== s.TIFF && t !== s.SVG && t !== s.ICO && t !== s.GIF;
}
/**
* Removes and disposes the active paint layer.
* If no paint layer exists, this method does nothing.
* @returns {void}
*/
removePaintLayer() {
this._paintLayer && (this.viewer.removeLayer(this._paintLayer), this._paintLayer = void 0);
}
}
class v {
/**
* Constructor.
* @param horizontal
* @param vertical
* @param rotationPlugin
*/
constructor(t, e, a) {
this.horizontal = t, this.vertical = e, this.rotationPlugin = a, this.name = "Flip";
}
/**
* Action implementation.
* @param viewer
**/
async execute(t) {
await this.rotationPlugin.flip(this.horizontal, this.vertical);
}
/**
* Undo action implementation.
* @param viewer
**/
async undo(t) {
await this.rotationPlugin.flip(this.horizontal, this.vertical);
}
}
class w {
/**
* Constructor.
* @param rotation
* @param prevRotation
* @param rotationPlugin
*/
constructor(t, e) {
this.rotation = t, this.rotationPlugin = e, this.name = "Rotation";
}
/**
* Action implementation.
* @param viewer
**/
async execute(t) {
await this.rotationPlugin.rotate(this.rotation);
}
/**
* Undo action implementation.
* @param viewer
**/
async undo(t) {
await this.rotationPlugin.rotate(-this.rotation);
}
}
function h(i) {
return i === !1 ? -1 : i || 0;
}
function _(i, t, e = 0, a = 0, o = !1, n = !1) {
i.save(), i.setTransform(
o ? -1 : 1,
0,
// set the direction of x axis
0,
n ? -1 : 1,
// set the direction of y axis
e + o ? t.width : 0,
// set the x origin
a + n ? t.height : 0
// set the y origin
), i.drawImage(t, 0, 0), i.restore();
}
class y extends m {
/**
* RotationPlugin constructor.
* @param options
*/
constructor(t) {
super(), this.id = "rotation", t = t || { rotatePosition: 1, flipHorizontalPosition: 2, flipVerticalPosition: 3 }, this.options = t;
}
initialize(t) {
this._viewer = t, this._ensureOptions(), t.toolbar.addItem(d(t, this)), t.toolbar.addItem(b(t, this)), t.toolbar.addItem(I(t, this));
const e = {
"rotate-image": h(this.options.rotatePosition),
"flip-horizontal": h(this.options.flipHorizontalPosition),
"flip-vertical": h(this.options.flipVerticalPosition)
}, a = [];
for (const o in e) {
const n = e[o];
n !== -1 && Number.isFinite(n) && (a[n] = o);
}
for (let o = 0; o < a.length; o++) {
const n = a[o];
n && ((t.toolbarLayout.viewer.default || []).splice(o, 0, n), (t.toolbarLayout.viewer.fullscreen || []).splice(o, 0, n), (t.toolbarLayout.viewer.mobile || []).splice(o, 0, n));
}
t.applyToolbarLayout(), t.onBeforeOpen.register(this._onBeforeOpen.bind(this)), this._initialized = !0;
}
dispose() {
this._initialized && (this._initialized = !1, this._removeRotateButtonFromLayout(this._viewer.toolbarLayout.viewer.default || [], "rotate-image"), this._removeRotateButtonFromLayout(this._viewer.toolbarLayout.viewer.fullscreen || [], "rotate-image"), this._removeRotateButtonFromLayout(this._viewer.toolbarLayout.viewer.mobile || [], "rotate-image"), this._removeRotateButtonFromLayout(this._viewer.toolbarLayout.viewer.default || [], "flip-horizontal"), this._removeRotateButtonFromLayout(this._viewer.toolbarLayout.viewer.fullscreen || [], "flip-horizontal"), this._removeRotateButtonFromLayout(this._viewer.toolbarLayout.viewer.mobile || [], "flip-horizontal"), this._removeRotateButtonFromLayout(this._viewer.toolbarLayout.viewer.default || [], "flip-vertical"), this._removeRotateButtonFromLayout(this._viewer.toolbarLayout.viewer.fullscreen || [], "flip-vertical"), this._removeRotateButtonFromLayout(this._viewer.toolbarLayout.viewer.mobile || [], "flip-vertical"), this._viewer.toolbar.removeItem("rotate-image"), this._viewer.toolbar.removeItem("flip-horizontal"), this._viewer.toolbar.removeItem("flip-vertical"), this._viewer = null, this._originalNaturalSize = null);
}
/**
* Specifies the rotation in degrees.
**/
getRotation() {
return this._rotation || 0;
}
async rotate(t) {
return this.setRotation(this._rotation + t);
}
/**
* Specifies the rotation in degrees.
**/
async setRotation(t) {
t = t % 360;
const e = await this._rotateImageData(t);
return e && !this._viewer.undoStorage.undoInProgress && this._viewer.undoStorage.onCommandExecuted(new w(t, this)), this._rotation = t, e;
}
/**
* Checks if the image format specified by the imageFormat parameter is supported.
* @param imageFormat
**/
isImageFormatSupported(t) {
return t = f(t), t !== s.TIFF && t !== s.SVG && t !== s.ICO && t !== s.GIF;
}
/**
* Flip image.
**/
flip(t = !0, e = !1) {
return new Promise((a) => {
const o = this._viewer, n = o.naturalSize, p = document.createElement("canvas");
p.width = n.width, p.height = n.height;
const u = p.getContext("2d"), l = new Image();
l.onload = () => {
_(u, l, 0, 0, t, e);
try {
const r = o.canvasToDataURL(p);
o.setImageDataUrl(r).then(() => {
a(!0), this._viewer.undoStorage.undoInProgress || this._viewer.undoStorage.onCommandExecuted(new v(t, e, this));
});
} catch (r) {
console.error(r), a(!1);
}
}, l.onerror = function(r) {
console.error(r), a(!1);
}, l.crossOrigin = "Anonymous";
try {
l.src = o.getImageDataUrl();
} catch (r) {
console.error(r), a(!1);
}
});
}
/**
* Flip image horizontally.
**/
flipHorizontal() {
return this.flip(!0, !1);
}
/**
* Flip image vertically.
**/
flipVertical() {
return this.flip(!1, !0);
}
//#region ** private
_removeRotateButtonFromLayout(t, e) {
if (!t) return;
const a = t.findIndex((o) => o === e);
a !== -1 && t.splice(a, 1);
}
_onBeforeOpen() {
this._originalNaturalSize = null, this._rotation = 0;
}
/**
* Rotate image data action.
**/
_rotateImageData(t) {
return new Promise((e) => {
const a = this._viewer, o = this._originalNaturalSize || a.naturalSize;
if (this._originalNaturalSize || (this._originalNaturalSize = o), a.imageFormat === 3) {
alert("Cannot rotate TIFF image."), e(!1);
return;
}
if (a.imageFormat === 7) {
let r = a.getOriginalImageDataUrl();
t && (r = r.replace("<svg", '<svg transform="rotate(' + t + ')"')), a.setImageDataUrl(r), e(!0);
return;
}
const n = document.createElement("canvas"), p = this._imageSizeAfterRotation([o.width, o.height], t);
n.width = p[0], n.height = p[1];
const u = n.getContext("2d");
u.translate(n.width / 2, n.height / 2), u.rotate(t * Math.PI / 180);
const l = new Image();
l.onload = function() {
u.drawImage(l, -o.width / 2, -o.height / 2);
try {
const r = a.canvasToDataURL(n);
a.setImageDataUrl(r), e(!0);
} catch (r) {
alert(r), e(!1);
}
}, l.onerror = function(r) {
console.error(r), e(!1);
}, l.crossOrigin = "Anonymous";
try {
l.src = a.getOriginalImageDataUrl();
} catch (r) {
alert(r), e(!1);
return;
}
});
}
_imageSizeAfterRotation(t, e) {
if (e = e % 180, e < 0 && (e = 180 + e), e >= 90 && (t = [t[1], t[0]], e = e - 90), e === 0)
return t;
const a = e * Math.PI / 180, o = t[0] * Math.cos(a) + t[1] * Math.sin(a), n = t[0] * Math.sin(a) + t[1] * Math.cos(a);
return [o, n];
}
_ensureOptions() {
const t = this.options || {};
t.rotatePosition === void 0 && (t.rotatePosition = 1), this.options = t;
}
//#endregion
}
(window || {}).RotationPlugin = y;
function d(i, t) {
return {
key: "rotate-image",
icon: { type: "svg", content: i.getType("svgIcons").rotate },
title: "Rotate image",
checked: !1,
enabled: !1,
action: () => {
t.setRotation(t.getRotation() + 90);
},
onUpdate: (a) => ({
title: t.getRotation() ? "Rotate image (" + t.getRotation() + "deg)" : "Rotate image",
enabled: a.state.session.status === 3 && i.hasImage && t.isImageFormatSupported(i.imageFormat)
})
};
}
function b(i, t) {
return {
key: "flip-horizontal",
icon: { type: "svg", content: i.getType("svgIcons")["flip-horizontal"] },
title: "Flip horizontal",
checked: !1,
enabled: !1,
action: () => {
t.flipHorizontal();
},
onUpdate: (a) => ({
title: "Flip horizontal",
enabled: a.state.session.status === 3 && i.hasImage && t.isImageFormatSupported(i.imageFormat)
})
};
}
function I(i, t) {
return {
key: "flip-vertical",
icon: { type: "svg", content: i.getType("svgIcons")["flip-vertical"] },
title: "Flip vertical",
checked: !1,
enabled: !1,
action: () => {
t.flipVertical();
},
onUpdate: (a) => ({
title: "Flip vertical",
enabled: a.state.session.status === 3 && i.hasImage && t.isImageFormatSupported(i.imageFormat)
})
};
}
export {
y as RotationPlugin,
_ as mirrorImage
};