mirror of
				https://github.com/Frooodle/Stirling-PDF.git
				synced 2025-10-25 11:17:28 +02:00 
			
		
		
		
	sign changes min size, lite docker, merge fix #172
This commit is contained in:
		
							parent
							
								
									ecba6461df
								
							
						
					
					
						commit
						04032c0dfe
					
				
							
								
								
									
										71
									
								
								.github/workflows/push-docker.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										71
									
								
								.github/workflows/push-docker.yml
									
									
									
									
										vendored
									
									
								
							| @ -8,8 +8,14 @@ on: | |||||||
|       - main |       - main | ||||||
| jobs: | jobs: | ||||||
|   push: |   push: | ||||||
| 
 |  | ||||||
|     runs-on: ubuntu-latest |     runs-on: ubuntu-latest | ||||||
|  |     strategy: | ||||||
|  |       matrix: | ||||||
|  |         config: [ | ||||||
|  |           { dockerfile: "./Dockerfile", tagSuffix: "" }, | ||||||
|  |           { dockerfile: "./Dockerfile-ultra-lite", tagSuffix: "-ultra-lite" }, | ||||||
|  |           { dockerfile: "./Dockerfile-lite", tagSuffix: "-lite" } | ||||||
|  |         ] | ||||||
|     steps: |     steps: | ||||||
| 
 | 
 | ||||||
|     - uses: actions/checkout@v3.5.2 |     - uses: actions/checkout@v3.5.2 | ||||||
| @ -46,17 +52,10 @@ jobs: | |||||||
|         username: ${{ github.actor }} |         username: ${{ github.actor }} | ||||||
|         password: ${{ github.token }} |         password: ${{ github.token }} | ||||||
| 
 | 
 | ||||||
