Skip to content

Commit

Permalink
Merge pull request #70 from victorsoares96/feat/handle-protected-files
Browse files Browse the repository at this point in the history
✨ feat: added support to compress protected pdf files
  • Loading branch information
victorsoares96 authored Jan 25, 2024
2 parents b85277a + c13db07 commit bc6904d
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 22 deletions.
12 changes: 6 additions & 6 deletions .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ jobs:
- name: Unit Testing
run: yarn test:coverage

# - name: Upload Coverage
# uses: codecov/codecov-action@v3
# with:
# # token: ${{secrets.CODECOV_TOKEN}} # not required for public repos
# directory: coverage
# fail_ci_if_error: true
- name: Upload Coverage
uses: codecov/codecov-action@v3
with:
token: ${{secrets.CODECOV_TOKEN}} # not required for public repos
directory: coverage
fail_ci_if_error: true

- name: Build
run: yarn build
Expand Down
38 changes: 37 additions & 1 deletion __tests__/compress.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ describe('compress', () => {
);

const originalFile = await fs.promises.readFile(originalFilePath);
const originalPDF = await testHelper.parsePDF(originalFilePath);
const originalPDF = await testHelper.parsePDF({
data: originalFile,
url: 0,
range: '',
});

const compressedFile = await compress(originalFilePath);
const compressedPDF = await testHelper.parsePDF(compressedFile);
Expand All @@ -21,4 +25,36 @@ describe('compress', () => {
expect(compressedPDF.numrender).toEqual(originalPDF.numrender);
expect(compressedPDF.text).toEqual(originalPDF.text);
});

it('should compress a protected pdf file', async () => {
const originalFilePath = path.resolve(
__dirname,
'../examples/A17_FlightPlan-protected.pdf'
);

const originalFile = await fs.promises.readFile(originalFilePath);
// https://gitlab.com/autokent/pdf-parse/-/merge_requests/4
const originalPDF = await testHelper.parsePDF({
data: originalFile,
url: 0,
range: '',
password: 'a17',
});

const compressedFile = await compress(originalFilePath, {
pdfPassword: 'a17',
});
// https://gitlab.com/autokent/pdf-parse/-/merge_requests/4
const compressedPDF = await testHelper.parsePDF({
data: compressedFile,
url: 0,
range: '',
password: 'a17',
});

expect(compressedFile.length).toBeLessThan(originalFile.length);
expect(compressedPDF.numpages).toEqual(originalPDF.numpages);
expect(compressedPDF.numrender).toEqual(originalPDF.numrender);
expect(compressedPDF.text).toEqual(originalPDF.text);
});
});
11 changes: 2 additions & 9 deletions __tests__/test.helper.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
import fs from 'fs';
import type pdfParser from 'pdf-parse';

// https://gitlab.com/autokent/pdf-parse/-/issues/24
// eslint-disable-next-line @typescript-eslint/no-var-requires
const PDFParser = require('pdf-parse');

export async function parsePDF(
file: string | Buffer,
src: unknown,
options?: pdfParser.Options
): Promise<pdfParser.Result> {
let dataBuffer: Buffer;

if (typeof file === 'string') {
dataBuffer = fs.readFileSync(file);
} else dataBuffer = file;

const data = await PDFParser(dataBuffer, options);
const data = await PDFParser(src, options);

return data;
}
Binary file added examples/A17_FlightPlan-protected.pdf
Binary file not shown.
Binary file removed examples/compressed_pdf.pdf
Binary file not shown.
11 changes: 11 additions & 0 deletions examples/protected.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import path from 'path';
import fs from 'fs';
import { compress } from '@/index';

(async () => {
const pdf = path.resolve(__dirname, 'A17_FlightPlan-protected.pdf');
const buffer = await compress(pdf, { pdfPassword: 'a17' });

const compressedPdf = path.resolve(__dirname, 'compressed_protected_pdf.pdf');
await fs.promises.writeFile(compressedPdf, buffer);
})();
42 changes: 36 additions & 6 deletions src/compress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,57 @@ const defaultOptions: Required<Options> = {
resolution: 'ebook',
imageQuality: 100,
gsModule: getBinPath(os.platform()),
pdfPassword: '',
removePasswordAfterCompression: false,
};

