diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 9638f3a..3bf11df 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -27,14 +27,15 @@ jobs: - name: Build Docker image run: docker build -t vue-pdf-annotate . - - name: Deploy Docker container to GitHub Pages + - name: Run Docker container run: | - docker run -d -p 5173:5173 vuetify-project - docker cp $(docker ps -ql):/app/dist ./dist + docker run -d -p 5000:80 vue-pdf-annotate + sleep 10 # wait for the container to start + docker cp $(docker ps -ql):/usr/share/nginx/html ./dist docker stop $(docker ps -ql) - name: Deploy to GitHub Pages uses: peaceiris/actions-gh-pages@v3 with: - github_token: ${{ secrets.GH_TOKEN }} + github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./dist diff --git a/Dockerfile b/Dockerfile index ff0cbf8..64a4913 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ -# Use a Node.js base image -FROM node:18 +# Stage 1: Build the application +FROM node:18 as build # Set the working directory WORKDIR /app @@ -16,8 +16,17 @@ COPY . . # Build the application RUN npm run build -# Expose the port the app runs on -EXPOSE 5173 +# Stage 2: Serve the application with Nginx +FROM nginx:alpine -# Command to run the app -CMD ["npm", "run", "dev"] \ No newline at end of file +# Copy the build output to the Nginx html directory +COPY --from=build /app/dist /usr/share/nginx/html + +# Copy the Nginx configuration file +COPY nginx.conf /etc/nginx/nginx.conf + +# Expose the port +EXPOSE 80 + +# Start Nginx +CMD ["nginx", "-g", "daemon off;"] diff --git a/README.md b/README.md index ffbd635..f219d37 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,12 @@ Welcome to the PDF Annotator project! This project is built using Vue.js, PDF.js As someone who found the documentation of PDF.js insufficient and faced significant challenges in programmatically adding annotations to PDF documents using a dedicated backend and database, I decided to create this project. Working with the annotation layer of PDF.js was very challenging and almost impossible to accomplish this task. Therefore, I created this small project to showcase the easiest production-level solution ([pdfAnnotate](https://github.com/highkite/pdfAnnotate)) I found for programmatic annotation and demonstrate how you can easily integrate the prebuilt PDF.js viewer into your Vue project. +

+ +

+ ### Table of Contents 1. [Getting Started](#getting-started) @@ -66,65 +72,31 @@ The `pdfViewer.vue` component integrates the default/prebuilt PDF.js viewer usin Here's how simple integration with iframe works: -1. **Vue Template Structure** +1. **Integration of PDFjs in Vue component via `iframe`** ```html ``` -2. **Vue Script Setup** - ```javascript - - ``` +2. **Break Down the Key Aspects** + +- **Iframe Source**: set the iframe's `src` to the path of the PDF.js viewer HTML file. +- **Iframe ID**: assigned the iframe an ID of `pdfViewer` for easy interaction with its content. +- **PDF Loading**: `loadPDF` and `iframeLoader` functions handle fetching and preparing the PDF, which is then loaded into the iframe. +- **Below are the major API calls to pdfjs and their functions**: + - **`PDFViewerApplication`**: This is the main class in viewer.mjs that we interact with, controlling rendering and sub-functionalities. + - `PDFViewerApplication.open(file)`: Used to load the PDF. Pass a Uint8Array instead of a URL. + - Ensure to decode base64 encoded data before passing it -- not all browsers support atob or data URI schemes. + - **`value.contentWindow.PDFViewerApplication`**: Accesses the DOM content. + - **`PDFViewerApplication.pdfDocument`**: Initializes interaction with the DOM content. + - **`PDFViewerApplication.pdfDocument.getData()`**: Retrieves data from the DOM for operations like client-side annotation and rendering. + - **`PDFViewerApplication.initialized`**: Checks if the viewer is initialized and ready for rendering. + - **`PDFViewerApplication.eventBus`**: Enables the event bus of pdfjs. + - **`PDFViewerApplication.eventBus.on("pagechanging")`**: Listens for page changes in the PDF -The PDF.js viewer is seamlessly integrated into the Vue component using an `iframe`, making it easy to load and display PDF documents. ## Annotating PDFs with pdfAnnotate @@ -138,11 +110,41 @@ Here's how you can use it: The `pdfAnnotate` library supports several types of annotations, including: - Highlight +

