Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
react-fast-scroll-pdf
Advanced tools
A small, super-fast javascript PDF renderer
We needed a way to very quickly render a complete PDF document but without using a lot of canvas elements (iPads etc limit the amount of canvas memory). This uses a single canvas element and uses pdfjs-dist to render each pdf page before converting it to a PNG image. PDF annotations are then placed on top of the image so that links etc still work.
[screenshot)
To get a local copy up and running follow these simple steps.
npm install --save react-fast-scroll-pdf
git clone https://github.com/wearemothership/react-fast-scroll-pdf
We have provided some demos of how this can be used in your project.
git clone https://github.com/wearemothership/react-fast-scroll-pdf
cd react-fast-scroll-pdf
npm install
npm run example
Some usage examples of how this can be used in you project.
import the FastScrollPDF component and pass in the required props
import React, { SyntheticEvent, useState } from "react";
import { FastScrollPDF } from "react-fast-scroll-pdf";
const App = (): JSX.Element => {
const [file, setFile] = useState<Uint8Array>();
const sourceOptions = {
data: file
};
const fileChanged = (ev: SyntheticEvent<HTMLInputElement>) => {
const target = ev.target as HTMLInputElement;
const newFile = target.files?.[0];
if (newFile) {
const fileReader = new FileReader();
fileReader.onload = (e) => {
const { result } = e.target as FileReader;
const arr = new Uint8Array(result as ArrayBuffer);
setFile(arr);
};
fileReader.readAsArrayBuffer(newFile);
}
};
return (
<div className="App">
<input type="file" onChange={fileChanged} />
{ file ? <FastScrollPDF source={sourceOptions} /> : null }
</div>
);
};
export default App;
This is something that you may wish to do if you want to apply your own styles or get access to the individual components to sort layout out in your own way. Here you're going to use the components along with the hook to give you lots of control over how you display the PDF.
Note: For reloading the PDF efficiently you should pass in refs to the PDFDocument component and then use those refs for changeZoom. If you choose not to use the refs, it will all still work but instead of reloading from the currently active page, it will reload from page 1.
import React, { SyntheticEvent, useState } from "react";
import { ZoomButtons, PDFDocument, usePDF } from "react-fast-scroll-pdf";
const App = (): JSX.Element => {
const [file, setFile] = useState<Uint8Array>();
const sourceOptions = {
data: file
};
const scrollContainerRef = useRef();
const viewerRef = useRef();
const {
pages,
changeZoomStart,
changeZoomEnd,
renderCurrentPage
} = usePDF({
source,
scrollContainer: scrollContainerRef.current,
viewer: viewerRef.current
});
// Recommend debouncing this code, e.g. lodash debounce.
const scrollDocument = () => renderCurrentPage();
const fileChanged = (ev: SyntheticEvent<HTMLInputElement>) => {
const target = ev.target as HTMLInputElement;
const newFile = target.files?.[0];
if (newFile) {
const fileReader = new FileReader();
fileReader.onload = (e) => {
const { result } = e.target as FileReader;
const arr = new Uint8Array(result as ArrayBuffer);
setFile(arr);
};
fileReader.readAsArrayBuffer(newFile);
}
};
const zoomChangeStart = useCallback((newZoom: number) => {
// This causes the pages to zoom in, but in low quality.
changeZoomStart(newZoom);
}, [changeZoomStart]);
const zoomChangeEnd = useCallback(() => {
// This tells the renderer to recreate all of the images.
changeZoomEnd();
}, [changeZoomEnd])
// Allows the page to be zoomed to fit to the page width
// This is OPTIONAL
const fitPage = useCallback(() => {
if (viewportWidth && scrollContainerRef.current) {
const initial = viewportWidth / zoom;
const scale = (scrollContainerRef.current.offsetWidth / initial) * 0.95;
doZoom(scale);
changeZoomEnd();
return scale;
}
return undefined;
}, [viewportWidth, doZoom, changeZoomEnd, zoom]);
useEffect(() => {
const oldRef = scrollContainerRef.current;
scrollContainerRef.current?.addEventListener("scroll", scrollDocument);
return () => oldRef?.removeEventListener("scroll", scrollDocument);
}, [scrollDocument]);
return (
<div className="App">
<input type="file" onChange={fileChanged} />
<ZoomButtons zoomChangeStart={zoomChangeStart} zoomChangeEnd={zoomChangeEnd} zoomFit={fitPage} />
<PDFDocument scrollContainerRef={scrollContainerRef} viewerRef={viewerRef} pages={pages} />
</div>
);
};
export default App;
You can import the usePDF hook element into React as below (see Example above to see this running)
import React, { SyntheticEvent, useRef, useState } from 'react';
import { usePDF } from "react-fast-scroll-pdf";
const App = (): JSX.Element => {
const scrollContainerRef = useRef<HTMLDivElement>(null);
const viewerRef = useRef<HTMLDivElement>(null);
const [zoom, setZoom] = useState<number>(1);
const [file, setFile] = useState<Uint8Array>();
const sourceOptions = {
data: file
}
const {
pages,
changeZoomStart,
changeZoomEnd,
renderCurrentPage
} = usePDF({
source: sourceOptions,
scrollContainer: scrollContainerRef.current,
viewer: viewerRef.current
})
const ZOOM_CHANGE: number = 0.1;
// Recommend debouncing this, e.g. lodash debounce.
const scrollDocument = () => renderCurrentPage();
const zoomIn = useCallback(() => {
const newZoom = zoom + ZOOM_CHANGE;
if (newZoom > 0) {
setZoom(newZoom);
changeZoomStart(newStart);
}
}, [changeZoomStart]);
const zoomOut = useCallback(() => {
const newZoom = zoom - ZOOM_CHANGE;
if (newZoom < 2) {
setZoom(newZoom);
changeZoomStart(newZoom);
}
}, [changeZoomStart]);
const zoomEnd = useCallback(() => {
changeZoomEnd();
}, [changeZoomEnd]);
const fileChanged = useCallback((ev: SyntheticEvent<HTMLInputElement>) => {
const target = ev.target as HTMLInputElement;
const file = target.files?.[0]
if (file) {
var fileReader = new FileReader();
fileReader.onload = (e) => {
const { result } = e.target as FileReader;
const arr = new Uint8Array(result as ArrayBuffer);
setFile(arr);
};
fileReader.readAsArrayBuffer(file);
}
}, [])
return (
<div className="App">
<input type="file" onChange={fileChanged} />
<div id="scrollContainer" ref={scrollContainerRef} style={{ overflow: "scroll", height: "800px" }}>
<div id="viewer" ref={viewerRef}>
{pages}
</div>
</div>
<button type="button" onMouseDown={zoomIn} onMouseUp={zoomEnd}>+</button>
<button type="button" onMouseDown={zoomOut} onMouseUp={zoomEnd}>-</button>
</div>
);
}
These two components can be accessed via an import and may be useful if you wish to add additional pages to the page list returned by the usePDF hook.
You can find details of the options available on the source object here.
See the open issues for a list of proposed features (and known issues).
Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are greatly appreciated.
git checkout -b feature/AmazingFeature
)git commit -m 'Add some AmazingFeature'
)git push origin feature/AmazingFeature
)Distributed under the MIT License. https://github.com/wearemothership/react-fast-scroll-pdf/blob/main/LICENSE.md
Copyright (c) 2021 Mothership Software Ltd.
Please let us know if you wish us to add your project to this list.
FAQs
Image-based PDF viewer using pdfjs
We found that react-fast-scroll-pdf demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.