Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/pdf #83

Draft
wants to merge 7 commits into
base: chore/update-intervention-image
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ TRANSMORPHER_DEV_MODE=false
TRANSMORPHER_STORE_DERIVATIVES=true
TRANSMORPHER_DISK_ORIGINALS=localOriginals
TRANSMORPHER_DISK_IMAGE_DERIVATIVES=localImageDerivatives
TRANSMORPHER_DISK_PDF_DERIVATIVES=localPdfDerivatives
TRANSMORPHER_DISK_VIDEO_DERIVATIVES=localVideoDerivatives
#TRANSMORPHER_SIGNING_KEYPAIR=
TRANSMORPHER_OPTIMIZER_TIMEOUT=10
Expand All @@ -33,6 +34,7 @@ AWS_USE_PATH_STYLE_ENDPOINT=false
# AWS S3
AWS_BUCKET_ORIGINALS=
AWS_BUCKET_IMAGE_DERIVATIVES=
AWS_BUCKET_PDF_DERIVATIVES=
AWS_BUCKET_VIDEO_DERIVATIVES=
# AWS CloudFront
AWS_CLOUDFRONT_DISTRIBUTION_ID=
Expand Down
2 changes: 2 additions & 0 deletions .env.testing
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ TRANSMORPHER_DEV_MODE=false
TRANSMORPHER_STORE_DERIVATIVES=true
TRANSMORPHER_DISK_ORIGINALS=localOriginals
TRANSMORPHER_DISK_IMAGE_DERIVATIVES=localImageDerivatives
TRANSMORPHER_DISK_PDF_DERIVATIVES=localPdfDerivatives
TRANSMORPHER_DISK_VIDEO_DERIVATIVES=localVideoDerivatives
TRANSMORPHER_SIGNING_KEYPAIR=cc063331aa0ba451046a7cf6d2715df28877cf65578aa06e46175c49ac394685781b6895274da76e26cb4e9d045e3c3c4072c2e6f38f8502edaac07a22773ef2781b6895274da76e26cb4e9d045e3c3c4072c2e6f38f8502edaac07a22773ef2
TRANSMORPHER_OPTIMIZER_TIMEOUT=5
Expand All @@ -28,6 +29,7 @@ AWS_USE_PATH_STYLE_ENDPOINT=false
# AWS S3
AWS_BUCKET_ORIGINALS=
AWS_BUCKET_IMAGE_DERIVATIVES=
AWS_BUCKET_PDF_DERIVATIVES=
AWS_BUCKET_VIDEO_DERIVATIVES=
# AWS CloudFront
AWS_CLOUDFRONT_DISTRIBUTION_ID=
Expand Down
10 changes: 9 additions & 1 deletion .github/workflows/pullpreview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,34 @@ on:
types: [ labeled, unlabeled, synchronize, closed, reopened ]

jobs:
# https://docs.github.com/en/actions/using-workflows/storing-workflow-data-as-artifacts
prepare-amigor-env:
name: Prepare Amigor .env
if: ${{ contains(github.event.pull_request.labels.*.name, 'pullpreview') || github.event.action == 'unlabeled' || github.event.action == 'closed' }}
runs-on: ubuntu-latest

steps:
- name: Checkout Transmorpher repo
if: ${{ contains(github.event.pull_request.labels.*.name, 'pullpreview') && github.event.action != 'unlabeled' && github.event.action != 'closed' }}
# https://github.com/actions/checkout
uses: actions/checkout@v4
with:
sparse-checkout: |
.env.amigor
# https://git-scm.com/docs/git-sparse-checkout#_internalscone_mode_handling
sparse-checkout-cone-mode: false
- run: echo "TRANSMORPHER_AUTH_TOKEN=\"${{ secrets.PULLPREVIEW_SANCTUM_AUTH_TOKEN }}\"" >> .env.amigor

- name: Write secrets in .env file
if: ${{ contains(github.event.pull_request.labels.*.name, 'pullpreview') && github.event.action != 'unlabeled' && github.event.action != 'closed' }}
run: echo "TRANSMORPHER_AUTH_TOKEN=\"${{ secrets.PULLPREVIEW_SANCTUM_AUTH_TOKEN }}\"" >> .env.amigor

- name: Upload Amigor .env file
if: ${{ contains(github.event.pull_request.labels.*.name, 'pullpreview') && github.event.action != 'unlabeled' && github.event.action != 'closed' }}
# https://github.com/actions/upload-artifact
uses: actions/upload-artifact@v4
with:
name: amigor-env
include-hidden-files: true
path: |
.env.amigor

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@ jobs:
PHP_VERSION: ${{ matrix.php }}
LARAVEL_VERSION: ${{ matrix.laravel }}
DEPENDENCY_VERSION: ${{ matrix.dependency-version }}
MYSQL_DATABASE: transmorpher_test
DATABASE_NAME: transmorpher_test
LINUX_PACKAGES: imagemagick jpegoptim optipng pngquant gifsicle webp ffmpeg
203 changes: 143 additions & 60 deletions .phpstorm.meta.php