+ +

- Squiggly +

+ +

- Underline +

+ +

- Strikeout +

+ +

- Square +

+ +

- Oval +

+ +

- and more ### Parameters Required @@ -160,114 +162,4 @@ for details and the rest of the documentation, I urge you to read their entire d * Note: one thing you need to be cautious is that pdfjs origin for a "rect" is top left, and pdfAnnotate origin is buttom left, so you need a simple conversion of "y" coordinates to create the list of your annotations. -### Script Setup - -```javascript - -``` - -By integrating `pdfAnnotate`, you can easily add programmatic annotations to your PDF documents. This library supports various annotation types, making it flexible and powerful for different use cases. - ---- - - - Thank you for using the PDF Annotator project! We hope this guide helps you get the most out of your PDF viewing and annotation capabilities. Happy coding! \ No newline at end of file diff --git a/index.html b/index.html index c157160..f284bc9 100644 --- a/index.html +++ b/index.html @@ -1,18 +1,3 @@ - - - @@ -25,11 +10,11 @@ integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w==" crossorigin="anonymous" /> - Vue PDFjs Annotation + Vue PDFjs Annotation
- \ No newline at end of file + diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..14675c5 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,36 @@ +user nginx; +worker_processes auto; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + server { + listen 80; + + server_name localhost; + + location / { + root /usr/share/nginx/html; + try_files $uri $uri/ /index.html; + } + + location ~* \.mjs$ { + add_header Content-Type application/javascript; + } + + # Enable CORS headers + location /pdfjs-4.2.67-dist/ { + add_header Access-Control-Allow-Origin *; + add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS'; + add_header Access-Control-Allow-Headers 'Origin, Content-Type, Accept'; + } + + error_page 404 /index.html; + } +} diff --git a/public/compressed.tracemonkey-pldi-09.pdf b/public/compressed.tracemonkey-pldi-09.pdf new file mode 100644 index 0000000..6557018 Binary files /dev/null and b/public/compressed.tracemonkey-pldi-09.pdf differ diff --git a/public/pdfjs-4.2.67-dist/web/test.html b/public/pdfjs-4.2.67-dist/web/test.html deleted file mode 100644 index 2195c82..0000000 --- a/public/pdfjs-4.2.67-dist/web/test.html +++ /dev/null @@ -1,276 +0,0 @@ - - - - - - - - - - - Coordinates:[] - - Annotation Content: - Annotation Author:
- - - - - - - - - - - - - -
-
-
-
- Status: - # Annotations -
- - - diff --git a/public/pdfjs-4.2.67-dist/web/viewer.mjs b/public/pdfjs-4.2.67-dist/web/viewer.mjs index 4b55303..acf2526 100644 --- a/public/pdfjs-4.2.67-dist/web/viewer.mjs +++ b/public/pdfjs-4.2.67-dist/web/viewer.mjs @@ -4624,7 +4624,7 @@ const defaultOptions = { }; { defaultOptions.defaultUrl = { - value: "", + value: "./pdfjs-4.2.67-dist/web/compressed.tracemonkey-pldi-09.pdf", kind: OptionKind.VIEWER }; defaultOptions.sandboxBundleSrc = { diff --git a/src/assets/highlight.png b/src/assets/highlight.png new file mode 100644 index 0000000..8c2f63d Binary files /dev/null and b/src/assets/highlight.png differ diff --git a/src/assets/higlight2.png b/src/assets/higlight2.png new file mode 100644 index 0000000..1c74a4b Binary files /dev/null and b/src/assets/higlight2.png differ diff --git a/src/assets/oval.png b/src/assets/oval.png new file mode 100644 index 0000000..a1233cd Binary files /dev/null and b/src/assets/oval.png differ diff --git a/src/assets/square.png b/src/assets/square.png new file mode 100644 index 0000000..84f0b1f Binary files /dev/null and b/src/assets/square.png differ diff --git a/src/assets/squiggly.png b/src/assets/squiggly.png new file mode 100644 index 0000000..35f9d54 Binary files /dev/null and b/src/assets/squiggly.png differ diff --git a/src/assets/strike.png b/src/assets/strike.png new file mode 100644 index 0000000..ff85544 Binary files /dev/null and b/src/assets/strike.png differ diff --git a/src/assets/underline.png b/src/assets/underline.png new file mode 100644 index 0000000..ced3e9a Binary files /dev/null and b/src/assets/underline.png differ diff --git a/src/components/pdfViewer.vue b/src/components/pdfViewer.vue index 4b5618a..3fe0246 100644 --- a/src/components/pdfViewer.vue +++ b/src/components/pdfViewer.vue @@ -11,10 +11,10 @@ import { storeToRefs } from 'pinia'; import { AnnotationFactory } from 'annotpdf'; const pdfViewerIframe = ref(null); -const viewerUrl = ref('/pdfjs-annotation/pdfjs-4.2.67-dist/web/viewer.html'); +//const viewerUrl = ref('./pdfjs-4.2.67-dist/web/viewer.html'); const pdfStore = piniaStore(); -const { pdfUrl } = storeToRefs(pdfStore); +const { pdfUrl, viewerUrl } = storeToRefs(pdfStore); const pdfPageDimensions = ref([]); // Call the function to load the PDF when the component is mounted diff --git a/src/stores/piniaStore.js b/src/stores/piniaStore.js index ced4095..f16583b 100644 --- a/src/stores/piniaStore.js +++ b/src/stores/piniaStore.js @@ -3,6 +3,7 @@ import { defineStore } from 'pinia'; export const piniaStore = defineStore('pdfStore', { state: () => ({ + viewerUrl: '/pdfjs-annotation/pdfjs-4.2.67-dist/web/viewer.html', pdfUrl: '/pdfjs-annotation/pdfjs-4.2.67-dist/web/compressed.tracemonkey-pldi-09.pdf', isHightlightAnnotationActive: false, }), diff --git a/src/style.css b/src/style.css deleted file mode 100644 index bb131d6..0000000 --- a/src/style.css +++ /dev/null @@ -1,79 +0,0 @@ -:root { - font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; - line-height: 1.5; - font-weight: 400; - - color-scheme: light dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; - - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -a { - font-weight: 500; - color: #646cff; - text-decoration: inherit; -} -a:hover { - color: #535bf2; -} - -body { - margin: 0; - display: flex; - place-items: center; - min-width: 320px; - min-height: 100vh; -} - -h1 { - font-size: 3.2em; - line-height: 1.1; -} - -button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - background-color: #1a1a1a; - cursor: pointer; - transition: border-color 0.25s; -} -button:hover { - border-color: #646cff; -} -button:focus, -button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; -} - -.card { - padding: 2em; -} - -#app { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - text-align: center; -} - -@media (prefers-color-scheme: light) { - :root { - color: #213547; - background-color: #ffffff; - } - a:hover { - color: #747bff; - } - button { - background-color: #f9f9f9; - } -} diff --git a/vite.config.js b/vite.config.js index bfeba6a..dc4245e 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,5 +1,5 @@ import { defineConfig } from 'vite' -import { fileURLToPath, URL } from "node:url"; +import { fileURLToPath, URL } from 'node:url' import vue from '@vitejs/plugin-vue' import vuetify from 'vite-plugin-vuetify' import svgLoader from 'vite-svg-loader' @@ -10,27 +10,27 @@ export default defineConfig({ vuetify({ autoImport: true, }), - svgLoader() + svgLoader(), ], - define: { "process.env": {} }, + define: { 'process.env': {} }, resolve: { - alias: { - "@": fileURLToPath(new URL("./src", import.meta.url)), - }, - extensions: [".js", ".json", ".jsx", ".mjs", ".ts", ".tsx", ".vue"], + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)), + }, + extensions: ['.js', '.json', '.jsx', '.mjs', '.ts', '.tsx', '.vue'], }, - base: "/pdfjs-annotation/", + base: '/pdfjs-annotation/', server: { host: '0.0.0.0', - port: 5173 + port: 5173, }, optimizeDeps: { esbuildOptions: { - target: 'esnext' - } + target: 'esnext', + }, }, build: { - outDir: 'dist', - target: 'esnext' + outDir: 'dist', + target: 'esnext', }, })