mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-16 19:33:11 +02:00
push docker (#5421)
# Description of Changes <!-- Please provide a summary of the changes, including: - What was changed - Why the change was made - Any challenges encountered Closes #(issue_number) --> --- ## Checklist ### General - [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md) (if applicable) - [ ] I have performed a self-review of my own code - [ ] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### Translations (if applicable) - [ ] I ran [`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing) for more details.
This commit is contained in:
@@ -1,245 +0,0 @@
|
|||||||
name: Push Docker Image - V2 Branch
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- V2-master
|
|
||||||
|
|
||||||
# cancel in-progress jobs if a new job is triggered
|
|
||||||
# This is useful to avoid running multiple builds for the same branch if a new commit is pushed
|
|
||||||
# or a pull request is updated.
|
|
||||||
# It helps to save resources and time by ensuring that only the latest commit is built and tested
|
|
||||||
# This is particularly useful for long-running jobs that may take a while to complete.
|
|
||||||
# The `group` is set to a combination of the workflow name, event name, and branch name.
|
|
||||||
# This ensures that jobs are grouped by the workflow and branch, allowing for cancellation of
|
|
||||||
# in-progress jobs when a new commit is pushed to the same branch or a new pull request is opened.
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref_name || github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
push:
|
|
||||||
if: ${{ vars.CI_PROFILE != 'lite' }}
|
|
||||||
runs-on: ubuntu-24.04-8core
|
|
||||||
permissions:
|
|
||||||
packages: write
|
|
||||||
id-token: write
|
|
||||||
steps:
|
|
||||||
- name: Harden Runner
|
|
||||||
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
|
|
||||||
with:
|
|
||||||
egress-policy: audit
|
|
||||||
|
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
|
||||||
|
|
||||||
- name: Set up JDK 21
|
|
||||||
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
|
|
||||||
with:
|
|
||||||
java-version: "21"
|
|
||||||
distribution: "temurin"
|
|
||||||
|
|
||||||
- uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0
|
|
||||||
with:
|
|
||||||
gradle-version: 8.14
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
id: buildx
|
|
||||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
|
|
||||||
|
|
||||||
- name: Get version number
|
|
||||||
id: versionNumber
|
|
||||||
run: echo "versionNumber=$(./gradlew printVersion --quiet | tail -1)" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Install cosign
|
|
||||||
if: github.ref == 'refs/heads/V2-master'
|
|
||||||
uses: sigstore/cosign-installer@d7543c93d881b35a8faa02e8e3605f69b7a1ce62 # v3.10.0
|
|
||||||
with:
|
|
||||||
cosign-release: "v2.4.1"
|
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKER_HUB_API }}
|
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
|
||||||
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ github.token }}
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
|
|
||||||
|
|
||||||
- name: Convert repository owner to lowercase
|
|
||||||
id: repoowner
|
|
||||||
run: echo "lowercase=$(echo ${{ github.repository_owner }} | awk '{print tolower($0)}')" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Generate tags for latest (V2-master branch - production)
|
|
||||||
id: meta
|
|
||||||
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
|
|
||||||
if: github.ref == 'refs/heads/V2-master'
|
|
||||||
with:
|
|
||||||
images: |
|
|
||||||
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
|
|
||||||
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf
|
|
||||||
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/stirling-pdf
|
|
||||||
${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf
|
|
||||||
tags: |
|
|
||||||
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}
|
|
||||||
type=raw,value=latest
|
|
||||||
|
|
||||||
- name: Generate tags for latest (V1_V2_merge branch - test)
|
|
||||||
id: meta-test
|
|
||||||
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
|
|
||||||
if: github.ref == 'refs/heads/V1_V2_merge'
|
|
||||||
with:
|
|
||||||
images: |
|
|
||||||
ghcr.io/stirling-tools/stirling-pdf-test
|
|
||||||
tags: |
|
|
||||||
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}
|
|
||||||
type=raw,value=latest
|
|
||||||
|
|
||||||
- name: Build and push Unified Dockerfile (latest variant)
|
|
||||||
id: build-push-latest
|
|
||||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
|
|
||||||
with:
|
|
||||||
builder: ${{ steps.buildx.outputs.name }}
|
|
||||||
context: .
|
|
||||||
file: ./docker/embedded/Dockerfile
|
|
||||||
push: true
|
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
tags: ${{ github.ref == 'refs/heads/V2-master' && steps.meta.outputs.tags || steps.meta-test.outputs.tags }}
|
|
||||||
labels: ${{ github.ref == 'refs/heads/V2-master' && steps.meta.outputs.labels || steps.meta-test.outputs.labels }}
|
|
||||||
build-args: VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
|
|
||||||
platforms: linux/amd64,linux/arm64/v8
|
|
||||||
provenance: true
|
|
||||||
sbom: true
|
|
||||||
|
|
||||||
- name: Sign regular images
|
|
||||||
if: github.ref == 'refs/heads/V2-master'
|
|
||||||
env:
|
|
||||||
DIGEST: ${{ steps.build-push-latest.outputs.digest }}
|
|
||||||
TAGS: ${{ steps.meta.outputs.tags }}
|
|
||||||
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
|
|
||||||
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
|
|
||||||
run: |
|
|
||||||
echo "$TAGS" | tr ',' '\n' | while read -r tag; do
|
|
||||||
cosign sign --yes \
|
|
||||||
--key env://COSIGN_PRIVATE_KEY \
|
|
||||||
"${tag}@${DIGEST}"
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: Generate tags for latest-fat (V2-master branch - production)
|
|
||||||
id: meta-fat
|
|
||||||
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
|
|
||||||
if: github.ref == 'refs/heads/V2-master'
|
|
||||||
with:
|
|
||||||
images: |
|
|
||||||
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
|
|
||||||
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf
|
|
||||||
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/stirling-pdf
|
|
||||||
${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf
|
|
||||||
tags: |
|
|
||||||
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-fat
|
|
||||||
type=raw,value=latest-fat
|
|
||||||
|
|
||||||
- name: Generate tags for latest-fat (V1_V2_merge branch - test)
|
|
||||||
id: meta-fat-test
|
|
||||||
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
|
|
||||||
if: github.ref == 'refs/heads/V1_V2_merge'
|
|
||||||
with:
|
|
||||||
images: |
|
|
||||||
ghcr.io/stirling-tools/stirling-pdf-test
|
|
||||||
tags: |
|
|
||||||
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-fat
|
|
||||||
type=raw,value=latest-fat
|
|
||||||
|
|
||||||
- name: Build and push Unified Dockerfile (fat variant)
|
|
||||||
id: build-push-fat
|
|
||||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
|
|
||||||
with:
|
|
||||||
builder: ${{ steps.buildx.outputs.name }}
|
|
||||||
context: .
|
|
||||||
file: ./docker/embedded/Dockerfile.fat
|
|
||||||
push: true
|
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
tags: ${{ github.ref == 'refs/heads/V2-master' && steps.meta-fat.outputs.tags || steps.meta-fat-test.outputs.tags }}
|
|
||||||
labels: ${{ github.ref == 'refs/heads/V2-master' && steps.meta-fat.outputs.labels || steps.meta-fat-test.outputs.labels }}
|
|
||||||
build-args: VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
|
|
||||||
platforms: linux/amd64,linux/arm64/v8
|
|
||||||
provenance: true
|
|
||||||
sbom: true
|
|
||||||
|
|
||||||
- name: Sign fat images
|
|
||||||
if: github.ref == 'refs/heads/V2-master'
|
|
||||||
env:
|
|
||||||
DIGEST: ${{ steps.build-push-fat.outputs.digest }}
|
|
||||||
TAGS: ${{ steps.meta-fat.outputs.tags }}
|
|
||||||
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
|
|
||||||
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
|
|
||||||
run: |
|
|
||||||
echo "$TAGS" | tr ',' '\n' | while read -r tag; do
|
|
||||||
cosign sign --key env://COSIGN_PRIVATE_KEY --yes "${tag}@${DIGEST}"
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: Generate tags for ultra-lite (V2-master branch - production)
|
|
||||||
id: meta-lite
|
|
||||||
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
|
|
||||||
if: github.ref == 'refs/heads/V2-master'
|
|
||||||
with:
|
|
||||||
images: |
|
|
||||||
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
|
|
||||||
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf
|
|
||||||
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/stirling-pdf
|
|
||||||
${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf
|
|
||||||
tags: |
|
|
||||||
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-ultra-lite
|
|
||||||
type=raw,value=latest-ultra-lite
|
|
||||||
|
|
||||||
- name: Generate tags for ultra-lite (V1_V2_merge branch - test)
|
|
||||||
id: meta-lite-test
|
|
||||||
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
|
|
||||||
if: github.ref == 'refs/heads/V1_V2_merge'
|
|
||||||
with:
|
|
||||||
images: |
|
|
||||||
ghcr.io/stirling-tools/stirling-pdf-test
|
|
||||||
tags: |
|
|
||||||
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-ultra-lite
|
|
||||||
type=raw,value=latest-ultra-lite
|
|
||||||
|
|
||||||
- name: Build and push Unified Dockerfile (ultra-lite variant)
|
|
||||||
id: build-push-lite
|
|
||||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
|
|
||||||
with:
|
|
||||||
builder: ${{ steps.buildx.outputs.name }}
|
|
||||||
context: .
|
|
||||||
file: ./docker/embedded/Dockerfile.ultra-lite
|
|
||||||
push: true
|
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
tags: ${{ github.ref == 'refs/heads/V2-master' && steps.meta-lite.outputs.tags || steps.meta-lite-test.outputs.tags }}
|
|
||||||
labels: ${{ github.ref == 'refs/heads/V2-master' && steps.meta-lite.outputs.labels || steps.meta-lite-test.outputs.labels }}
|
|
||||||
build-args: VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
|
|
||||||
platforms: linux/amd64,linux/arm64/v8
|
|
||||||
provenance: true
|
|
||||||
sbom: true
|
|
||||||
|
|
||||||
- name: Sign ultra-lite images
|
|
||||||
if: github.ref == 'refs/heads/V2-master'
|
|
||||||
env:
|
|
||||||
DIGEST: ${{ steps.build-push-lite.outputs.digest }}
|
|
||||||
TAGS: ${{ steps.meta-lite.outputs.tags }}
|
|
||||||
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
|
|
||||||
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
|
|
||||||
run: |
|
|
||||||
echo "$TAGS" | tr ',' '\n' | while read -r tag; do
|
|
||||||
cosign sign --key env://COSIGN_PRIVATE_KEY --yes "${tag}@${DIGEST}"
|
|
||||||
done
|
|
||||||
@@ -6,6 +6,8 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
- main
|
- main
|
||||||
|
- V2-master
|
||||||
|
- testMain
|
||||||
|
|
||||||
# cancel in-progress jobs if a new job is triggered
|
# cancel in-progress jobs if a new job is triggered
|
||||||
# This is useful to avoid running multiple builds for the same branch if a new commit is pushed
|
# This is useful to avoid running multiple builds for the same branch if a new commit is pushed
|
||||||
@@ -25,7 +27,7 @@ permissions:
|
|||||||
jobs:
|
jobs:
|
||||||
push:
|
push:
|
||||||
if: ${{ vars.CI_PROFILE != 'lite' }}
|
if: ${{ vars.CI_PROFILE != 'lite' }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04-8core
|
||||||
permissions:
|
permissions:
|
||||||
packages: write
|
packages: write
|
||||||
id-token: write
|
id-token: write
|
||||||
@@ -47,18 +49,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
gradle-version: 8.14
|
gradle-version: 8.14
|
||||||
|
|
||||||
- name: Run Gradle Command
|
|
||||||
run: ./gradlew clean build
|
|
||||||
env:
|
|
||||||
DISABLE_ADDITIONAL_FEATURES: true
|
|
||||||
STIRLING_PDF_DESKTOP_UI: false
|
|
||||||
|
|
||||||
- name: Install cosign
|
|
||||||
if: github.ref == 'refs/heads/master'
|
|
||||||
uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0
|
|
||||||
with:
|
|
||||||
cosign-release: "v2.4.1"
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
id: buildx
|
id: buildx
|
||||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
|
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
|
||||||
@@ -67,6 +57,12 @@ jobs:
|
|||||||
id: versionNumber
|
id: versionNumber
|
||||||
run: echo "versionNumber=$(./gradlew printVersion --quiet | tail -1)" >> $GITHUB_OUTPUT
|
run: echo "versionNumber=$(./gradlew printVersion --quiet | tail -1)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Install cosign
|
||||||
|
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/V2-master'
|
||||||
|
uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0
|
||||||
|
with:
|
||||||
|
cosign-release: "v2.4.1"
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
|
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
|
||||||
with:
|
with:
|
||||||
@@ -87,10 +83,9 @@ jobs:
|
|||||||
id: repoowner
|
id: repoowner
|
||||||
run: echo "lowercase=$(echo ${{ github.repository_owner }} | awk '{print tolower($0)}')" >> $GITHUB_OUTPUT
|
run: echo "lowercase=$(echo ${{ github.repository_owner }} | awk '{print tolower($0)}')" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Generate tags
|
- name: Generate tags for latest
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
|
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
|
||||||
if: github.ref != 'refs/heads/main'
|
|
||||||
with:
|
with:
|
||||||
images: |
|
images: |
|
||||||
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
|
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
|
||||||
@@ -98,13 +93,13 @@ jobs:
|
|||||||
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/stirling-pdf
|
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/stirling-pdf
|
||||||
${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf
|
${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf
|
||||||
tags: |
|
tags: |
|
||||||
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }},enable=${{ github.ref == 'refs/heads/master' }}
|
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }},enable=${{ github.ref == 'refs/heads/master' || github.ref == 'refs/heads/V2-master' }}
|
||||||
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/master' }}
|
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/master' || github.ref == 'refs/heads/V2-master' }}
|
||||||
|
type=raw,value=alpha,enable=${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/testMain' }}
|
||||||
|
|
||||||
- name: Build and push main Dockerfile
|
- name: Build and push Unified Dockerfile (latest variant)
|
||||||
id: build-push-regular
|
id: build-push-latest
|
||||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
|
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
|
||||||
if: github.ref != 'refs/heads/main'
|
|
||||||
with:
|
with:
|
||||||
builder: ${{ steps.buildx.outputs.name }}
|
builder: ${{ steps.buildx.outputs.name }}
|
||||||
context: .
|
context: .
|
||||||
@@ -120,9 +115,9 @@ jobs:
|
|||||||
sbom: true
|
sbom: true
|
||||||
|
|
||||||
- name: Sign regular images
|
- name: Sign regular images
|
||||||
if: github.ref == 'refs/heads/master'
|
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/V2-master'
|
||||||
env:
|
env:
|
||||||
DIGEST: ${{ steps.build-push-regular.outputs.digest }}
|
DIGEST: ${{ steps.build-push-latest.outputs.digest }}
|
||||||
TAGS: ${{ steps.meta.outputs.tags }}
|
TAGS: ${{ steps.meta.outputs.tags }}
|
||||||
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
|
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
|
||||||
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
|
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
|
||||||
@@ -133,10 +128,10 @@ jobs:
|
|||||||
"${tag}@${DIGEST}"
|
"${tag}@${DIGEST}"
|
||||||
done
|
done
|
||||||
|
|
||||||
- name: Generate tags ultra-lite
|
- name: Generate tags for latest-fat
|
||||||
id: meta2
|
id: meta-fat
|
||||||
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
|
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
|
||||||
if: github.ref != 'refs/heads/main'
|
if: github.ref != 'refs/heads/main' && github.ref != 'refs/heads/testMain'
|
||||||
with:
|
with:
|
||||||
images: |
|
images: |
|
||||||
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
|
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
|
||||||
@@ -144,43 +139,13 @@ jobs:
|
|||||||
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/stirling-pdf
|
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/stirling-pdf
|
||||||
${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf
|
${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf
|
||||||
tags: |
|
tags: |
|
||||||
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-ultra-lite,enable=${{ github.ref == 'refs/heads/master' }}
|
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-fat,enable=${{ github.ref == 'refs/heads/master' || github.ref == 'refs/heads/V2-master' }}
|
||||||
type=raw,value=latest-ultra-lite,enable=${{ github.ref == 'refs/heads/master' }}
|
type=raw,value=latest-fat,enable=${{ github.ref == 'refs/heads/master' || github.ref == 'refs/heads/V2-master' }}
|
||||||
|
|
||||||
- name: Build and push Dockerfile-ultra-lite
|
- name: Build and push Unified Dockerfile (fat variant)
|
||||||
id: build-push-lite
|
|
||||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
|
|
||||||
if: github.ref != 'refs/heads/main'
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: ./docker/embedded/Dockerfile.ultra-lite
|
|
||||||
push: true
|
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
tags: ${{ steps.meta2.outputs.tags }}
|
|
||||||
labels: ${{ steps.meta2.outputs.labels }}
|
|
||||||
build-args: VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
|
|
||||||
platforms: linux/amd64,linux/arm64/v8
|
|
||||||
provenance: true
|
|
||||||
sbom: true
|
|
||||||
|
|
||||||
- name: Generate tags fat
|
|
||||||
id: meta3
|
|
||||||
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
|
|
||||||
with:
|
|
||||||
images: |
|
|
||||||
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
|
|
||||||
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf
|
|
||||||
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/stirling-pdf
|
|
||||||
${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf
|
|
||||||
tags: |
|
|
||||||
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-fat,enable=${{ github.ref == 'refs/heads/master' }}
|
|
||||||
type=raw,value=latest-fat,enable=${{ github.ref == 'refs/heads/master' }}
|
|
||||||
type=raw,value=alpha,enable=${{ github.ref == 'refs/heads/main' }}
|
|
||||||
|
|
||||||
- name: Build and push main Dockerfile fat
|
|
||||||
id: build-push-fat
|
id: build-push-fat
|
||||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
|
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
|
||||||
|
if: github.ref != 'refs/heads/main' && github.ref != 'refs/heads/testMain'
|
||||||
with:
|
with:
|
||||||
builder: ${{ steps.buildx.outputs.name }}
|
builder: ${{ steps.buildx.outputs.name }}
|
||||||
context: .
|
context: .
|
||||||
@@ -188,18 +153,62 @@ jobs:
|
|||||||
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.meta3.outputs.tags }}
|
tags: ${{ steps.meta-fat.outputs.tags }}
|
||||||
labels: ${{ steps.meta3.outputs.labels }}
|
labels: ${{ steps.meta-fat.outputs.labels }}
|
||||||
build-args: VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
|
build-args: VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
|
||||||
platforms: linux/amd64,linux/arm64/v8
|
platforms: linux/amd64,linux/arm64/v8
|
||||||
provenance: true
|
provenance: true
|
||||||
sbom: true
|
sbom: true
|
||||||
|
|
||||||
- name: Sign fat images
|
- name: Sign fat images
|
||||||
if: github.ref == 'refs/heads/master'
|
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/V2-master'
|
||||||
env:
|
env:
|
||||||
DIGEST: ${{ steps.build-push-fat.outputs.digest }}
|
DIGEST: ${{ steps.build-push-fat.outputs.digest }}
|
||||||
TAGS: ${{ steps.meta3.outputs.tags }}
|
TAGS: ${{ steps.meta-fat.outputs.tags }}
|
||||||
|
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
|
||||||
|
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
|
||||||
|
run: |
|
||||||
|
echo "$TAGS" | tr ',' '\n' | while read -r tag; do
|
||||||
|
cosign sign --key env://COSIGN_PRIVATE_KEY --yes "${tag}@${DIGEST}"
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Generate tags for ultra-lite
|
||||||
|
id: meta-lite
|
||||||
|
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
|
||||||
|
if: github.ref != 'refs/heads/main' && github.ref != 'refs/heads/testMain'
|
||||||
|
with:
|
||||||
|
images: |
|
||||||
|
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
|
||||||
|
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf
|
||||||
|
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/stirling-pdf
|
||||||
|
${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf
|
||||||
|
tags: |
|
||||||
|
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-ultra-lite,enable=${{ github.ref == 'refs/heads/master' || github.ref == 'refs/heads/V2-master' }}
|
||||||
|
type=raw,value=latest-ultra-lite,enable=${{ github.ref == 'refs/heads/master' || github.ref == 'refs/heads/V2-master' }}
|
||||||
|
|
||||||
|
- name: Build and push Unified Dockerfile (ultra-lite variant)
|
||||||
|
id: build-push-lite
|
||||||
|
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
|
||||||
|
if: github.ref != 'refs/heads/main' && github.ref != 'refs/heads/testMain'
|
||||||
|
with:
|
||||||
|
builder: ${{ steps.buildx.outputs.name }}
|
||||||
|
context: .
|
||||||
|
file: ./docker/embedded/Dockerfile.ultra-lite
|
||||||
|
push: true
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
|
tags: ${{ steps.meta-lite.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta-lite.outputs.labels }}
|
||||||
|
build-args: VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
|
||||||
|
platforms: linux/amd64,linux/arm64/v8
|
||||||
|
provenance: true
|
||||||
|
sbom: true
|
||||||
|
|
||||||
|
- name: Sign ultra-lite images
|
||||||
|
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/V2-master'
|
||||||
|
env:
|
||||||
|
DIGEST: ${{ steps.build-push-lite.outputs.digest }}
|
||||||
|
TAGS: ${{ steps.meta-lite.outputs.tags }}
|
||||||
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
|
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
|
||||||
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
|
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package stirling.software.SPDF.controller.api;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
@@ -27,7 +28,6 @@ import org.springframework.http.ResponseEntity;
|
|||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
|
||||||
@@ -277,7 +277,7 @@ public class MergeController {
|
|||||||
"This endpoint merges multiple PDF files into a single PDF file. The merged"
|
"This endpoint merges multiple PDF files into a single PDF file. The merged"
|
||||||
+ " file will contain all pages from the input files in the order they were"
|
+ " file will contain all pages from the input files in the order they were"
|
||||||
+ " provided. Input:PDF Output:PDF Type:MISO")
|
+ " provided. Input:PDF Output:PDF Type:MISO")
|
||||||
public ResponseEntity<StreamingResponseBody> mergePdfs(
|
public ResponseEntity<byte[]> mergePdfs(
|
||||||
@ModelAttribute MergePdfsRequest request,
|
@ModelAttribute MergePdfsRequest request,
|
||||||
@RequestParam(value = "fileOrder", required = false) String fileOrder)
|
@RequestParam(value = "fileOrder", required = false) String fileOrder)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
@@ -304,8 +304,6 @@ public class MergeController {
|
|||||||
request.getSortType())); // Sort files based on requested sort type
|
request.getSortType())); // Sort files based on requested sort type
|
||||||
}
|
}
|
||||||
|
|
||||||
ResponseEntity<StreamingResponseBody> response;
|
|
||||||
|
|
||||||
try (TempFile mt = new TempFile(tempFileManager, ".pdf")) {
|
try (TempFile mt = new TempFile(tempFileManager, ".pdf")) {
|
||||||
|
|
||||||
PDFMergerUtility mergerUtility = new PDFMergerUtility();
|
PDFMergerUtility mergerUtility = new PDFMergerUtility();
|
||||||
@@ -399,7 +397,7 @@ public class MergeController {
|
|||||||
String mergedFileName =
|
String mergedFileName =
|
||||||
GeneralUtils.generateFilename(firstFilename, "_merged_unsigned.pdf");
|
GeneralUtils.generateFilename(firstFilename, "_merged_unsigned.pdf");
|
||||||
|
|
||||||
response = WebResponseUtils.pdfFileToWebResponse(outputTempFile, mergedFileName);
|
byte[] pdfBytes = Files.readAllBytes(outputTempFile.getPath());
|
||||||
return response;
|
return WebResponseUtils.bytesToWebResponse(pdfBytes, mergedFileName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-23
@@ -1,7 +1,7 @@
|
|||||||
package stirling.software.SPDF.controller.api;
|
package stirling.software.SPDF.controller.api;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
@@ -19,40 +19,37 @@ import org.apache.pdfbox.util.Matrix;
|
|||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.config.swagger.MultiFileResponse;
|
||||||
import stirling.software.SPDF.model.SplitTypes;
|
import stirling.software.SPDF.model.SplitTypes;
|
||||||
import stirling.software.SPDF.model.api.SplitPdfBySectionsRequest;
|
import stirling.software.SPDF.model.api.SplitPdfBySectionsRequest;
|
||||||
|
import stirling.software.common.annotations.AutoJobPostMapping;
|
||||||
|
import stirling.software.common.annotations.api.GeneralApi;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.common.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.common.util.ExceptionUtils;
|
import stirling.software.common.util.ExceptionUtils;
|
||||||
import stirling.software.common.util.GeneralUtils;
|
import stirling.software.common.util.GeneralUtils;
|
||||||
import stirling.software.common.util.PDFService;
|
|
||||||
import stirling.software.common.util.TempFile;
|
import stirling.software.common.util.TempFile;
|
||||||
import stirling.software.common.util.TempFileManager;
|
import stirling.software.common.util.TempFileManager;
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
import stirling.software.common.util.WebResponseUtils;
|
||||||
|
|
||||||
|
@GeneralApi
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/v1/general")
|
|
||||||
@Tag(name = "General", description = "General APIs")
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class SplitPdfBySectionsController {
|
public class SplitPdfBySectionsController {
|
||||||
|
|
||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
private final TempFileManager tempFileManager;
|
private final TempFileManager tempFileManager;
|
||||||
private final PDFService pdfService;
|
|
||||||
|
|
||||||
@PostMapping(value = "/split-pdf-by-sections", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
@AutoJobPostMapping(
|
||||||
|
consumes = MediaType.MULTIPART_FORM_DATA_VALUE,
|
||||||
|
value = "/split-pdf-by-sections")
|
||||||
|
@MultiFileResponse
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Split PDF pages into smaller sections",
|
summary = "Split PDF pages into smaller sections",
|
||||||
description =
|
description =
|
||||||
@@ -60,8 +57,8 @@ public class SplitPdfBySectionsController {
|
|||||||
+ " which page to split, and how to split"
|
+ " which page to split, and how to split"
|
||||||
+ " ( halves, thirds, quarters, etc.), both vertically and horizontally."
|
+ " ( halves, thirds, quarters, etc.), both vertically and horizontally."
|
||||||
+ " Input:PDF Output:ZIP-PDF Type:SISO")
|
+ " Input:PDF Output:ZIP-PDF Type:SISO")
|
||||||
public ResponseEntity<StreamingResponseBody> splitPdf(
|
public ResponseEntity<byte[]> splitPdf(@ModelAttribute SplitPdfBySectionsRequest request)
|
||||||
@ModelAttribute SplitPdfBySectionsRequest request) throws Exception {
|
throws Exception {
|
||||||
MultipartFile file = request.getFileInput();
|
MultipartFile file = request.getFileInput();
|
||||||
String pageNumbers = request.getPageNumbers();
|
String pageNumbers = request.getPageNumbers();
|
||||||
SplitTypes splitMode =
|
SplitTypes splitMode =
|
||||||
@@ -80,9 +77,10 @@ public class SplitPdfBySectionsController {
|
|||||||
String filename = GeneralUtils.generateFilename(file.getOriginalFilename(), "_split");
|
String filename = GeneralUtils.generateFilename(file.getOriginalFilename(), "_split");
|
||||||
|
|
||||||
if (merge) {
|
if (merge) {
|
||||||
TempFile tempFile = new TempFile(tempFileManager, ".pdf");
|
try (PDDocument mergedDoc =
|
||||||
try (PDDocument mergedDoc = pdfDocumentFactory.createNewDocument();
|
pdfDocumentFactory.createNewDocumentBasedOnOldDocument(
|
||||||
OutputStream out = Files.newOutputStream(tempFile.getPath())) {
|
sourceDocument);
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
|
||||||
LayerUtility layerUtility = new LayerUtility(mergedDoc);
|
LayerUtility layerUtility = new LayerUtility(mergedDoc);
|
||||||
for (int pageIndex = 0;
|
for (int pageIndex = 0;
|
||||||
pageIndex < sourceDocument.getNumberOfPages();
|
pageIndex < sourceDocument.getNumberOfPages();
|
||||||
@@ -99,12 +97,9 @@ public class SplitPdfBySectionsController {
|
|||||||
addPageToTarget(sourceDocument, pageIndex, mergedDoc, layerUtility);
|
addPageToTarget(sourceDocument, pageIndex, mergedDoc, layerUtility);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mergedDoc.save(out);
|
mergedDoc.save(baos);
|
||||||
} catch (IOException e) {
|
return WebResponseUtils.baosToWebResponse(baos, filename + ".pdf");
|
||||||
log.error("Error creating merged PDF document", e);
|
|
||||||
throw e;
|
|
||||||
}
|
}
|
||||||
return WebResponseUtils.pdfFileToWebResponse(tempFile, filename + ".pdf");
|
|
||||||
} else {
|
} else {
|
||||||
TempFile zipTempFile = new TempFile(tempFileManager, ".zip");
|
TempFile zipTempFile = new TempFile(tempFileManager, ".zip");
|
||||||
try (ZipOutputStream zipOut =
|
try (ZipOutputStream zipOut =
|
||||||
@@ -163,7 +158,9 @@ public class SplitPdfBySectionsController {
|
|||||||
log.error("Error creating ZIP file with split PDF sections", e);
|
log.error("Error creating ZIP file with split PDF sections", e);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
return WebResponseUtils.zipFileToWebResponse(zipTempFile, filename + ".zip");
|
byte[] zipBytes = Files.readAllBytes(zipTempFile.getPath());
|
||||||
|
return WebResponseUtils.bytesToWebResponse(
|
||||||
|
zipBytes, filename + ".zip", MediaType.APPLICATION_OCTET_STREAM);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Error splitting PDF file: {}", file.getOriginalFilename(), e);
|
log.error("Error splitting PDF file: {}", file.getOriginalFilename(), e);
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
tesseract-ocr tesseract-ocr-eng tesseract-ocr-deu tesseract-ocr-fra \
|
tesseract-ocr tesseract-ocr-eng tesseract-ocr-deu tesseract-ocr-fra \
|
||||||
tesseract-ocr-por tesseract-ocr-chi-sim \
|
tesseract-ocr-por tesseract-ocr-chi-sim \
|
||||||
libcairo2 libpango-1.0-0 libpangoft2-1.0-0 libgdk-pixbuf-2.0-0 \
|
libcairo2 libpango-1.0-0 libpangoft2-1.0-0 libgdk-pixbuf-2.0-0 \
|
||||||
gosu unpaper \
|
gosu unpaper qpdf \
|
||||||
# AWT headless support (required for some Java graphics operations)
|
# AWT headless support (required for some Java graphics operations)
|
||||||
libfreetype6 libfontconfig1 libx11-6 libxt6 libxext6 libxrender1 libxtst6 libxi6 \
|
libfreetype6 libfontconfig1 libx11-6 libxt6 libxext6 libxrender1 libxtst6 libxi6 \
|
||||||
libxinerama1 libxkbcommon0 libxkbfile1 libsm6 libice6 \
|
libxinerama1 libxkbcommon0 libxkbfile1 libsm6 libice6 \
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
tesseract-ocr tesseract-ocr-eng tesseract-ocr-deu tesseract-ocr-fra \
|
tesseract-ocr tesseract-ocr-eng tesseract-ocr-deu tesseract-ocr-fra \
|
||||||
tesseract-ocr-por tesseract-ocr-chi-sim \
|
tesseract-ocr-por tesseract-ocr-chi-sim \
|
||||||
libcairo2 libpango-1.0-0 libpangoft2-1.0-0 libgdk-pixbuf-2.0-0 \
|
libcairo2 libpango-1.0-0 libpangoft2-1.0-0 libgdk-pixbuf-2.0-0 \
|
||||||
gosu unpaper \
|
gosu unpaper qpdf \
|
||||||
# Extra fonts for fat/air-gapped version
|
# Extra fonts for fat/air-gapped version
|
||||||
fonts-dejavu fonts-liberation fonts-noto fonts-noto-cjk fonts-noto-color-emoji \
|
fonts-dejavu fonts-liberation fonts-noto fonts-noto-cjk fonts-noto-color-emoji \
|
||||||
fonts-freefont-ttf fonts-terminus fonts-linuxlibertine \
|
fonts-freefont-ttf fonts-terminus fonts-linuxlibertine \
|
||||||
|
|||||||
Reference in New Issue
Block a user