Large diffs are not rendered by default.

35 changes: 29 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Transmorpher Media Server

A media server for images and videos.
A media server for images, pdfs and videos.

> For a client implementation for Laravel
> see [Laravel Transmorpher Client](https://github.com/cybex-gmbh/laravel-transmorpher-client).
Expand All @@ -12,6 +12,9 @@ A media server for images and videos.
- [Intervention Image](https://github.com/Intervention/image)
- [Laravel Image Optimizer](https://github.com/spatie/laravel-image-optimizer)

#### PDF metadata removal
- [PDF Merge](https://github.com/karriereat/pdf-merge)

#### Video transcoding

- [PHP-FFmpeg-video-streaming](https://github.com/hadronepoch/PHP-FFmpeg-video-streaming)
Expand Down Expand Up @@ -185,6 +188,7 @@ To use AWS S3 disks set the according `.env` values:
```dotenv
TRANSMORPHER_DISK_ORIGINALS=s3Originals
TRANSMORPHER_DISK_IMAGE_DERIVATIVES=s3ImageDerivatives
TRANSMORPHER_DISK_PDF_DERIVATIVES=s3PdfDerivatives
TRANSMORPHER_DISK_VIDEO_DERIVATIVES=s3VideoDerivatives
```

Expand All @@ -193,6 +197,7 @@ Define the AWS S3 bucket for each disk:
```dotenv
AWS_BUCKET_ORIGINALS=
AWS_BUCKET_IMAGE_DERIVATIVES=
AWS_BUCKET_PDF_DERIVATIVES=
AWS_BUCKET_VIDEO_DERIVATIVES=
```

Expand Down Expand Up @@ -261,6 +266,7 @@ Select the following Laravel disks in the `.env`:
```dotenv
TRANSMORPHER_DISK_ORIGINALS=localOriginals
TRANSMORPHER_DISK_IMAGE_DERIVATIVES=localImageDerivatives
TRANSMORPHER_DISK_PDF_DERIVATIVES=localPdfDerivatives
TRANSMORPHER_DISK_VIDEO_DERIVATIVES=localVideoDerivatives
```

Expand Down Expand Up @@ -339,7 +345,7 @@ The media server provides the following features for media:
- set version
- delete

> Marked with * only applies to images.
> Marked with * does not apply to videos.

## Image transformation

Expand Down Expand Up @@ -369,6 +375,22 @@ For example:
The [Laravel Transmorpher Client](https://github.com/cybex-gmbh/laravel-transmorpher-client) will receive this information and store it. It can also create URLs with
transformations.

## PDF handling

Requesting a PDF file will return the document with removed metadata.
When transformations are specified, an image of a page will be returned.

All image transformations mentioned in the above section also apply to PDF image derivatives.
Requesting a PDF also follows the same URL structure as images, just replace `images` with `pdfs`.

Additionally, the page which should be used as image can be specified with the `p` transformation. Otherwise, the first page will be used.

For example:

PDF document: `https://transmorpher.test/pdfs/catworld/cat-essay`

Image of page 5: `https://transmorpher.test/pdfs/catworld/cat-essay/p-5+w-1920+h-1080`

## Video transcoding

Video transcoding is handled as an asynchronous task. The client will receive the
Expand Down Expand Up @@ -529,8 +551,8 @@ We provide a command which will additionally notify clients with a signed reques
php artisan purge:derivatives
```

The command accepts the options `--image`, `--video` and `--all` (or `-a`) for purging the respective derivatives.
Image derivatives will be deleted, for video derivatives we dispatch a new transcoding job for the current version.
The command accepts the options `--image`, `--pdf`, `--video` and `--all` (or `-a`) for purging the respective derivatives.
Image and PDF derivatives will be deleted, for video derivatives we dispatch a new transcoding job for the current version.

The derivatives revision is available on the route `/api/v*/cacheInvalidator`.

Expand All @@ -542,6 +564,7 @@ To restore operation of the server, restore the following:
- the `originals` disk
- `.env` file*
- the `image derivatives` disk*
- the `pdf derivatives` disk*
- the `video derivatives` disk*

> Marked with * are optional, but recommended.
Expand All @@ -550,7 +573,7 @@ If the `.env` file is lost follow the setup instructions above, including creati

If video derivatives are lost, use the [purge command](#purging-derivatives) to restore them.

Lost image derivatives will automatically be re-generated on demand.
Lost image and pdf derivatives will automatically be re-generated on demand.

## Development

Expand All @@ -569,7 +592,7 @@ App-specific GitHub Secrets:

#### Companion App

A demonstration app, which implements the client package, is booted with PullPreview and available at the PullPreview root URL. The Transmorpher media server runs under `/transmorpherServer`.
A demonstration app, which implements the client package, is booted with PullPreview and available at the PullPreview root URL. The Transmorpher media server runs as `transmorpher.` subdomain.

#### Auth Token Hash

Expand Down
86 changes: 73 additions & 13 deletions _ide_helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -22391,6 +22391,77 @@ public static function isConfigured()
*
*
*/
class DeliveryFacade {
/**
* Retrieve an original for a version.
*
* @param \App\Models\Version $version
* @return \Illuminate\Contracts\Foundation\Application|\Response|\Illuminate\Contracts\Routing\ResponseFactory
* @static
*/
public static function getOriginal($version)
{
/** @var \App\Classes\Delivery $instance */
return $instance->getOriginal($version);
}

/**
*
*
* @param string $transformations
* @param \App\Models\Version $version
* @param \App\Enums\MediaType $mediaType
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Response
* @static
*/
public static function getDerivative($transformations, $version, $mediaType)
{
/** @var \App\Classes\Delivery $instance */
return $instance->getDerivative($transformations, $version, $mediaType);
}

}
/**
*
*
*/
class OptimizeFacade {
/**
* Optimize an image derivative.
*
* Creates a temporary file since image optimizers only work locally.
*
* @param string $derivative
* @param int|null $quality
* @return string
* @throws Exception
* @static
*/
public static function optimize($derivative, $quality = null)
{
/** @var \App\Classes\Optimizer\Optimize $instance */
return $instance->optimize($derivative, $quality);
}

/**
*
*
* @param string $derivative
* @return string
* @throws Exception
* @static
*/
public static function removePdfMetadata($derivative)
{
/** @var \App\Classes\Optimizer\Optimize $instance */
return $instance->removePdfMetadata($derivative);
}

}
/**
*
*
*/
class TranscodeFacade {
/**
* Returns the class which handles the actual transcoding.
Expand Down Expand Up @@ -22462,7 +22533,6 @@ class TransformFacade {
* @param string $pathToOriginalImage
* @param array|null $transformations
* @return string Binary string of the image.
* @throws FileNotFoundException
* @static
*/
public static function transform($pathToOriginalImage, $transformations = null)
Expand All @@ -22471,18 +22541,6 @@ public static function transform($pathToOriginalImage, $transformations = null)
return $instance->transform($pathToOriginalImage, $transformations);
}

/**
*
*
* @return string[]
* @static
*/
public static function getSupportedFormats()
{
/** @var \App\Classes\Intervention\Transform $instance */
return $instance->getSupportedFormats();
}

}
}

Expand Down Expand Up @@ -28252,6 +28310,8 @@ class Validator extends \Illuminate\Support\Facades\Validator {}
class View extends \Illuminate\Support\Facades\View {}
class Vite extends \Illuminate\Support\Facades\Vite {}
class CdnHelper extends \App\Facades\CdnHelperFacade {}
class Delivery extends \App\Facades\DeliveryFacade {}
class Optimize extends \App\Facades\OptimizeFacade {}
class Transcode extends \App\Facades\TranscodeFacade {}
class Transform extends \App\Facades\TransformFacade {}
class Protector extends \Cybex\Protector\ProtectorFacade {}
Expand Down
63 changes: 63 additions & 0 deletions app/Classes/Delivery.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

namespace App\Classes;

use App\Enums\MediaStorage;
use App\Enums\MediaType;
use App\Enums\Transformation;
use App\Exceptions\InvalidTransformationFormatException;
use App\Exceptions\InvalidTransformationValueException;
use App\Exceptions\TransformationNotFoundException;
use App\Models\Version;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\Routing\ResponseFactory;
use Illuminate\Http\Response;

class Delivery
{
/**
* Retrieve an original for a version.
*
* @param Version $version
* @return Application|Response|ResponseFactory
*/
public function getOriginal(Version $version): Response|Application|ResponseFactory
{
$originalsDisk = MediaStorage::ORIGINALS->getDisk();
$pathToOriginal = $version->originalFilePath();

return response($originalsDisk->get($pathToOriginal), 200, ['Content-Type' => mime_content_type($originalsDisk->readStream($pathToOriginal))]);
}

/**
* @param string $transformations
* @param Version $version
* @param MediaType $mediaType
* @return Application|ResponseFactory|Response
*/
public function getDerivative(string $transformations, Version $version, MediaType $mediaType): ResponseFactory|Application|Response
{
try {
$transformationsArray = Transformation::arrayFromString($transformations);
} catch (TransformationNotFoundException|InvalidTransformationValueException|InvalidTransformationFormatException $exception) {
abort(400, $exception->getMessage());
}

$derivativesDisk = $mediaType->handler()->getDerivativesDisk();
$derivativePath = $version->nonVideoDerivativeFilePath($transformationsArray);

// Check if derivative already exists and return if so.
if (!config('transmorpher.dev_mode') && config('transmorpher.store_derivatives') && $derivativesDisk->exists($derivativePath)) {
$derivative = $derivativesDisk->get($derivativePath);
} else {
// Apply transformations to the media.
$derivative = $mediaType->handler()->applyTransformations($version, $transformationsArray);

if (config('transmorpher.store_derivatives')) {
$derivativesDisk->put($derivativePath, $derivative);
}
}

return response($derivative, 200, ['Content-Type' => mime_content_type($derivativesDisk->readStream($derivativePath))]);
}
}
Loading
Loading