async function compress(file: string | Buffer, options?: Options) {
const { resolution, imageQuality, compatibilityLevel, gsModule } = defaults(
options,
defaultOptions
);
const {
resolution,
imageQuality,
compatibilityLevel,
gsModule,
pdfPassword,
removePasswordAfterCompression,
} = defaults(options, defaultOptions);

const output = path.resolve(os.tmpdir(), Date.now().toString());

let command: string;
let tempFile: string | undefined;

if (typeof file === 'string') {
command = `${gsModule} -q -dNOPAUSE -dBATCH -dSAFER -dSimulateOverprint=true -sDEVICE=pdfwrite -dCompatibilityLevel=${compatibilityLevel} -dPDFSETTINGS=/${resolution} -dEmbedAllFonts=true -dSubsetFonts=true -dAutoRotatePages=/None -dColorImageDownsampleType=/Bicubic -dColorImageResolution=${imageQuality} -dGrayImageDownsampleType=/Bicubic -dGrayImageResolution=${imageQuality} -dMonoImageDownsampleType=/Bicubic -dMonoImageResolution=${imageQuality} -sOutputFile=${output} ${file}`;
command = `${gsModule} -q -dNOPAUSE -dBATCH -dSAFER -dSimulateOverprint=true -sDEVICE=pdfwrite -dCompatibilityLevel=${compatibilityLevel} -dPDFSETTINGS=/${resolution} -dEmbedAllFonts=true -dSubsetFonts=true -dAutoRotatePages=/None -dColorImageDownsampleType=/Bicubic -dColorImageResolution=${imageQuality} -dGrayImageDownsampleType=/Bicubic -dGrayImageResolution=${imageQuality} -dMonoImageDownsampleType=/Bicubic -dMonoImageResolution=${imageQuality} -sOutputFile=${output}`;

if (pdfPassword) {
command = command.concat(` -sPDFPassword=${pdfPassword}`);
}

if (!removePasswordAfterCompression) {
command = command.concat(
` -sOwnerPassword=${pdfPassword} -sUserPassword=${pdfPassword}`
);
}

command = command.concat(` ${file}`);
} else {
tempFile = path.resolve(os.tmpdir(), (Date.now() * 2).toString());

await fs.promises.writeFile(tempFile, file);

command = `${gsModule} -q -dNOPAUSE -dBATCH -dSAFER -dSimulateOverprint=true -sDEVICE=pdfwrite -dCompatibilityLevel=${compatibilityLevel} -dPDFSETTINGS=/${resolution} -dEmbedAllFonts=true -dSubsetFonts=true -dAutoRotatePages=/None -dColorImageDownsampleType=/Bicubic -dColorImageResolution=${imageQuality} -dGrayImageDownsampleType=/Bicubic -dGrayImageResolution=${imageQuality} -dMonoImageDownsampleType=/Bicubic -dMonoImageResolution=${imageQuality} -sOutputFile=${output} ${tempFile}`;
command = `${gsModule} -q -dNOPAUSE -dBATCH -dSAFER -dSimulateOverprint=true -sDEVICE=pdfwrite -dCompatibilityLevel=${compatibilityLevel} -dPDFSETTINGS=/${resolution} -dEmbedAllFonts=true -dSubsetFonts=true -dAutoRotatePages=/None -dColorImageDownsampleType=/Bicubic -dColorImageResolution=${imageQuality} -dGrayImageDownsampleType=/Bicubic -dGrayImageResolution=${imageQuality} -dMonoImageDownsampleType=/Bicubic -dMonoImageResolution=${imageQuality} -sOutputFile=${output}`;

if (pdfPassword) {
command = command.concat(` -sPDFPassword=${pdfPassword}`);
}

if (!removePasswordAfterCompression) {
command = command.concat(
` -sOwnerPassword=${pdfPassword} -sUserPassword=${pdfPassword}`
);
}

command = command.concat(` ${tempFile}`);
}

await exec(command);
Expand Down
8 changes: 8 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,12 @@ export type Options = {
* `You can download binaries in releases section inside any version of this repository.`
*/
gsModule?: string;
/**
* The pdf password
*/
pdfPassword?: string;
/**
* Remove password of a protected pdf, after compression
*/
removePasswordAfterCompression?: boolean;
};

0 comments on commit bc6904d

Please sign in to comment.