Skip to content

Commit

Permalink
release: 0.40.14
Browse files Browse the repository at this point in the history
  • Loading branch information
RyotaUshio committed Dec 20, 2024
1 parent 22d47ce commit abe61dc
Show file tree
Hide file tree
Showing 18 changed files with 219 additions and 107 deletions.
4 changes: 0 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@
<img src="https://img.shields.io/badge/dynamic/json?logo=obsidian&color=%238a5cf5&label=downloads&query=%24%5B%22pdf-plus%22%5D.downloads&url=https%3A%2F%2Fraw.githubusercontent.com%2Fobsidianmd%2Fobsidian-releases%2Fmaster%2Fcommunity-plugin-stats.json" alt="Obsidian Downloads">
</p>

> [!warning]
> For those who has a [Catalyst license](https://help.obsidian.md/Licenses+and+payment/Catalyst+license): PDF++ 0.40.13 might be incompatible with Obsidian's latest early-access version ([1.8.0](https://obsidian.md/changelog/2024-12-18-desktop-v1.8.0/)).
> Please do not update Obsidian until PDF++ 0.40.14 is available. [Learn more](https://github.com/RyotaUshio/obsidian-pdf-plus/discussions/311)
> [!note]
> All contribution to this plugin has been made by a single voluntary student (me).
>
Expand Down
2 changes: 1 addition & 1 deletion manifest-beta.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "pdf-plus",
"name": "PDF++",
"version": "0.40.13",
"version": "0.40.14",
"minAppVersion": "1.5.8",
"description": "The most Obsidian-native PDF annotation tool ever.",
"author": "Ryota Ushio",
Expand Down
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "pdf-plus",
"name": "PDF++",
"version": "0.40.13",
"version": "0.40.14",
"minAppVersion": "1.5.8",
"description": "The most Obsidian-native PDF annotation tool ever.",
"author": "Ryota Ushio",
Expand Down
10 changes: 5 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "obsidian-pdf-plus",
"version": "0.40.13",
"version": "0.40.14",
"description": "The most Obsidian-native PDF annotation tool ever.",
"scripts": {
"dev": "node esbuild.config.mjs",
Expand Down
12 changes: 7 additions & 5 deletions src/backlink-visualizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import PDFPlus from 'main';
import { PDFPlusComponent } from 'lib/component';
import { PDFBacklinkCache, PDFBacklinkIndex, PDFPageBacklinkIndex } from 'lib/pdf-backlink-index';
import { PDFPageView, PDFViewerChild, Rect } from 'typings';
import { MultiValuedMap, isCanvas, isEmbed, isHoverPopover, isMouseEventExternal, isNonEmbedLike } from 'utils';
import { MultiValuedMap, getTextLayerInfo, isCanvas, isEmbed, isHoverPopover, isMouseEventExternal, isNonEmbedLike } from 'utils';
import { onBacklinkVisualizerContextMenu } from 'context-menu';
import { BidirectionalMultiValuedMap } from 'utils';
import { MergedRect } from 'lib/highlights/geometry';
Expand Down Expand Up @@ -294,9 +294,10 @@ export class RectangleCache extends PDFPlusComponent {

const textLayer = pageView.textLayer;
if (!textLayer) return null;
if (!textLayer.textDivs.length) return null;
const textLayerInfo = getTextLayerInfo(textLayer);
if (!textLayerInfo.textDivs.length) return null;

const rects = this.lib.highlight.geometry.computeMergedHighlightRects(textLayer, beginIndex, beginOffset, endIndex, endOffset);
const rects = this.lib.highlight.geometry.computeMergedHighlightRects(textLayerInfo, beginIndex, beginOffset, endIndex, endOffset);
return rects;
}
}
Expand Down Expand Up @@ -407,7 +408,8 @@ export class PDFViewerBacklinkVisualizer extends PDFBacklinkVisualizer implement

const textLayer = pageView.textLayer;
if (!textLayer) return;
if (!textLayer.textDivs.length) return;
const { textDivs } = getTextLayerInfo(textLayer);
if (!textDivs.length) return;

const rects = this.rectangleCache.getRectsForSelection(pageNumber, id);
if (!rects) return;
Expand All @@ -417,7 +419,7 @@ export class PDFViewerBacklinkVisualizer extends PDFBacklinkVisualizer implement
rectEl.addClasses(['pdf-plus-backlink', 'pdf-plus-backlink-selection']);

// font-size is used to set the padding of this highlight in em unit
const textDiv = textLayer.textDivs[indices[0]];
const textDiv = textDivs[indices[0]];
rectEl.setCssStyles({
fontSize: textDiv.style.fontSize
});
Expand Down
23 changes: 15 additions & 8 deletions src/lib/copy-link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Editor, EditorRange, MarkdownFileInfo, MarkdownView, Notice, TFile } fr

import { PDFPlusLibSubmodule } from './submodule';
import { PDFPlusTemplateProcessor } from 'template';
import { encodeLinktext, getOffsetInTextLayerNode, getTextLayerNode, paramsToSubpath, parsePDFSubpath, subpathToParams } from 'utils';
import { encodeLinktext, getOffsetInTextLayerNode, getTextLayerInfo, getTextLayerNode, paramsToSubpath, parsePDFSubpath, subpathToParams } from 'utils';
import { Canvas, PDFOutlineTreeNode, PDFViewerChild, Rect } from 'typings';
import { ColorPalette } from 'color-palette';

Expand Down Expand Up @@ -76,9 +76,12 @@ export class copyLinkLib extends PDFPlusLibSubmodule {
page = child.pdfViewer.pdfViewer?.currentPageNumber ?? page;
}

const selectionStr = child.getTextSelectionRangeStr(pageEl);
if (!selectionStr) return null;

const subpath = paramsToSubpath({
page,
selection: child.getTextSelectionRangeStr(pageEl),
selection: selectionStr,
...subpathParams
});

Expand Down Expand Up @@ -283,12 +286,16 @@ export class copyLinkLib extends PDFPlusLibSubmodule {
// TODO: Needs refactor
const result = parsePDFSubpath(subpath);
if (result && 'beginIndex' in result) {
const item = child.getPage(page).textLayer?.textContentItems[result.beginIndex];
if (item) {
const left = item.transform[4];
const top = item.transform[5] + item.height;
if (typeof left === 'number' && typeof top === 'number') {
this.plugin.lastCopiedDestInfo = { file, destArray: [page - 1, 'XYZ', left, top, null] };
const textLayer = child.getPage(page).textLayer;
if (textLayer) {
const { textContentItems } = getTextLayerInfo(textLayer);
const item = textContentItems[result.beginIndex];
if (item) {
const left = item.transform[4];
const top = item.transform[5] + item.height;
if (typeof left === 'number' && typeof top === 'number') {
this.plugin.lastCopiedDestInfo = { file, destArray: [page - 1, 'XYZ', left, top, null] };
}
}
}
}
Expand Down
56 changes: 28 additions & 28 deletions src/lib/highlights/geometry.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { PDFPlusLibSubmodule } from 'lib/submodule';
import { PropRequired } from 'utils';
import { getNodeAndOffsetOfTextPos, PropRequired } from 'utils';
import { TextLayerBuilder, Rect, TextContentItem } from 'typings';


Expand All @@ -12,8 +12,8 @@ export class HighlightGeometryLib extends PDFPlusLibSubmodule {
* Each rectangle is obtained by merging the rectangles of the text content items contained in the selection, when possible (typically when the text selection is within a single line).
* Each rectangle is associated with an array of indices of the text content items contained in the rectangle.
*/
computeMergedHighlightRects(textLayer: TextLayerBuilder, beginIndex: number, beginOffset: number, endIndex: number, endOffset: number): MergedRect[] {
const { textContentItems, textDivs, div } = textLayer;
computeMergedHighlightRects(textLayer: { textDivs: HTMLElement[], textContentItems: TextContentItem[] }, beginIndex: number, beginOffset: number, endIndex: number, endOffset: number): MergedRect[] {
const { textContentItems, textDivs } = textLayer;

const results: MergedRect[] = [];

Expand All @@ -34,7 +34,7 @@ export class HighlightGeometryLib extends PDFPlusLibSubmodule {
if (!item.str) continue;

// the minimum rectangle that contains all the chars of this text content item
const rect = this.computeHighlightRectForItem(div, item, textDiv, index, beginIndex, beginOffset, endIndex, endOffset);
const rect = this.computeHighlightRectForItem(item, textDiv, index, beginIndex, beginOffset, endIndex, endOffset);
if (!rect) continue;

if (!mergedRect) {
Expand All @@ -59,13 +59,13 @@ export class HighlightGeometryLib extends PDFPlusLibSubmodule {
return results;
}

computeHighlightRectForItem(textLayerDiv: HTMLElement, item: TextContentItem, textDiv: HTMLElement, index: number, beginIndex: number, beginOffset: number, endIndex: number, endOffset: number): Rect | null {
computeHighlightRectForItem(item: TextContentItem, textDiv: HTMLElement, index: number, beginIndex: number, beginOffset: number, endIndex: number, endOffset: number): Rect | null {
// If the item has the `chars` property filled, use it to get the bounding rectangle of each character in the item.
if (item.chars && item.chars.length >= item.str.length) {
return this.computeHighlightRectForItemFromChars(item as PropRequired<TextContentItem, 'chars'>, index, beginIndex, beginOffset, endIndex, endOffset);
}
// Otherwise, use the text layer divs to get the bounding rectangle of the text selection.
return this.computeHighlightRectForItemFromTextLayer(textLayerDiv, item, textDiv, index, beginIndex, beginOffset, endIndex, endOffset);
return this.computeHighlightRectForItemFromTextLayer(item, textDiv, index, beginIndex, beginOffset, endIndex, endOffset);
}

computeHighlightRectForItemFromChars(item: PropRequired<TextContentItem, 'chars'>, index: number, beginIndex: number, beginOffset: number, endIndex: number, endOffset: number): Rect | null {
Expand All @@ -92,40 +92,40 @@ export class HighlightGeometryLib extends PDFPlusLibSubmodule {
];
}

// Inspired by PDFViewerChild.prototype.hightlightText from Obsidian's app.js
computeHighlightRectForItemFromTextLayer(textLayerDiv: HTMLElement, item: TextContentItem, textDiv: HTMLElement, index: number, beginIndex: number, beginOffset: number, endIndex: number, endOffset: number): Rect | null {
const offsetFrom = index === beginIndex ? beginOffset : 0;
// `endOffset` is computed from the `endOffset` property (https://developer.mozilla.org/en-US/docs/Web/API/Range/endOffset)
// of the `Range` contained in the selection, which is the number of characters from the start of the `Range` to its end.
// Therefore, `endOffset` is 1 greater than the index of the last character in the selection.
const offsetTo = index === endIndex ? endOffset : undefined;

computeHighlightRectForItemFromTextLayer(item: TextContentItem, textDiv: HTMLElement, index: number, beginIndex: number, beginOffset: number, endIndex: number, endOffset: number): Rect | null {
// the bounding box of the whole text content item
const x1 = item.transform[4];
const y1 = item.transform[5];
const x2 = item.transform[4] + item.width;
const y2 = item.transform[5] + item.height;

const textDivCopied = textDiv.cloneNode() as HTMLElement;
textLayerDiv.appendChild(textDivCopied);

const textBefore = item.str.substring(0, offsetFrom);
textDivCopied.appendText(textBefore);
const range = textDiv.doc.createRange();

const text = item.str.substring(offsetFrom, offsetTo);
const boundingEl = textDivCopied.createSpan();
boundingEl.appendText(text);
if (index === beginIndex) {
const posFrom = getNodeAndOffsetOfTextPos(textDiv, beginOffset);
if (posFrom) {
range.setStart(posFrom.node, posFrom.offset);
} else {
range.setStartBefore(textDiv);
}
} else {
range.setStartBefore(textDiv);
}

if (offsetTo !== undefined) {
const textAfter = item.str.substring(offsetTo);
textDivCopied.appendText(textAfter);
if (index === endIndex) {
const posTo = getNodeAndOffsetOfTextPos(textDiv, endOffset);
if (posTo) {
range.setEnd(posTo.node, posTo.offset);
} else {
range.setEndAfter(textDiv);
}
} else {
range.setEndAfter(textDiv);
}

const rect = boundingEl.getBoundingClientRect();
const rect = range.getBoundingClientRect();
const parentRect = textDiv.getBoundingClientRect();

textDivCopied.remove();

return [
x1 + (rect.left - parentRect.left) / parentRect.width * item.width,
y1 + (rect.bottom - parentRect.bottom) / parentRect.height * item.height,
Expand Down
5 changes: 3 additions & 2 deletions src/lib/highlights/write-file/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Notice, TFile } from 'obsidian';
import PDFPlus from 'main';
import { PdfLibIO } from './pdf-lib';
import { PDFPlusLibSubmodule } from 'lib/submodule';
import { parsePDFSubpath } from 'utils';
import { getTextLayerInfo, parsePDFSubpath } from 'utils';
import { DestArray, PDFViewerChild, Rect } from 'typings';


Expand Down Expand Up @@ -63,7 +63,8 @@ export class AnnotationWriteFileLib extends PDFPlusLibSubmodule {
if (1 <= pageNumber && pageNumber <= child.pdfViewer.pagesCount) {
const pageView = child.getPage(pageNumber);
if (pageView?.textLayer && pageView.div.dataset.loaded) {
const results = this.lib.highlight.geometry.computeMergedHighlightRects(pageView.textLayer, beginIndex, beginOffset, endIndex, endOffset);
const textLayerInfo = getTextLayerInfo(pageView.textLayer);
const results = this.lib.highlight.geometry.computeMergedHighlightRects(textLayerInfo, beginIndex, beginOffset, endIndex, endOffset);
const rects = results.map(({ rect }) => rect);
let annotationID;
try {
Expand Down
5 changes: 4 additions & 1 deletion src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,10 @@ export class PDFPlusLib {
}

getTextContentItems() {
return this.getPage(true)?.textLayer?.textContentItems;
const textLayer = this.getPage(true)?.textLayer;
if (textLayer) {
return utils.getTextLayerInfo(textLayer).textContentItems;
}
}

getPDFDocument(activeOnly: boolean = false) {
Expand Down
Loading

0 comments on commit abe61dc

Please sign in to comment.