diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/documents/DocUtils.ts | 2 | ||||
-rw-r--r-- | src/client/views/MarqueeAnnotator.tsx | 28 | ||||
-rw-r--r-- | src/client/views/nodes/ImageBox.tsx | 89 | ||||
-rw-r--r-- | src/client/views/nodes/formattedText/FormattedTextBox.tsx | 55 | ||||
-rw-r--r-- | src/client/views/pdf/AnchorMenu.tsx | 2 |
5 files changed, 84 insertions, 92 deletions
diff --git a/src/client/documents/DocUtils.ts b/src/client/documents/DocUtils.ts index 0c9fe0315..327bb1f8a 100644 --- a/src/client/documents/DocUtils.ts +++ b/src/client/documents/DocUtils.ts @@ -37,7 +37,7 @@ import { Docs, DocumentOptions } from './Documents'; const { DFLT_IMAGE_NATIVE_DIM } = require('../views/global/globalCssVariables.module.scss'); // prettier-ignore -const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace('px', '')); +const defaultNativeImageDim = 10000000; //Number(DFLT_IMAGE_NATIVE_DIM.replace('px', '')); export namespace DocUtils { function matchFieldValue(doc: Doc, key: string, valueIn: any): boolean { diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index c7ffce2b4..67321a5cc 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -47,10 +47,10 @@ export class MarqueeAnnotator extends ObservableReactComponent<MarqueeAnnotatorP makeObservable(this); } - @observable private _width: number = 0; - @observable private _height: number = 0; - @computed get top() { return Math.min(this._start.y, this._start.y + this._height); } // prettier-ignore - @computed get left() { return Math.min(this._start.x, this._start.x + this._width);} // prettier-ignore + @observable Width: number = 0; + @observable Height: number = 0; + @computed get top() { return Math.min(this._start.y, this._start.y + this.Height); } // prettier-ignore + @computed get left() { return Math.min(this._start.x, this._start.x + this.Width);} // prettier-ignore static clearAnnotations = action((savedAnnotations: ObservableMap<number, HTMLDivElement[]>) => { AnchorMenu.Instance.Status = 'marquee'; @@ -167,7 +167,7 @@ export class MarqueeAnnotator extends ObservableReactComponent<MarqueeAnnotatorP @action public onInitiateSelection(down: number[]) { - this._width = this._height = 0; + this.Width = this.Height = 0; this._start = this.getTransformedScreenPt(down); document.removeEventListener('pointermove', this.onSelectMove); @@ -241,15 +241,15 @@ export class MarqueeAnnotator extends ObservableReactComponent<MarqueeAnnotatorP @action onMove = (pt: number[]) => { const movLoc = this.getTransformedScreenPt(pt); - this._width = movLoc.x - this._start.x; - this._height = movLoc.y - this._start.y; + this.Width = movLoc.x - this._start.x; + this.Height = movLoc.y - this._start.y; }; @action onSelectMove = (e: PointerEvent) => { const movLoc = this.getTransformedScreenPt([e.clientX, e.clientY]); - this._width = movLoc.x - this._start.x; - this._height = movLoc.y - this._start.y; + this.Width = movLoc.x - this._start.x; + this.Height = movLoc.y - this._start.y; // e.stopPropagation(); // overlay documents are all 'active', yet they can be dragged. if we stop propagation, then they can be marqueed but not dragged. if we don't stop, then they will be marqueed and dragged, but the marquee will be zero width since the doc will move along with the cursor. }; @@ -280,11 +280,11 @@ export class MarqueeAnnotator extends ObservableReactComponent<MarqueeAnnotatorP AnchorMenu.Instance.jumpTo(x, y); } this.props.finishMarquee(this.isEmpty ? x : undefined, this.isEmpty ? y : undefined); - this._width = this._height = 0; + this.Width = this.Height = 0; }; get isEmpty() { - return Math.abs(this._width) <= 10 && Math.abs(this._height) <= 10; + return Math.abs(this.Width) <= 10 && Math.abs(this.Height) <= 10; } render() { @@ -294,9 +294,9 @@ export class MarqueeAnnotator extends ObservableReactComponent<MarqueeAnnotatorP style={{ left: `${this.left}px`, top: `${this.top}px`, - width: `${Math.abs(this._width)}px`, - height: `${Math.abs(this._height)}px`, - border: `${this._width === 0 ? '' : '2px dashed black'}`, + width: `${Math.abs(this.Width)}px`, + height: `${Math.abs(this.Height)}px`, + border: `${this.Width === 0 ? '' : '2px dashed black'}`, }} /> ); diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index ff938df78..a794e213e 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -302,70 +302,20 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { }; createCanvas = async (downX?: number, downY?: number, cb?: (filename: string, x: number | undefined, y: number | undefined) => void) => { - const width = NumCast(this.layoutDoc._width); const canvas = document.createElement('canvas'); - // canvas.width = 640; - // canvas.height = (640 * Doc.NativeHeight(this.layoutDoc)) / (Doc.NativeWidth(this.layoutDoc) || 1); - canvas.width = NumCast(this.layoutDoc._width); - canvas.height = NumCast(this.layoutDoc._height); + const scaling = 1 / (this._props.NativeDimScaling?.() || 1); + const w = AnchorMenu.Instance.marqueeWidth * scaling; + const h = AnchorMenu.Instance.marqueeHeight * scaling; + canvas.width = w; + canvas.height = h; const ctx = canvas.getContext('2d'); // draw image to canvas. scale to target dimensions if (ctx) { - // this._imageRef && ctx.drawImage(this._imageRef, 0, 0, canvas.width, canvas.height); - this._imageRef && ctx.drawImage(this._imageRef, NumCast(this._marqueeref.current?.left), NumCast(this._marqueeref.current?.top), this._width, this._height, 0, 0, 1000, 1000); - //this._imageRef && ctx.drawImage(this._imageRef, 0, 0, 2000, 1000, 0, 0, canvas.width, canvas.height); - // console.log(NumCast(this._marqueeref.current?.left) + 100); + this._imageRef && ctx.drawImage(this._imageRef, NumCast(this._marqueeref.current?.left) * scaling, NumCast(this._marqueeref.current?.top) * scaling, w, h, 0, 0, w, h); } + // canvas.style.zIndex = '2000000'; + // document.body.appendChild(canvas); const blob = await ImageUtility.canvasToBlob(canvas); return ImageBox.selectUrlToBase64(blob); - - // if (this._imageRef) { - // const canv = ImageUtility.getCroppedImg(this._imageRef, this._imageRef.width, this._imageRef.height); - // console.log(this._imageRef.width); - // if (canv) { - // const blob = await ImageUtility.canvasToBlob(canv); - // return ImageBox.selectUrlToBase64(blob); - // } - // } - if (!this._imageRef) { - const b = Docs.Create.LabelDocument({ - x: NumCast(this.layoutDoc.x) + width, - y: NumCast(this.layoutDoc.y, 1), - _width: 150, - _height: 50, - // title: (this.layoutDoc._layout_currentTimecode || 0).toString(), - onClick: FollowLinkScript(), - }); - this._props.addDocument?.(b); - DocUtils.MakeLink(b, this.Document, { link_relationship: 'image snapshot' }); - } else { - // convert to desired file format - // const dataUrl = canvas.toDataURL('image/png'); // can also use 'image/png' - // // if you want to preview the captured image, - // const retitled = StrCast(this.Document.title).replace(/[ -.:]/g, ''); - // const encodedFilename = encodeURIComponent(('snapshot' + retitled + '_' + (this.layoutDoc._layout_currentTimecode || 0).toString()).replace(/[./?=]/g, '_')); - // const filename = basename(encodedFilename); - // ClientUtils.convertDataUri(dataUrl, filename).then((returnedFilename: string) => returnedFilename && (cb ?? this.createSnapshotLink)(returnedFilename, downX, downY)); - } - // convert to desired file format - - // const dataUrl = canvas.toDataURL('image/png'); // can also use 'image/png' - // // if you want to preview the captured image, - // const retitled = StrCast(this.Document.title).replace(/[ -.:]/g, ''); - // const encodedFilename = encodeURIComponent(('snapshot' + retitled + '_' + (this.layoutDoc._layout_currentTimecode || 0).toString()).replace(/[./?=]/g, '_')); - // const filename = basename(encodedFilename); - //ClientUtils.convertDataUri(dataUrl, filename).then((returnedFilename: string) => returnedFilename && (cb ?? this.createSnapshotLink)(returnedFilename, downX, downY)); - // } - // const docViewContent = this.DocumentView?.().ContentDiv!; - // if (docViewContent instanceof HTMLCanvasElement) { - // const canvas = docViewContent; - // const img = document.createElement('img'); // create a Image Element - // img.src = canvas.toDataURL(); // image sourcez - // img.style.width = canvas.style.width; - // img.style.height = canvas.style.height; - // const parEle = newCan.parentElement as HTMLElement; - // parEle.removeChild(newCan); - // parEle.appendChild(img); - // } }; createSnapshotLink = (imagePath: string, downX?: number, downY?: number) => { @@ -390,21 +340,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { setTimeout(() => downX !== undefined && downY !== undefined && DocumentView.getFirstDocumentView(imageSnapshot)?.startDragging(downX, downY, dropActionType.move, true)); }; - /** - * - if (oldDiv instanceof HTMLCanvasElement) { - const canvas = oldDiv; - const img = document.createElement('img'); // create a Image Element - img.src = canvas.toDataURL(); // image sourcez - img.style.width = canvas.style.width; - img.style.height = canvas.style.height; - const newCan = newDiv as HTMLCanvasElement; - const parEle = newCan.parentElement as HTMLElement; - parEle.removeChild(newCan); - parEle.appendChild(img); - } - */ - static selectUrlToBase64 = async (blob: Blob): Promise<string> => { try { return new Promise((resolve, reject) => { @@ -445,10 +380,10 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { try { // const hrefBase64 = await ImageBox.imageUrlToBase64(hrefComplete); const hrefBase64 = await this.createCanvas(); - const response = await gptImageLabel(hrefBase64, 'Tell me what words you see on this image.'); - //const response = await gptImageLabel(hrefBase64, 'Make flashcards out of this text with each question and answer labeled as question and answer. Do not label each flashcard and do not include asterisks: '); + //const response = await gptImageLabel(hrefBase64, 'Tell me what words you see on this image.'); + const response = await gptImageLabel(hrefBase64, 'Make flashcards out of this text with each question and answer labeled as question and answer. Do not label each flashcard and do not include asterisks: '); console.log(response); - // AnchorMenu.Instance.transferToFlashcard(response); + AnchorMenu.Instance.transferToFlashcard(response); // this.Document[DocData].description = response.trim(); // return response; // Return the response } catch (error) { @@ -669,6 +604,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { this._getAnchor = AnchorMenu.Instance?.GetAnchor; AnchorMenu.Instance.gptFlashcards = this.getImageDesc; AnchorMenu.Instance.addToCollection = this._props.DocumentView?.()._props.addDocument; + AnchorMenu.Instance.marqueeWidth = this._marqueeref.current?.Width ?? 0; + AnchorMenu.Instance.marqueeHeight = this._marqueeref.current?.Height ?? 0; this._marqueeref.current?.onTerminateSelection(); this._props.select(false); }; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 3e2befb5f..aee885688 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -65,6 +65,8 @@ import { removeMarkWithAttrs } from './prosemirrorPatches'; import { RichTextMenu, RichTextMenuPlugin } from './RichTextMenu'; import { RichTextRules } from './RichTextRules'; import { schema } from './schema_rts'; +import { URLField } from '../../../../fields/URLField'; +import { gptImageLabel } from '../../../apis/gpt/GPT'; // import * as applyDevTools from 'prosemirror-dev-tools'; export interface FormattedTextBoxProps extends FieldViewProps { @@ -907,7 +909,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB ); const appearance = cm.findByDescription('Appearance...'); const appearanceItems: ContextMenuProps[] = appearance && 'subitems' in appearance ? appearance.subitems : []; - + appearanceItems.push({ + description: 'Find image tags', + event: this.findImageTags, + icon: !this.Document._layout_noSidebar ? 'eye-slash' : 'eye', + }); appearanceItems.push({ description: !this.Document._layout_noSidebar ? 'Hide Sidebar Handle' : 'Show Sidebar Handle', event: () => { @@ -995,6 +1001,53 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB !help && cm.addItem({ description: 'Help...', subitems: helpItems, icon: 'eye' }); }; + findImageTags = () => { + const c = this.ProseRef?.getElementsByTagName('img'); + if (c) { + for (let i of c) { + this.getImageDesc(i.src); + console.log(i); + } + } + // console.log('HI' + this.ProseRef?.getElementsByTagName('img')); + }; + + static imageUrlToBase64 = async (imageUrl: string): Promise<string> => { + try { + const response = await fetch(imageUrl); + const blob = await response.blob(); + + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.readAsDataURL(blob); + reader.onloadend = () => resolve(reader.result as string); + reader.onerror = error => reject(error); + }); + } catch (error) { + console.error('Error:', error); + throw error; + } + }; + + getImageDesc = async (u: string) => { + // if (StrCast(this.dataDoc.description)) return StrCast(this.dataDoc.description); // Return existing description + const { href } = (u as URLField).url; + const hrefParts = href.split('.'); + const hrefComplete = `${hrefParts[0]}_o.${hrefParts[1]}`; + try { + const hrefBase64 = await FormattedTextBox.imageUrlToBase64(hrefComplete); + //const response = await gptImageLabel(hrefBase64, 'Tell me what words you see on this image.'); + const response = await gptImageLabel(hrefBase64, 'Make flashcards out of this text with each question and answer labeled as question and answer. Do not label each flashcard and do not include asterisks: '); + console.log(response); + // AnchorMenu.Instance.transferToFlashcard(response); + // this.Document[DocData].description = response.trim(); + // return response; // Return the response + } catch (error) { + console.log('Error'); + } + // return ''; + }; + animateRes = (resIndex: number, newText: string) => { if (resIndex < newText.length) { const marks = this._editorView?.state.storedMarks ?? []; diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx index 777117f26..6dc41ead2 100644 --- a/src/client/views/pdf/AnchorMenu.tsx +++ b/src/client/views/pdf/AnchorMenu.tsx @@ -72,6 +72,8 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { public ShowTargetTrail: () => void = unimplementedFunction; public IsTargetToggler: () => boolean = returnFalse; public gptFlashcards: () => void = unimplementedFunction; + public marqueeWidth = 0; + public marqueeHeight = 0; public get Active() { return this._left > 0; } |