|     - name: Generate tags |     - name: Convert repository owner to lowercase | ||||||
|       id: meta |       id: repoowner | ||||||
|       uses: docker/metadata-action@v4.4.0 |       run: echo "::set-output name=lowercase::$(echo ${{ github.repository_owner }} | awk '{print tolower($0)}')" | ||||||
|       with: |        | ||||||
|         images: | |  | ||||||
|           ${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf |  | ||||||
|           ghcr.io/${{ github.repository_owner }}/s-pdf |  | ||||||
|         tags: | |  | ||||||
|           type=raw,value=${{ steps.versionNumber.outputs.versionNumber }},enable=${{ github.ref == 'refs/heads/master' }} |  | ||||||
|           type=raw,value=latest,enable=${{ github.ref == 'refs/heads/master' }} |  | ||||||
|           type=raw,value=alpha,enable=${{ github.ref == 'refs/heads/main' }} |  | ||||||
| 
 | 
 | ||||||
|     - name: Set up QEMU |     - name: Set up QEMU | ||||||
|       uses: docker/setup-qemu-action@v2.1.0 |       uses: docker/setup-qemu-action@v2.1.0 | ||||||
| @ -64,44 +63,28 @@ jobs: | |||||||
|     - name: Set up Docker Buildx |     - name: Set up Docker Buildx | ||||||
|       uses: docker/setup-buildx-action@v2.5.0 |       uses: docker/setup-buildx-action@v2.5.0 | ||||||
| 
 | 
 | ||||||
|     - name: Build and push main Dockerfile | 
 | ||||||
|  |     - name: Generate tags | ||||||
|  |       id: meta | ||||||
|  |       uses: docker/metadata-action@v4.4.0 | ||||||
|  |       with: | ||||||
|  |         images: | | ||||||
|  |           ${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf | ||||||
|  |           ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf | ||||||
|  |         tags: | | ||||||
|  |           type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}${{ matrix.config.tagSuffix }},enable=${{ github.ref == 'refs/heads/master' }} | ||||||
|  |           type=raw,value=latest${{ matrix.config.tagSuffix }},enable=${{ github.ref == 'refs/heads/master' }} | ||||||
|  |           type=raw,value=alpha,enable=${{ github.ref == 'refs/heads/main' }} | ||||||
|  |      | ||||||
|  |     - name: Build and push Dockerfile | ||||||
|       uses: docker/build-push-action@v4.0.0 |       uses: docker/build-push-action@v4.0.0 | ||||||
|       with: |       with: | ||||||
|         context: . |         context: . | ||||||
|         dockerfile: ./Dockerfile |         dockerfile: ${{ matrix.config.dockerfile }} | ||||||
|         push: true |         push: true | ||||||
|         cache-from: type=gha |         cache-from: type=gha | ||||||
|         cache-to: type=gha,mode=max |         cache-to: type=gha,mode=max | ||||||
|         tags: ${{ steps.meta.outputs.tags }} |         tags: ${{ steps.meta.outputs.tags }} | ||||||
|         labels: ${{ steps.meta.outputs.labels }} |         labels: ${{ steps.meta.outputs.labels }} | ||||||
|         platforms: linux/amd64,linux/arm64/v8 |         platforms: linux/amd64,linux/arm64/v8 | ||||||
| 
 |      | ||||||
|     - name: Generate tags |  | ||||||
|       id: meta2 |  | ||||||
|       uses: docker/metadata-action@v4.4.0 |  | ||||||
|       with: |  | ||||||
|         images: | |  | ||||||
|           ${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf |  | ||||||
|           ghcr.io/${{ github.repository_owner }}/s-pdf |  | ||||||
|         tags: | |  | ||||||
|           type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-ultra-light,enable=${{ github.ref == 'refs/heads/master' }} |  | ||||||
|           type=raw,value=latest-ultra-light,enable=${{ github.ref == 'refs/heads/master' }} |  | ||||||
|           type=raw,value=alpha-ultra-light,enable=${{ github.ref == 'refs/heads/main' }} |  | ||||||
|            |  | ||||||
|     - name: Convert repository owner to lowercase |  | ||||||
|       id: repoowner |  | ||||||
|       run: echo "::set-output name=lowercase::$(echo ${{ github.repository_owner }} | awk '{print tolower($0)}')" |  | ||||||
| 
 |  | ||||||
|     - name: Build and push Dockerfile-ultralite |  | ||||||
|       uses: docker/build-push-action@v4.0.0 |  | ||||||
|       with: |  | ||||||
|         context: . |  | ||||||
|         file: ./Dockerfile-ultralite |  | ||||||
|         push: true |  | ||||||
|         cache-from: type=gha |  | ||||||
|         cache-to: type=gha,mode=max |  | ||||||
|         tags: ${{ steps.meta2.outputs.tags }} |  | ||||||
|         labels: ${{ steps.meta2.outputs.labels }} |  | ||||||
|         platforms: linux/amd64,linux/arm64/v8 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
							
								
								
									
										23
									
								
								Dockerfile-lite
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								Dockerfile-lite
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | |||||||
|  | # Build jbig2enc in a separate stage | ||||||
|  | FROM bellsoft/liberica-openjdk-debian:17 | ||||||
|  | RUN apt-get update && \ | ||||||
|  |     apt-get install -y --no-install-recommends \ | ||||||
|  |         libreoffice-core-nogui \ | ||||||
|  |         libreoffice-common \ | ||||||
|  |         libreoffice-writer-nogui \ | ||||||
|  |         libreoffice-calc-nogui \ | ||||||
|  |         libreoffice-impress-nogui \ | ||||||
|  |         unoconv && \ | ||||||
|  |     rm -rf /var/lib/apt/lists/* | ||||||
|  | 
 | ||||||
|  | # Copy the application JAR file | ||||||
|  | COPY build/libs/*.jar app.jar | ||||||
|  | 
 | ||||||
|  | # Expose the application port | ||||||
|  | EXPOSE 8080 | ||||||
|  | 
 | ||||||
|  | # Set environment variables | ||||||
|  | ENV GROUPS_TO_REMOVE=Python,OpenCV,OCRmyPDF | ||||||
|  | 
 | ||||||
|  | # Run the application | ||||||
|  | CMD ["java", "-jar", "/app.jar"] | ||||||
| @ -1,5 +1,5 @@ | |||||||
| # Build jbig2enc in a separate stage | # Build jbig2enc in a separate stage | ||||||
| FROM openjdk:17-jdk-slim | FROM bellsoft/liberica-openjdk-alpine:17 | ||||||
| 
 | 
 | ||||||
| # Copy the application JAR file | # Copy the application JAR file | ||||||
| COPY build/libs/*.jar app.jar | COPY build/libs/*.jar app.jar | ||||||
| @ -1,5 +1,5 @@ | |||||||
| # Main stage | # Main stage | ||||||
| FROM openjdk:17-jdk-slim AS base | FROM bellsoft/liberica-openjdk-debian:17 AS base | ||||||
| RUN apt-get update && \ | RUN apt-get update && \ | ||||||
|     apt-get install -y --no-install-recommends \ |     apt-get install -y --no-install-recommends \ | ||||||
|         libreoffice-core-nogui \ |         libreoffice-core-nogui \ | ||||||
|  | |||||||
| @ -14,13 +14,21 @@ def is_blank_image(image_path, threshold=10, white_percent=99, white_value=255, | |||||||
|     blurred_image = cv2.GaussianBlur(image, (blur_size, blur_size), 0) |     blurred_image = cv2.GaussianBlur(image, (blur_size, blur_size), 0) | ||||||
| 
 | 
 | ||||||
|     _, thresholded_image = cv2.threshold(blurred_image, white_value - threshold, white_value, cv2.THRESH_BINARY) |     _, thresholded_image = cv2.threshold(blurred_image, white_value - threshold, white_value, cv2.THRESH_BINARY) | ||||||
|      | 
 | ||||||
|     # Calculate the percentage of white pixels in the thresholded image |     # Calculate the percentage of white pixels in the thresholded image | ||||||
|     white_pixels = np.sum(thresholded_image == white_value) |     white_pixels = 0 | ||||||
|     total_pixels = thresholded_image.size |     total_pixels = thresholded_image.size | ||||||
|     white_pixel_percentage = (white_pixels / total_pixels) * 100 |     for i in range(0, thresholded_image.shape[0], 2): | ||||||
|  |         for j in range(0, thresholded_image.shape[1], 2): | ||||||
|  |             if thresholded_image[i, j] == white_value: | ||||||
|  |                 white_pixels += 1 | ||||||
|  |             white_pixel_percentage = (white_pixels / (i * thresholded_image.shape[1] + j + 1)) * 100 | ||||||
|  |             if white_pixel_percentage < white_percent: | ||||||
|  |                 return False | ||||||
|  | 
 | ||||||
|     print(f"Page has white pixel percent of {white_pixel_percentage}") |     print(f"Page has white pixel percent of {white_pixel_percentage}") | ||||||
|     return white_pixel_percentage > white_percent |     return True | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| if __name__ == "__main__": | if __name__ == "__main__": | ||||||
|  | |||||||
| @ -20,12 +20,14 @@ public class EndpointConfiguration { | |||||||
|     } |     } | ||||||
|      |      | ||||||
|     public void enableEndpoint(String endpoint) { |     public void enableEndpoint(String endpoint) { | ||||||
|         endpointStatuses.put(endpoint, true); |     	endpointStatuses.put(endpoint, true); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public void disableEndpoint(String endpoint) { |     public void disableEndpoint(String endpoint) { | ||||||
|         logger.info("Disabling {}", endpoint); |     	if(!endpointStatuses.containsKey(endpoint) || endpointStatuses.get(endpoint) !=  false) { | ||||||
|         endpointStatuses.put(endpoint, false); | 	        logger.info("Disabling {}", endpoint); | ||||||
|  | 	        endpointStatuses.put(endpoint, false); | ||||||
|  |     	} | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public boolean isEndpointEnabled(String endpoint) { |     public boolean isEndpointEnabled(String endpoint) { | ||||||
|  | |||||||
| @ -74,7 +74,9 @@ public class OtherWebController { | |||||||
|     @Hidden |     @Hidden | ||||||
|     public ModelAndView ocrPdfPage() { |     public ModelAndView ocrPdfPage() { | ||||||
|         ModelAndView modelAndView = new ModelAndView("other/ocr-pdf"); |         ModelAndView modelAndView = new ModelAndView("other/ocr-pdf"); | ||||||
|         modelAndView.addObject("languages", getAvailableTesseractLanguages()); |         List<String> languages = getAvailableTesseractLanguages(); | ||||||
|  |         Collections.sort(languages); | ||||||
|  |         modelAndView.addObject("languages", languages); | ||||||
|         modelAndView.addObject("currentPage", "ocr-pdf"); |         modelAndView.addObject("currentPage", "ocr-pdf"); | ||||||
|         return modelAndView; |         return modelAndView; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -19,12 +19,13 @@ $(document).ready(function() { | |||||||
| 		$('#submitBtn').text('Processing...'); | 		$('#submitBtn').text('Processing...'); | ||||||
| 
 | 
 | ||||||
| 		try { | 		try { | ||||||
| 			if (override === 'multi' || files.length > 1 && override !== 'single') { | 			if(remoteCall === true) { | ||||||
| 				await submitMultiPdfForm(url, files); | 				if (override === 'multi' || (!multiple && files.length > 1) && override !== 'single' ) { | ||||||
| 			} else { | 					await submitMultiPdfForm(url, files); | ||||||
| 				await handleSingleDownload(url, formData); | 				} else { | ||||||
|  | 					await handleSingleDownload(url, formData); | ||||||
|  | 				} | ||||||
| 			} | 			} | ||||||
| 
 |  | ||||||
| 			$('#submitBtn').text(originalButtonText); | 			$('#submitBtn').text(originalButtonText); | ||||||
| 		} catch (error) { | 		} catch (error) { | ||||||
| 			handleDownloadError(error); | 			handleDownloadError(error); | ||||||
|  | |||||||
| @ -25,33 +25,50 @@ const DraggableUtils = { | |||||||
|             }, |             }, | ||||||
|         }) |         }) | ||||||
|         .resizable({ |         .resizable({ | ||||||
|             edges: { left: true, right: true, bottom: true, top: true }, |     edges: { left: true, right: true, bottom: true, top: true }, | ||||||
|             listeners: { |     listeners: { | ||||||
|                 move: (event) => { |         move: (event) => { | ||||||
|                     var target = event.target |             var target = event.target | ||||||
|                     var x = (parseFloat(target.getAttribute('data-x')) || 0) |             var x = (parseFloat(target.getAttribute('data-x')) || 0) | ||||||
|                     var y = (parseFloat(target.getAttribute('data-y')) || 0) |             var y = (parseFloat(target.getAttribute('data-y')) || 0) | ||||||
| 
 | 
 | ||||||
|                     // update the element's style
 |             // check if control key is pressed
 | ||||||
|                     target.style.width = event.rect.width + 'px' |             if (event.ctrlKey) { | ||||||
|                     target.style.height = event.rect.height + 'px' |                 const aspectRatio = target.offsetWidth / target.offsetHeight; | ||||||
|  |                 // preserve aspect ratio
 | ||||||
|  |                 let width = event.rect.width; | ||||||
|  |                 let height = event.rect.height; | ||||||
| 
 | 
 | ||||||
|                     // translate when resizing from top or left edges
 |                 if (Math.abs(event.deltaRect.width) >= Math.abs(event.deltaRect.height)) { | ||||||
|                     x += event.deltaRect.left |                     height = width / aspectRatio; | ||||||
|                     y += event.deltaRect.top |                 } else { | ||||||
|  |                     width = height * aspectRatio; | ||||||
|  |                 } | ||||||
| 
 | 
 | ||||||
|                     target.style.transform = 'translate(' + x + 'px,' + y + 'px)' |                 event.rect.width = width; | ||||||
|  |                 event.rect.height = height; | ||||||
|  |             } | ||||||
| 
 | 
 | ||||||
|                     target.setAttribute('data-x', x) |             target.style.width = event.rect.width + 'px' | ||||||
|                     target.setAttribute('data-y', y) |             target.style.height = event.rect.height + 'px' | ||||||
|                     target.textContent = Math.round(event.rect.width) + '\u00D7' + Math.round(event.rect.height) | 
 | ||||||
|  |             // translate when resizing from top or left edges
 | ||||||
|  |             x += event.deltaRect.left | ||||||
|  |             y += event.deltaRect.top | ||||||
|  | 
 | ||||||
|  |             target.style.transform = 'translate(' + x + 'px,' + y + 'px)' | ||||||
|  | 
 | ||||||
|  |             target.setAttribute('data-x', x) | ||||||
|  |             target.setAttribute('data-y', y) | ||||||
|  |             target.textContent = Math.round(event.rect.width) + '\u00D7' + Math.round(event.rect.height) | ||||||
|  | 
 | ||||||
|  |             this.onInteraction(target); | ||||||
|  |         }, | ||||||
|  |     }, | ||||||
| 
 | 
 | ||||||
|                     this.onInteraction(target); |  | ||||||
|                 }, |  | ||||||
|             }, |  | ||||||
|             modifiers: [ |             modifiers: [ | ||||||
|                 interact.modifiers.restrictSize({ |                 interact.modifiers.restrictSize({ | ||||||
|                     min: { width: 50, height: 50 }, |                     min: { width: 5, height: 5 }, | ||||||
|                 }), |                 }), | ||||||
|             ], |             ], | ||||||
|             inertia: true, |             inertia: true, | ||||||
|  | |||||||
| @ -90,9 +90,11 @@ | |||||||
|     </dialog> |     </dialog> | ||||||
| </th:block> | </th:block> | ||||||
| 
 | 
 | ||||||
| <th:block th:fragment="fileSelector(name, multiple)"  th:with="accept=${accept} ?: '*/*', inputText=${inputText} ?: #{pdfPrompt}, remoteCall=${remoteCall} ?: 'true', notRequired=${notRequired} ?: false"> | <th:block th:fragment="fileSelector(name, multiple)"  th:with="accept=${accept} ?: '*/*', inputText=${inputText} ?: #{pdfPrompt}, remoteCall=${remoteCall} ?: true, notRequired=${notRequired} ?: false"> | ||||||
|     <script th:inline="javascript"> |     <script th:inline="javascript"> | ||||||
| 		const pdfPasswordPrompt =/*[[#{error.pdfPassword}]]*/ ''; | 		const pdfPasswordPrompt =/*[[#{error.pdfPassword}]]*/ ''; | ||||||
|  | 		const multiple = [[${multiple}]] || false; | ||||||
|  | 		const remoteCall = [[${remoteCall}]] || true; | ||||||
| 	</script> | 	</script> | ||||||
|     <script src="js/downloader.js"></script> |     <script src="js/downloader.js"></script> | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -130,12 +130,13 @@ | |||||||
|                                         // When zoomed out to less than 100%, for some very strange reason, |                                         // When zoomed out to less than 100%, for some very strange reason, | ||||||
|                                         // some browsers report devicePixelRatio as less than 1 |                                         // some browsers report devicePixelRatio as less than 1 | ||||||
|                                         // and only part of the canvas is cleared then. |                                         // and only part of the canvas is cleared then. | ||||||
|                                         var ratio =  Math.max(window.devicePixelRatio || 1, 1); |                                         var ratio = Math.max(window.devicePixelRatio || 1, 1); | ||||||
|  | 									    var additionalFactor = 10;   | ||||||
|  | 									 | ||||||
|  | 									    signaturePadCanvas.width = signaturePadCanvas.offsetWidth * ratio * additionalFactor; | ||||||
|  | 									    signaturePadCanvas.height = signaturePadCanvas.offsetHeight * ratio * additionalFactor; | ||||||
|  | 									    signaturePadCanvas.getContext("2d").scale(ratio * additionalFactor, ratio * additionalFactor); | ||||||
| 
 | 
 | ||||||
|                                         // This part causes the canvas to be cleared |  | ||||||
|                                         signaturePadCanvas.width = signaturePadCanvas.offsetWidth * ratio; |  | ||||||
|                                         signaturePadCanvas.height = signaturePadCanvas.offsetHeight * ratio; |  | ||||||
|                                         signaturePadCanvas.getContext("2d").scale(ratio, ratio); |  | ||||||
| 
 | 
 | ||||||
|                                         // This library does not listen for canvas changes, so after the canvas is automatically |                                         // This library does not listen for canvas changes, so after the canvas is automatically | ||||||
|                                         // cleared by the browser, SignaturePad#isEmpty might still return false, even though the |                                         // cleared by the browser, SignaturePad#isEmpty might still return false, even though the | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user