Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make linking optional #15

Merged
merged 2 commits into from
Jan 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Goal of this Plugin in to implement a native PDF handling workflow in Obsidian
### Features

- Insert a single PDF Page inside Note
- Insert a list or range of Pages into Obsidian Note
- Insert a list or range of pages into Obsidian Note
- Hyperlink to PDF
- Scale the size of PDF Pages to fit Note layout
- Rotate PDF
Expand All @@ -20,9 +20,10 @@ Goal of this Plugin in to implement a native PDF handling workflow in Obsidian
|parameter|required|example|
|--|--|--|
|url |yes |**myPDF.pdf** or **subfolder/myPDF.pdf** or "[[MyFile.pdf]]"
|link|optional (default = false)| **true** or **false**
|page|optional (default = 1)| **1** or **[1, [3, 6], 8]** where **[3, 6]** is an inclusive range of pages
|range|optional| **[1, 3]** Insert pages **1** to **3** (inclusive). Overwrites page.
|scale|optional (default = 1.0)| **0.5** for 50% size or **2.0** for 200% size
|fit|optional (default = true)| **true** or **false**
|rotation|optional (default = 0)| **90** for 90deg or **-90** -90deg or **180**
|rect|optional (default = \[0,0,0,0\])| offsetX, offsetY, sizeX, sizeX in Pixel
|rect|optional (default = \[0,0,0,0\])| offsetX, offsetY, sizeX, sizeX in Pixel
325 changes: 168 additions & 157 deletions main.ts
Original file line number Diff line number Diff line change
@@ -1,157 +1,168 @@
import { Plugin, MarkdownRenderChild, App } from "obsidian";
import * as pdfjs from "pdfjs-dist/build/pdf.js";
import * as worker from "pdfjs-dist/build/pdf.worker.entry.js";

interface PdfNodeParameters {
url: string;
page: number | Array<number | Array<number>>;
scale: number;
fit: boolean,
rotation: number;
rect: Array<number>;
}

export default class BetterPDFPlugin extends Plugin {
async onload() {
console.log("Better PDF loading...");

pdfjs.GlobalWorkerOptions.workerSrc = worker;

this.registerMarkdownCodeBlockProcessor("pdf", async (src, el, ctx) => {

// Get Parameters
let parameters: PdfNodeParameters = null;
try {
parameters = this.readParameters(src);
} catch (e) {
el.createEl("h2", { text: "PDF Parameters invalid: " + e.message });
}

//Create PDF Node
if (parameters !== null) {
try {

//Read Document
var vaultName = this.app.vault.getName();
var buffer = await this.app.vault.adapter.readBinary(parameters.url);
var document = await pdfjs.getDocument(buffer).promise;

//Read pages
for (let pageNumber of <number[]>parameters.page) {
var page = await document.getPage(pageNumber);

// Create hyperlink for Page
var href = el.createEl("a");
href.href = parameters.url + "#page=" + pageNumber;
href.className = "internal-link";

// Get Viewport
var offsetX = Math.floor(
parameters.rect[0] * -1 * parameters.scale
);
var offsetY = Math.floor(
parameters.rect[1] * -1 * parameters.scale
);

var viewport = page.getViewport({
scale: parameters.scale,
rotation: parameters.rotation,
offsetX: offsetX,
offsetY: offsetY,
});

// Render Canvas
var canvas = href.createEl("canvas");
if (parameters.fit) {
canvas.style.width = "100%";
}

var context = canvas.getContext("2d");

if (parameters.rect[2] < 1) {
canvas.height = viewport.height;
canvas.width = viewport.width;
} else {
canvas.height = Math.floor(parameters.rect[2] * parameters.scale);
canvas.width = Math.floor(parameters.rect[3] * parameters.scale);
}

var renderContext = {
canvasContext: context,
viewport: viewport,
};
await page.render(renderContext);
}
} catch (error) {
el.createEl("h2", { text: error });
}
}
});
}

private readParameters(jsonString: any) {
// "url" : [[file.pdf]] is an invalid json since it misses quotation marks in value
if (jsonString.contains("[[") && !jsonString.contains('"[[')) {
jsonString = jsonString.replace("[[", '"[[');
jsonString = jsonString.replace("]]", ']]"');
}

let parameters: PdfNodeParameters = JSON.parse(jsonString);

//Transform internal Link to external
if (parameters.url.startsWith("[[")) {
parameters.url = parameters.url.substr(2, parameters.url.length - 4);
parameters.url = this.app.metadataCache.getFirstLinkpathDest(
parameters.url,
""
).path;
}

//Convert Range (if present) and Page to Array<Page>
if (parameters.range !== undefined) {
parameters.page = Array.from({ length: parameters.range[1] - parameters.range[0] + 1 }, (_, i) => parameters.range[0] + i);
}
if (typeof parameters.page === "number") {
parameters.page = [parameters.page];
}
if (parameters.page === undefined) {
parameters.page = [1];
}

// Flatten ranges
for (let i = 0; i < parameters.page.length; i++) {
if (Array.isArray(parameters.page[i])) {
let range = parameters.page.splice(i, 1)[0] as Array<number>;
for (let j = range[0]; j <= range[1]; j++) {
parameters.page.splice(i, 0, j);
i += 1;
}
}
}

if (
parameters.scale === undefined ||
parameters.scale < 0.1 ||
parameters.scale > 10.0
) {
parameters.scale = 1.0;
}

if (parameters.fit === undefined) {
parameters.fit = true;
}

if (parameters.rotation === undefined) {
parameters.rotation = 0;
}

if (parameters.rect === undefined) {
parameters.rect = [0, 0, 0, 0];
}
return parameters;
}

onunload() {
console.log("unloading Better PDF plugin...");
}
}
import { Plugin, MarkdownRenderChild, App } from "obsidian";
import * as pdfjs from "pdfjs-dist/build/pdf.js";
import * as worker from "pdfjs-dist/build/pdf.worker.entry.js";

