Ghostscript PDF file compression using PHP's exec (Laravel on Docker)

风流意气都作罢 提交于 2021-01-28 12:02:08

问题


What needs to be done:

User has to be able to upload a PDF, then the file is uploaded to an Amazon S3 bucket, the file should be compressed then.

Current environment:

  • Laravel application (mounted on Docker) (php:7.4-fpm-alpine3.11, GPL Ghostscript 9.50, Laravel Framework 5.8.37)
  • Amazon S3 bucket to save documents in
  • Script is in a shell file which is made executable and added to /usr/local/bin as shrink
  • Shell is not explicitly added in Docker container, should it be?

Current flow:

  1. User uploads file
  2. File is uploaded to S3
  3. Laravel then downloads the file to local temp folder
  4. Ghostscript is then ran to compress said file (this script)
  5. Compressed file is uploaded back to S3

Problem:

The file is found and being compressed, but the output is a blank (1 page, which is white) pdf file.

Dockerfile:

# Add compression shell script to global executables
COPY .docker/config/shrink.sh /usr/local/bin/shrink
RUN chmod u+x /usr/local/bin/shrink
RUN chown nobody.nobody /usr/local/bin/shrink

nobody is the user PHP is running on.

PHP function that should compress the file:

public function optimizeFile($file_path)
    {
        // Copy file from default disk to temp disk
        Storage::disk('temp')->put($file_path, Storage::get($file_path));

        $fullTempFilePath = Storage::disk('temp')->path($file_path);

        if (Storage::mimeType($file_path) == 'application/pdf') {
            $output = shell_exec("shrink " . $fullTempFilePath . " " . $fullTempFilePath);
            if ($output != null) {
                Log::error($output);
            }
        } else {
            ImageOptimizer::optimize($fullTempFilePath);
        }

        // Write the compressed file back to default disk
        Storage::put($file_path, Storage::disk('temp')->get($file_path));

        // Delete temp file
        Storage::disk('temp')->delete($file_path);
    }

If the file isn't a PDF, ImageOptimizer does it's job and compresses the image successfully.

What have I tried:

  • (Local) Successfully compressed the file without Docker, using php artisan serve to launch Laravel app;
  • (Local) Successfully compressed the file with Docker using docker exec -it <container_id> shrink in.pdf out.pdf;
  • (Local) Successfully compressed the file with Docker in it's shell using docker exec -it <container_id> /bin/bash;
  • (Local) My coworker did the same things locally and the response is also a blank pdf

回答1:


Ok, so the problem is in here:

$output = shell_exec("shrink " . $fullTempFilePath . " " . $fullTempFilePath);

Ghostscript PDF compression does not work as expected if the input and output files are the same. Solution:

$output = shell_exec("shrink " . $fullTempFilePath  . $fullTempFilePath . "-compressed ");
shell_exec("mv " . $fullTempFilePath . "-compressed " . $fullTempFilePath);



回答2:


OK so first point; Ghostscript (more accurately the Ghostscript pdfwrite device) does not shrink PDF files. The actual process is described in the documentation in the overview in VectorDevices.htm. I'd reccomend you read it.

Secondly you can't use the same name for the input and output files. Ghostscript will still be reading from the input file while the pdfwrite device wants to write to the output file.



来源:https://stackoverflow.com/questions/60987289/ghostscript-pdf-file-compression-using-phps-exec-laravel-on-docker

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!