Compare commits

...

14 commits

Author SHA1 Message Date
Nick
c7f531517a Update deps 2026-05-01 21:31:59 +02:00
Nick
6b6f37d903 Bump version to 1.4.1 2025-07-28 21:32:53 +02:00
Nick
d2dc1ef4cb Bumped version to 1.4.0 2025-07-27 10:42:25 +02:00
Benjamin Nelan
fcd8f9daf6
feat: Add support for Clip Studio Paint .clip files via sql.js and Web Assembly (#7)
* Added ClipStudioPaint support and necessary setting.
2025-07-27 10:39:43 +02:00
Nick
a0ed4b06ad Bump version to 1.3.0 2025-05-30 14:04:11 +02:00
Nick
3fe799c975 Added auto reload on file change 2025-05-30 14:03:37 +02:00
Nick
926932a7cc Removed console log, version bump 1.2.5 2025-02-21 21:23:41 +01:00
Nick
4e976fb48b
Merge pull request #2 from Nick-de-Bruin/dependabot/npm_and_yarn/esbuild-0.25.0
Bump esbuild from 0.17.3 to 0.25.0
2025-02-11 18:39:21 +01:00
Nick
4a8c2bfb8a Bump Obsidian version in package lock 2025-02-11 18:39:05 +01:00
dependabot[bot]
57191175f1
Bump esbuild from 0.17.3 to 0.25.0
Bumps [esbuild](https://github.com/evanw/esbuild) from 0.17.3 to 0.25.0.
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG-2023.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.17.3...v0.25.0)

---
updated-dependencies:
- dependency-name: esbuild
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-11 17:37:59 +00:00
Nick
5308033e31 Updated readme 2025-02-03 20:22:59 +01:00
Nick
a5e9d0d94a Bump version to 1.2.4 2025-01-26 20:37:40 +01:00
Nick
3790aa24de Added option parsing, added size parsing 2025-01-26 20:36:37 +01:00
Nick
6bbc919f72 Removed lie from settings 2025-01-25 10:56:14 +01:00
21 changed files with 3485 additions and 613 deletions

View file

@ -6,6 +6,14 @@ This is considered to be outside of the scope of this plugin.
File types can be toggled in the settings.
![](assets/embed_kra.png)
*`.kra` file provided and made by Tio Tzen Ann ([Artstation](https://www.artstation.com/greasetanker), [Instagram](https://www.instagram.com/bullyinggnomes/)).*
![](assets/embed_canvas.png)
*Also works in Canvas.*
# Currently Supported
The file types that are currently supported are:
@ -13,10 +21,32 @@ The file types that are currently supported are:
- `.kra` (Files made in Krita)
- `.psd` (Photoshop, other visual programs)
- `.ai` (Adobe Illustrator)
- `.clip` (Clip Studio Paint)
- `.gltf`, `.glb` (3D scene format)
- `.obj` (3D object format)
- `.stl` (3D format, often used for 3d printing)
## Settings
When embedding files, the following settings can be added as `![[file.ext|setting1=value;setting2=value]]` or `![setting1=value;setting2=value](file.ext)`.
**All files**:
- `width` or `widthxheight` in which both `width` and `height` are numbers. Follows the way images are embedded in Obsidian, and allows for the width and height of the embed to be changed.
**3d files** (`.obj`, `.gltf`, `.glb`, `.stl`):
- `spin=true` or `spin=false`, overrides the default setting on whether to animate 3d models.
- `camPos=x,y,z` in which `x`, `y`, and `z` are the coordinates the camera should have.
- `camLookAt=x,y,z` in which `x`, `y`, and `z` are the coordinates the camera should look at.
Note that with spin/animation enabled, `camPos` will not work, and `camLookAt` may not have the desired behavior, because the camera moves around.
Additionally, 3d objects that are loaded in are placed on `(0, 0, 0)` and scaled to fit in a unit cube.
**`.ai` files**:
- `scale=number`, will override the default setting for `.ai` file scaling. High values might cause high loading time.
## Contributing
If you wish to contribute to the plugin, feel free to open a pull-request or an issue.

BIN
assets/embed_canvas.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

BIN
assets/embed_kra.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 KiB

View file

@ -1,6 +1,8 @@
import esbuild from "esbuild";
import process from "process";
import builtins from "builtin-modules";
import { readFileSync } from "fs";
import { join } from 'path';
const banner =
`/*
@ -11,6 +13,33 @@ if you want to view the source, please visit the github repository of this plugi
const prod = (process.argv[2] === "production");
const wasmPlugin = {
name: 'wasm',
setup(build) {
build.onResolve({ filter: /\.wasm$/ }, args => {
if (args.resolveDir === '') return;
return {
path: join(args.resolveDir, args.path),
namespace: 'wasm-binary',
};
});
build.onLoad({ filter: /\.wasm$/, namespace: 'wasm-binary' }, async (args) => {
const contents = readFileSync(args.path);
const wasmBase64 = contents.toString('base64');
return {
contents: `
const wasmBase64 = "${wasmBase64}";
const wasmBinary = Uint8Array.from(atob(wasmBase64), c => c.charCodeAt(0));
export default wasmBinary;
`,
loader: 'js',
};
});
},
};
const context = await esbuild.context({
banner: {
js: banner,
@ -38,6 +67,9 @@ const context = await esbuild.context({
sourcemap: prod ? false : "inline",
treeShaking: true,
outfile: "main.js",
plugins: [
wasmPlugin
],
minify: prod,
});

17
main.ts
View file

@ -21,7 +21,7 @@ export default class ExtendedFileSupport extends Plugin {
this.registerExtensions([extension_type], extension.view_type);
embedRegistry.registerExtension(extension_type, (context, file, _) => {
return new extension.component(context.containerEl, this, file, context.linktext);
return new extension.component(context.containerEl, this, file, context.containerEl.getAttr('alt'));
});
}
}
@ -60,7 +60,7 @@ export default class ExtendedFileSupport extends Plugin {
this.registerExtensions(e.types, e.view_type);
embedRegistry.registerExtension(extension, (context, file, _) => {
return new e.component(context.containerEl, this, file, context.linktext);
return new e.component(context.containerEl, this, file, context.containerEl.getAttr('alt'));
});
} else {
this.app.viewRegistry.unregisterExtensions([extension]);
@ -97,6 +97,17 @@ class ExtendedFileSupportSettingTab extends PluginSettingTab {
this.plugin.toggleExtension("psd", value);
}));
new Setting(containerEl)
.setName(".clip")
.setDesc("Files generated by Clip Studio Paint.")
.addToggle(toggle => toggle
.setValue(this.plugin.settings.clip)
.onChange(async (value) => {
this.plugin.settings.clip = value;
await this.plugin.saveSettings();
this.plugin.toggleExtension("clip", value);
}));
new Setting(containerEl)
.setName(".kra")
.setDesc("Files generated by Krita.")
@ -121,7 +132,7 @@ class ExtendedFileSupportSettingTab extends PluginSettingTab {
new Setting(containerEl)
.setName(".ai render scale")
.setDesc("Render scale for Illustrator files. Higher means higher resolution, but longer load times. Default: 1.")
.setDesc("Render scale for Illustrator files. Higher means higher resolution, but longer load times. Default: 1.5.")
.addDropdown(dropdown => dropdown
.addOptions({"0.5": "0.5", "1.0": "1.0", "1.5": "1.5", "2.0": "2.0", "2.5": "2.5", "3.0": "3.0"})
.setValue(this.plugin.settings.ai_render_scale.toFixed(1))

View file

@ -1,7 +1,7 @@
{
"id": "extended-file-support",
"name": "Extended File Support",
"version": "1.2.1",
"version": "1.4.1",
"minAppVersion": "0.18.0",
"description": "Adds file support for various file types. Allows viewing and embedding these filetypes. Includes: .kra, .psd, .obj, .glb, .gltf, and more.",
"author": "Nick de Bruin",

3649
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
{
"name": "extended-file-support",
"version": "1.2.1",
"version": "1.4.1",
"description": "Extended file support for Obsidian",
"main": "main.js",
"scripts": {
@ -14,11 +14,12 @@
"devDependencies": {
"@types/node": "^16.11.6",
"@types/pdfjs-dist": "^2.10.378",
"@types/sql.js": "^1.4.9",
"@types/three": "^0.172.0",
"@typescript-eslint/eslint-plugin": "5.29.0",
"@typescript-eslint/parser": "5.29.0",
"builtin-modules": "3.3.0",
"esbuild": "0.17.3",
"esbuild": "0.25.0",
"obsidian": "latest",
"obsidian-typings": "^2.11.1",
"tslib": "2.4.0",
@ -27,6 +28,7 @@
"dependencies": {
"@webtoon/psd": "^0.4.0",
"@zip.js/zip.js": "^2.6.40",
"sql.js": "^1.13.0",
"three": "^0.172.0"
}
}

View file

@ -1,4 +1,4 @@
import { ExtensionComponent } from "src/extensionComponent";
import { AltTextParsed, ExtensionComponent } from "src/extensionComponent";
import { ExtensionView } from "src/extensionView";
import * as THREE from 'three';
@ -8,23 +8,69 @@ export abstract class ThreeJSComponent extends ExtensionComponent {
renderer?: THREE.WebGLRenderer;
scene?: THREE.Scene;
resizeObserver?: ResizeObserver;
spin: boolean;
camLookAt: THREE.Vector3;
camPos: THREE.Vector3;
abstract loadModel(resource: string): void;
parseLinkText(settings: AltTextParsed): void {
//#region spin
if (settings["spin"] && settings["spin"].toLowerCase() == "true") {
this.spin = true;
} else if (settings["spin"] && settings["spin"].toLowerCase() == "false") {
this.spin = false
} else {
this.spin = this.plugin.settings.animate_3d_objects;
}
//#endregion spin
//#region camLookAt
let camLookAtValid = false;
if (settings["camLookAt"]) {
const [x, y, z] = settings["camLookAt"].split(',');
if (Number(x) && Number(y) && Number(z)) {
this.camLookAt = new THREE.Vector3(Number(x), Number(y), Number(z));
camLookAtValid = true;
}
}
if (!camLookAtValid) {
this.camLookAt = new THREE.Vector3(0, 0, 0);
}
//#endregion camLookAt
//#region camPos
let camPosValid = false;
if (settings["camPos"]) {
const [x, y, z] = settings["camPos"].split(',');
if (Number(x) && Number(y) && Number(z)) {
this.camPos = new THREE.Vector3(Number(x), Number(y), Number(z));
camPosValid = true;
}
}
if (!camPosValid) {
this.camPos = new THREE.Vector3(1, 0.5, 1);
}
//#endregion camPos
}
async loadFile(): Promise<void> {
this.scene = new THREE.Scene();
// Subtract 1 to remove the scrollbar...
let width = this.contentEl.innerWidth - 1;
let width = this.width ?? this.contentEl.innerWidth - 1;
width = width > 0 ? width : 1;
const height = this.height ?? width;
this.renderer = new THREE.WebGLRenderer();
this.renderer.setSize(width, width);
this.renderer.setSize(width, height);
this.renderer.setClearColor(0x000000, 0);
const camera = new THREE.PerspectiveCamera( 75, 1, 0.1, 1000 );
camera.position.set(1, 0.5, 1);
camera.lookAt(0, 0, 0);
const camera = new THREE.PerspectiveCamera(75, 1, 0.1, 1000 );
camera.position.set(this.camPos.x, this.camPos.y, this.camPos.z);
camera.lookAt(this.camLookAt);
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
this.scene.add(ambientLight);
@ -47,12 +93,12 @@ export abstract class ThreeJSComponent extends ExtensionComponent {
this.renderer.setAnimationLoop(() => {
if (this.scene && this.renderer) {
if (this.plugin.settings.animate_3d_objects) {
if (this.spin) {
angle += 0.01;
camera.position.x = radius * Math.cos(angle);
camera.position.z = radius * Math.sin(angle);
camera.lookAt(0, 0, 0);
camera.lookAt(this.camLookAt);
}
this.renderer.render(this.scene, camera);
@ -60,20 +106,17 @@ export abstract class ThreeJSComponent extends ExtensionComponent {
});
this.resizeObserver = new ResizeObserver(() => {
let width = this.contentEl.innerWidth - 1;
if (this.linkText && !isNaN(Number(this.linkText))) {
width = Number(this.linkText);
if (!this.width) {
const width = this.contentEl.innerWidth - 1;
this.renderer?.setSize(width, width);
}
this.renderer?.setSize(width, width);
camera.updateProjectionMatrix();
});
this.resizeObserver.observe(this.contentEl);
}
onunload(): void {
cleanup(): void {
this.renderer?.setAnimationLoop(null);
this.renderer?.dispose();

View file

@ -1,20 +1,65 @@
import ExtendedFileSupport from "main";
import { Component, TFile } from "obsidian";
import { Component, EventRef, TFile } from "obsidian";
export type AltTextParsed = {[key: string]: string}
export abstract class ExtensionComponent extends Component {
protected plugin: ExtendedFileSupport;
protected contentEl: HTMLElement;
protected file: TFile;
protected linkText?: string;
protected linkText: string | null;
protected width?: number;
protected height?: number;
protected fileModify?: EventRef;
public constructor(contentEl: HTMLElement, plugin: ExtendedFileSupport, file: TFile, linkText?: string) {
public constructor(contentEl: HTMLElement, plugin: ExtendedFileSupport, file: TFile, linkText: string | null) {
super();
this.contentEl = contentEl;
this.plugin = plugin;
this.file = file;
this.linkText = linkText;
const parsed: AltTextParsed = {};
for (const val of linkText?.split(';') ?? []) {
const [key, value] = val.split('=');
if (key && value !== undefined) {
parsed[key] = value;
} else {
if (Number(val)) {
this.width = Number(val);
} else {
const [width, height] = val.split("x");
if (Number(width) && Number(height)) {
this.width = Number(width);
this.height = Number(height);
}
}
}
}
if (Number(contentEl.getAttr("width"))) {
this.width = Number(contentEl.getAttr("width"));
}
if (Number(contentEl.getAttr("height"))) {
this.height = Number(contentEl.getAttr("height"));
}
this.parseLinkText(parsed);
this.fileModify = this.plugin.app.vault.on("modify", (f) => {
if (f === this.file) {
this.contentEl.addClass("extended-file-loading");
this.contentEl.empty();
this.contentEl.createEl("i", { text: `Reloading ${this.file?.name}...`});
this.loadFile();
}
});
}
abstract parseLinkText(settings: AltTextParsed): void;
abstract loadFile(): void;
onload() {
@ -22,5 +67,13 @@ export abstract class ExtensionComponent extends Component {
this.contentEl.createEl("i", { text: `Loading ${this.file?.name}...`});
}
abstract onunload(): void;
onunload(): void {
if (this.fileModify) {
this.plugin.app.vault.offref(this.fileModify);
}
this.cleanup();
}
abstract cleanup(): void;
}

View file

@ -21,7 +21,7 @@ export abstract class ExtensionView<T extends ExtensionComponent> extends FileVi
async onLoadFile(file: TFile) {
const ComponentClass = this.getComponent();
this.component = new ComponentClass(this.contentEl, this.plugin, file);
this.component = new ComponentClass(this.contentEl, this.plugin, file, null);
this.component.loadFile();
}

View file

@ -1,11 +1,20 @@
import { loadPdfJs } from "obsidian";
import { ExtensionComponent } from "src/extensionComponent";
import { AltTextParsed, ExtensionComponent } from "src/extensionComponent";
import { ExtensionView } from "src/extensionView";
import type { PDFDocumentProxy } from "pdfjs-dist"
export const VIEW_TYPE_AI = "extended-file-support-ai";
export class AIComponent extends ExtensionComponent {
scale: number;
parseLinkText(settings: AltTextParsed): void {
if (settings["scale"] && Number(settings["scale"])) {
this.scale = Number(settings["scale"]);
} else {
this.scale = this.plugin.settings.ai_render_scale;
}
}
async loadFile(): Promise<void> {
const pdfJS = await loadPdfJs();
@ -14,22 +23,36 @@ export class AIComponent extends ExtensionComponent {
const page = await doc.getPage(1);
console.log(this.plugin.settings.ai_render_scale);
const SCALE = this.plugin.settings.ai_render_scale;
const SCALE = this.scale;
const viewport = page.getViewport({scale: SCALE});
const canvas = document.createElement('canvas');
canvas.width = viewport.width;
canvas.height = viewport.height;
canvas.addClass("full-width");
canvas.width = this.width ?? viewport.width;
canvas.height = this.height ?? (this.width ? (viewport.height / viewport.width * this.width) : viewport.height);
const context = canvas.getContext('2d');
if (context) {
await page.render({ canvasContext: context, viewport: viewport}).promise;
if (this.width) {
const tempCanvas = document.createElement("canvas");
tempCanvas.width = viewport.width;
tempCanvas.height = viewport.height;
const tempContext = tempCanvas.getContext("2d");
if (tempContext && context) {
await page.render({ canvasContext: tempContext, viewport: viewport}).promise;
context.drawImage(tempCanvas, 0, 0, tempCanvas.width, tempCanvas.height, 0, 0, canvas.width, canvas.height);
}
} else {
if (context) {
await page.render({ canvasContext: context, viewport: viewport}).promise;
}
canvas.addClass("full-width");
}
this.contentEl.empty();
this.contentEl.removeClass("extended-file-loading");
this.contentEl.addClasses(["media-embed", "image-embed"]);
@ -42,7 +65,7 @@ export class AIComponent extends ExtensionComponent {
}
}
onunload(): void {}
cleanup(): void {}
}
export class AIView extends ExtensionView<AIComponent> {

114
src/extensions/clip.ts Normal file
View file

@ -0,0 +1,114 @@
import { AltTextParsed, ExtensionComponent } from "src/extensionComponent";
import { ExtensionView } from "src/extensionView";
import initSqlJs from 'sql.js'
// @ts-ignore
import wasmBinary from '../../node_modules/sql.js/dist/sql-wasm.wasm';
export const VIEW_TYPE_CLIP = "extended-file-support-clip";
export class CLIPComponent extends ExtensionComponent {
private sql: any = null
private objectURL?: string;
parseLinkText(_: AltTextParsed): void { }
private async getSql() {
if (!this.sql) {
try{
this.sql = await initSqlJs({
wasmBinary: wasmBinary
});
} catch (error) {
console.error('Failed to load sql.js WebAssembly file required to read .clip files.', error);
this.sql = false;
}
}
return this.sql;
}
async loadFile(): Promise<void> {
const resource = this.plugin.app.vault.getResourcePath(this.file);
const res = await fetch(resource);
const arrayBuffer = await res.arrayBuffer();
const offset = this.getDatabaseOffset(arrayBuffer);
if (offset !== -1) {
const sqliteDB = arrayBuffer.slice(offset);
const SQL = await this.getSql();
try{
const db = new SQL.Database(new Uint8Array(sqliteDB));
const result = db.exec("SELECT imageData FROM CanvasPreview");
if ( !result || result.length === 0 ) {
throw new Error("No image data found in CanvasPreview table");
}
const imageBytes = result[0].values[0][0] as Uint8Array;
const image_file = new Blob([imageBytes]);
this.objectURL = URL.createObjectURL(image_file);
} catch (error) {
console.error('Error accessing imageData from sqlite database.', error);
}
}
if (this.objectURL) {
const image = new Image();
image.src = this.objectURL;
image.alt = this.file.name;
if (this.width) {
image.width = this.width;
}
if (this.height) {
image.height = this.height;
}
this.contentEl.empty();
this.contentEl.removeClass("extended-file-loading");
this.contentEl.addClasses(["media-embed", "image-embed"]);
this.contentEl.append(image);
} else {
this.contentEl.empty();
this.contentEl.createEl("i", { text: `Could not load ${this.file.path}` });
}
}
cleanup(): void {
if (this.objectURL) {
URL.revokeObjectURL(this.objectURL);
this.objectURL = undefined;
}
}
getDatabaseOffset(arrayBuffer: ArrayBuffer): number {
const haystack = new Uint8Array(arrayBuffer);
const needle = new TextEncoder().encode('SQLite format 3\0');
for (let i = 0; i <= haystack.length - needle.length; i++) {
let found = true;
for (let j = 0; j < needle.length; j++) {
if (haystack[i + j] !== needle[j]) {
found = false;
break;
}
}
if (found) {
return i;
}
}
return -1;
}
}
export class CLIPView extends ExtensionView<CLIPComponent> {
getIcon(): string {
return "image";
}
getComponent(): new (...args: ConstructorParameters<typeof ExtensionComponent>) => CLIPComponent {
return CLIPComponent;
}
getViewType(): string {
return VIEW_TYPE_CLIP;
}
}

View file

@ -1,6 +1,5 @@
import ExtendedFileSupport from "main";
import { TFile } from "obsidian";
import { ThreeJSComponent, ThreeJSView } from "src/abstractions/threejsComponent";
import { ExtensionComponent } from "src/extensionComponent";
import { GLTFLoader } from "three/examples/jsm/Addons.js";
export const VIEW_TYPE_GLB = "extended-file-support-GLB";
@ -20,7 +19,7 @@ export class GLBComponent extends ThreeJSComponent {
}
export class GLBView extends ThreeJSView<GLBComponent> {
getComponent(): new (contentEl: HTMLElement, plugin: ExtendedFileSupport, file: TFile, linkText?: string | undefined) => GLBComponent {
getComponent(): new (...args: ConstructorParameters<typeof ExtensionComponent>) => GLBComponent {
return GLBComponent;
}

View file

@ -1,5 +1,5 @@
import { BlobReader, BlobWriter, ZipReader } from "@zip.js/zip.js";
import { ExtensionComponent } from "src/extensionComponent";
import { AltTextParsed, ExtensionComponent } from "src/extensionComponent";
import { ExtensionView } from "src/extensionView";
export const VIEW_TYPE_KRA = "extended-file-support-kra";
@ -7,6 +7,8 @@ export const VIEW_TYPE_KRA = "extended-file-support-kra";
export class KRAComponent extends ExtensionComponent {
private objectURL?: string;
parseLinkText(_: AltTextParsed): void { }
async loadFile(): Promise<void> {
const MERGED_PATH = "mergedimage.png";
@ -29,6 +31,13 @@ export class KRAComponent extends ExtensionComponent {
image.src = this.objectURL;
image.alt = this.file.name;
if (this.width) {
image.width = this.width;
}
if (this.height) {
image.height = this.height;
}
this.contentEl.empty();
this.contentEl.removeClass("extended-file-loading");
this.contentEl.addClasses(["media-embed", "image-embed"]);
@ -39,7 +48,7 @@ export class KRAComponent extends ExtensionComponent {
}
}
onunload(): void {
cleanup(): void {
if (this.objectURL) {
URL.revokeObjectURL(this.objectURL);
this.objectURL = undefined;

View file

@ -1,6 +1,5 @@
import ExtendedFileSupport from "main";
import { TFile } from "obsidian";
import { ThreeJSComponent, ThreeJSView } from "src/abstractions/threejsComponent";
import { ExtensionComponent } from "src/extensionComponent";
import { OBJLoader } from 'three/examples/jsm/Addons.js';
export const VIEW_TYPE_OBJ = "extended-file-support-obj";
@ -21,7 +20,7 @@ export class OBJComponent extends ThreeJSComponent {
}
export class OBJView extends ThreeJSView<OBJComponent> {
getComponent(): new (contentEl: HTMLElement, plugin: ExtendedFileSupport, file: TFile, linkText?: string | undefined) => OBJComponent {
getComponent(): new (...args: ConstructorParameters<typeof ExtensionComponent>) => OBJComponent {
return OBJComponent;
}

View file

@ -1,10 +1,12 @@
import { ExtensionComponent } from "src/extensionComponent";
import { AltTextParsed, ExtensionComponent } from "src/extensionComponent";
import { ExtensionView } from "src/extensionView";
import Psd from "@webtoon/psd";
export const VIEW_TYPE_PSD = "extended-file-support-psd";
export class PSDComponent extends ExtensionComponent {
parseLinkText(_: AltTextParsed): void { }
async loadFile(): Promise<void> {
const resource = this.plugin.app.vault.getResourcePath(this.file);
const res = await fetch(resource);
@ -18,19 +20,33 @@ export class PSDComponent extends ExtensionComponent {
const imageData = new ImageData(compositeBuffer, psd.width, psd.height);
canvasEl.width = psd.width;
canvasEl.height = psd.height;
canvasEl.width = this.width ?? psd.width;
canvasEl.height = this.height ?? (this.width ? (psd.height / psd.width * this.width) : psd.height);
canvasEl.addClass("full-width");
if (this.width) {
const tempCanvas = document.createElement("canvas");
tempCanvas.width = imageData.width;
tempCanvas.height = imageData.height;
const tempContext = tempCanvas.getContext("2d");
if (tempContext) {
tempContext.putImageData(imageData, 0, 0);
context?.drawImage(tempCanvas, 0, 0, tempCanvas.width, tempCanvas.height, 0, 0, canvasEl.width, canvasEl.height);
}
} else {
canvasEl.addClass("full-width");
context?.putImageData(imageData, 0, 0);
}
context?.putImageData(imageData, 0, 0);
this.contentEl.empty();
this.contentEl.removeClass("extended-file-loading");
this.contentEl.addClasses(["media-embed", "image-embed"]);
this.contentEl.append(canvasEl);
}
onunload(): void {}
cleanup(): void {}
}
export class PSDView extends ExtensionView<PSDComponent> {

View file

@ -1,8 +1,7 @@
import ExtendedFileSupport from "main";
import { TFile } from "obsidian";
import { ThreeJSComponent, ThreeJSView } from "src/abstractions/threejsComponent";
import { STLLoader } from "three/examples/jsm/Addons.js";
import * as THREE from 'three';
import { ExtensionComponent } from "src/extensionComponent";
export const VIEW_TYPE_STL = "extended-file-support-STL";
@ -30,7 +29,7 @@ export class STLComponent extends ThreeJSComponent {
}
export class STLView extends ThreeJSView<STLComponent> {
getComponent(): new (contentEl: HTMLElement, plugin: ExtendedFileSupport, file: TFile, linkText?: string | undefined) => STLComponent {
getComponent(): new (...args: ConstructorParameters<typeof ExtensionComponent>) => STLComponent {
return STLComponent;
}

View file

@ -4,6 +4,7 @@ import { ExtensionComponent } from "./extensionComponent"
import { OBJComponent, OBJView, VIEW_TYPE_OBJ } from "./extensions/obj"
import { GLBComponent, GLBView, VIEW_TYPE_GLB } from "./extensions/glb"
import { PSDComponent, PSDView, VIEW_TYPE_PSD } from "./extensions/psd"
import { CLIPComponent, CLIPView, VIEW_TYPE_CLIP } from "./extensions/clip"
import { STLComponent, STLView, VIEW_TYPE_STL } from "./extensions/stl"
import { AIComponent, AIView, VIEW_TYPE_AI } from "./extensions/ai"
@ -17,6 +18,7 @@ export type Extension = {
// Type should match settings field
export const EXTENSION_REGISTRY: Extension[] = [
{ types: ["kra"], view_type: VIEW_TYPE_KRA, view: KRAView, component: KRAComponent },
{ types: ["clip"], view_type: VIEW_TYPE_CLIP, view: CLIPView, component: CLIPComponent },
{ types: ["obj"], view_type: VIEW_TYPE_OBJ, view: OBJView, component: OBJComponent },
{ types: ["glb", "gltf"], view_type: VIEW_TYPE_GLB, view: GLBView, component: GLBComponent },
{ types: ["psd"], view_type: VIEW_TYPE_PSD, view: PSDView, component: PSDComponent },

View file

@ -1,5 +1,6 @@
export interface ExtendedFileSupportSettings {
kra: boolean;
clip: boolean;
psd: boolean;
ai: boolean;
ai_render_scale: number;
@ -14,6 +15,7 @@ export interface ExtendedFileSupportSettings {
export const DEFAULT_SETTINGS: ExtendedFileSupportSettings = {
kra: true,
clip: true,
psd: true,
ai: true,
ai_render_scale: 1.5,

View file

@ -1,5 +1,10 @@
{
"1.0.0": "0.18.0",
"1.0.1": "0.18.0",
"1.2.1": "0.18.0"
"1.2.1": "0.18.0",
"1.2.4": "0.18.0",
"1.2.5": "0.18.0",
"1.3.0": "0.18.0",
"1.4.0": "0.18.0",
"1.4.1": "0.18.0"
}