mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-14 20:14:37 +00:00
web: Support file types
- added new exportable type `tvg` - support jpg/png/svg/tvg load
This commit is contained in:
parent
5f088a2357
commit
20a6ca19e7
1 changed files with 90 additions and 42 deletions
|
@ -45,6 +45,16 @@ export interface LibraryVersion {
|
||||||
// Define file type which can be exported
|
// Define file type which can be exported
|
||||||
export enum ExportableType {
|
export enum ExportableType {
|
||||||
GIF = 'gif',
|
GIF = 'gif',
|
||||||
|
TVG = 'tvg',
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define mime type which player can load
|
||||||
|
export enum MimeType {
|
||||||
|
JSON = 'json',
|
||||||
|
JPG = 'jpg',
|
||||||
|
PNG = 'png',
|
||||||
|
SVG = 'svg',
|
||||||
|
TVG = 'tvg',
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define valid player states
|
// Define valid player states
|
||||||
|
@ -79,7 +89,7 @@ export enum PlayerEvent {
|
||||||
Stop = "stop",
|
Stop = "stop",
|
||||||
}
|
}
|
||||||
|
|
||||||
const _parseURL = async (url: string): Promise<LottieJson> => {
|
const _parseLottieFromURL = async (url: string): Promise<LottieJson> => {
|
||||||
if (typeof url !== "string") {
|
if (typeof url !== "string") {
|
||||||
throw new Error(`The url value must be a string`);
|
throw new Error(`The url value must be a string`);
|
||||||
}
|
}
|
||||||
|
@ -97,21 +107,45 @@ const _parseURL = async (url: string): Promise<LottieJson> => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const _parseSrc = async (src: string | object): Promise<Uint8Array> => {
|
const _parseImageFromURL = async (url: string): Promise<ArrayBuffer> => {
|
||||||
let data = src;
|
const response = await fetch(url);
|
||||||
if (typeof data === "object") {
|
return response.arrayBuffer();
|
||||||
data = JSON.stringify(data);
|
}
|
||||||
} else if (typeof data === "string") {
|
|
||||||
try {
|
const _parseJSON = async (data: string): Promise<string> => {
|
||||||
data = JSON.parse(data);
|
try {
|
||||||
} catch (err) {
|
data = JSON.parse(data);
|
||||||
const json = await _parseURL(data as string);
|
} catch (err) {
|
||||||
data = JSON.stringify(json);
|
const json = await _parseLottieFromURL(data as string);
|
||||||
}
|
data = JSON.stringify(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
const _parseSrc = async (src: string | object | ArrayBuffer, mimeType: MimeType): Promise<Uint8Array> => {
|
||||||
const encoder = new TextEncoder();
|
const encoder = new TextEncoder();
|
||||||
return encoder.encode(data as string);
|
let data = src;
|
||||||
|
|
||||||
|
switch (typeof data) {
|
||||||
|
case 'object':
|
||||||
|
if (data instanceof ArrayBuffer) {
|
||||||
|
return new Uint8Array(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
data = JSON.stringify(data);
|
||||||
|
return encoder.encode(data);
|
||||||
|
case 'string':
|
||||||
|
if (mimeType === MimeType.JSON) {
|
||||||
|
data = await _parseJSON(data);
|
||||||
|
return encoder.encode(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
const buffer = await _parseImageFromURL(data);
|
||||||
|
return new Uint8Array(buffer);
|
||||||
|
default:
|
||||||
|
throw new Error('Invalid src type');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const _wait = (timeToDelay: number) => {
|
const _wait = (timeToDelay: number) => {
|
||||||
|
@ -141,6 +175,13 @@ export class LottiePlayer extends LitElement {
|
||||||
@property({ type: String })
|
@property({ type: String })
|
||||||
public src?: string;
|
public src?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File mime type.
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
@property({ type: MimeType })
|
||||||
|
public mimeType: MimeType = MimeType.JSON;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Animation speed.
|
* Animation speed.
|
||||||
* @since 1.0
|
* @since 1.0
|
||||||
|
@ -244,7 +285,7 @@ export class LottiePlayer extends LitElement {
|
||||||
this._TVG = _tvg;
|
this._TVG = _tvg;
|
||||||
|
|
||||||
if (this.src) {
|
if (this.src) {
|
||||||
this.load(this.src);
|
this.load(this.src, this.mimeType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,7 +299,7 @@ export class LottiePlayer extends LitElement {
|
||||||
|
|
||||||
if (this.src) {
|
if (this.src) {
|
||||||
if (this._TVG) {
|
if (this._TVG) {
|
||||||
this.load(this.src);
|
this.load(this.src, this.mimeType);
|
||||||
} else {
|
} else {
|
||||||
this._timer = setInterval(this._delayedLoad.bind(this), 100);
|
this._timer = setInterval(this._delayedLoad.bind(this), 100);
|
||||||
}
|
}
|
||||||
|
@ -282,7 +323,7 @@ export class LottiePlayer extends LitElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
private _loadBytes(data: Uint8Array, rPath: string = ''): void {
|
private _loadBytes(data: Uint8Array, rPath: string = ''): void {
|
||||||
const isLoaded = this._TVG.load(data, 'lottie', this._canvas!.width, this._canvas!.height, rPath);
|
const isLoaded = this._TVG.load(data, this.mimeType, this._canvas!.width, this._canvas!.height, rPath);
|
||||||
if (!isLoaded) {
|
if (!isLoaded) {
|
||||||
throw new Error('Unable to load an image. Error: ', this._TVG.error());
|
throw new Error('Unable to load an image. Error: ', this._TVG.error());
|
||||||
}
|
}
|
||||||
|
@ -372,11 +413,12 @@ export class LottiePlayer extends LitElement {
|
||||||
* Configure and load
|
* Configure and load
|
||||||
* @since 1.0
|
* @since 1.0
|
||||||
*/
|
*/
|
||||||
public async load(src: string | object): Promise<void> {
|
public async load(src: string | object, mimeType: MimeType = MimeType.JSON): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const bytes = await _parseSrc(src);
|
const bytes = await _parseSrc(src, mimeType);
|
||||||
this.dispatchEvent(new CustomEvent(PlayerEvent.Ready));
|
this.dispatchEvent(new CustomEvent(PlayerEvent.Ready));
|
||||||
|
|
||||||
|
this.mimeType = mimeType;
|
||||||
this._loadBytes(bytes);
|
this._loadBytes(bytes);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.currentState = PlayerState.Error;
|
this.currentState = PlayerState.Error;
|
||||||
|
@ -389,6 +431,10 @@ export class LottiePlayer extends LitElement {
|
||||||
* @since 1.0
|
* @since 1.0
|
||||||
*/
|
*/
|
||||||
public play(): void {
|
public play(): void {
|
||||||
|
if (this.mimeType !== MimeType.JSON) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.totalFrame = this._TVG.totalFrame();
|
this.totalFrame = this._TVG.totalFrame();
|
||||||
if (this.totalFrame < 1) {
|
if (this.totalFrame < 1) {
|
||||||
return;
|
return;
|
||||||
|
@ -528,31 +574,33 @@ export class LottiePlayer extends LitElement {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bytes = await _parseSrc(this.src);
|
const isExported = this._TVG.save(target);
|
||||||
|
if (!isExported) {
|
||||||
switch (target) {
|
throw new Error('Unable to save. Error: ', this._TVG.error());
|
||||||
case ExportableType.GIF:
|
|
||||||
const isExported = this._TVG.save2Gif(bytes, 'lottie', this._canvas!.width, this._canvas!.height, 30);
|
|
||||||
if (!isExported) {
|
|
||||||
throw new Error('Unable to save a GIF. Error: ', this._TVG.error());
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = _module.FS.readFile('output.gif');
|
|
||||||
if (data.length < 6) {
|
|
||||||
throw new Error("Unable to save the Gif data. The generated file size is invalid.");
|
|
||||||
}
|
|
||||||
|
|
||||||
const blob = new Blob([data], {type: 'application/octet-stream'});
|
|
||||||
const link = document.createElement("a");
|
|
||||||
link.setAttribute('href', URL.createObjectURL(blob));
|
|
||||||
link.setAttribute('download', 'output.gif');
|
|
||||||
document.body.appendChild(link);
|
|
||||||
link.click();
|
|
||||||
document.body.removeChild(link);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Error('Unsupported file type.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fileName = `output.${target}`;
|
||||||
|
const data = _module.FS.readFile(fileName);
|
||||||
|
|
||||||
|
if (target === ExportableType.GIF && data.length < 6) {
|
||||||
|
throw new Error(
|
||||||
|
`Unable to save the GIF data. The generated file size is invalid.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target === ExportableType.TVG && data.length < 33) {
|
||||||
|
throw new Error(
|
||||||
|
`Unable to save the TVG data. The generated file size is invalid.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const blob = new Blob([data], {type: 'application/octet-stream'});
|
||||||
|
const link = document.createElement("a");
|
||||||
|
link.setAttribute('href', URL.createObjectURL(blob));
|
||||||
|
link.setAttribute('download', fileName);
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Add table
Reference in a new issue