interface PdfNodeParameters {
url: string;
link: boolean;
page: number | Array<number | Array<number>>;
scale: number;
fit: boolean,
rotation: number;
rect: Array<number>;
}

export default class BetterPDFPlugin extends Plugin {
async onload() {
console.log("Better PDF loading...");

pdfjs.GlobalWorkerOptions.workerSrc = worker;

this.registerMarkdownCodeBlockProcessor("pdf", async (src, el, ctx) => {

// Get Parameters
let parameters: PdfNodeParameters = null;
try {
parameters = this.readParameters(src);
} catch (e) {
el.createEl("h2", { text: "PDF Parameters invalid: " + e.message });
}

//Create PDF Node
if (parameters !== null) {
try {

//Read Document
var vaultName = this.app.vault.getName();
var buffer = await this.app.vault.adapter.readBinary(parameters.url);
var document = await pdfjs.getDocument(buffer).promise;

//Read pages
for (let pageNumber of <number[]>parameters.page) {
var page = await document.getPage(pageNumber);
var host = el;

// Create hyperlink for Page
if (parameters.link) {
var href = el.createEl("a");
href.href = parameters.url + "#page=" + pageNumber;
href.className = "internal-link";

host = href;
}

// Get Viewport
var offsetX = Math.floor(
parameters.rect[0] * -1 * parameters.scale
);
var offsetY = Math.floor(
parameters.rect[1] * -1 * parameters.scale
);

var viewport = page.getViewport({
scale: parameters.scale,
rotation: parameters.rotation,
offsetX: offsetX,
offsetY: offsetY,
});

// Render Canvas
var canvas = href.createEl("canvas");
if (parameters.fit) {
canvas.style.width = "100%";
}

var context = canvas.getContext("2d");

if (parameters.rect[2] < 1) {
canvas.height = viewport.height;
canvas.width = viewport.width;
} else {
canvas.height = Math.floor(parameters.rect[2] * parameters.scale);
canvas.width = Math.floor(parameters.rect[3] * parameters.scale);
}

var renderContext = {
canvasContext: context,
viewport: viewport,
};
await page.render(renderContext);
}
} catch (error) {
el.createEl("h2", { text: error });
}
}
});
}

private readParameters(jsonString: any) {
// "url" : [[file.pdf]] is an invalid json since it misses quotation marks in value
if (jsonString.contains("[[") && !jsonString.contains('"[[')) {
jsonString = jsonString.replace("[[", '"[[');
jsonString = jsonString.replace("]]", ']]"');
}

let parameters: PdfNodeParameters = JSON.parse(jsonString);

//Transform internal Link to external
if (parameters.url.startsWith("[[")) {
parameters.url = parameters.url.substr(2, parameters.url.length - 4);
parameters.url = this.app.metadataCache.getFirstLinkpathDest(
parameters.url,
""
).path;
}

if (parameters.link === undefined) {
parameters.link = false;
}

//Convert Range (if present) and Page to Array<Page>
if (parameters.range !== undefined) {
parameters.page = Array.from({ length: parameters.range[1] - parameters.range[0] + 1 }, (_, i) => parameters.range[0] + i);
}

if (typeof parameters.page === "number") {
parameters.page = [parameters.page];
}
if (parameters.page === undefined) {
parameters.page = [1];
}

// Flatten ranges
for (let i = 0; i < parameters.page.length; i++) {
if (Array.isArray(parameters.page[i])) {
let range = parameters.page.splice(i, 1)[0] as Array<number>;
for (let j = range[0]; j <= range[1]; j++) {
parameters.page.splice(i, 0, j);
i += 1;
}
}
}

if (
parameters.scale === undefined ||
parameters.scale < 0.1 ||
parameters.scale > 10.0
) {
parameters.scale = 1.0;
}

if (parameters.fit === undefined) {
parameters.fit = true;
}

if (parameters.rotation === undefined) {
parameters.rotation = 0;
}

if (parameters.rect === undefined) {
parameters.rect = [0, 0, 0, 0];
}
return parameters;
}

onunload() {
console.log("unloading Better PDF plugin...");
}
}