Skip to content

Error when testing (read filled pdf) on Docker node:14.5.0-alpine3.12 #93

Description

@Brian-McBride

Error when testing on Docker node:14.5.0-alpine3.12

Overview

When we fill out a PDF in a docker container, it seems to work. Reading back in the filed out PDF results in an error:

"Error (2651941): Missing 'endstream' or incorrect stream length"
"Error: Couldn't find trailer dictionary"
"Error (2651941): Missing 'endstream' or incorrect stream length"
"Error: Couldn't find trailer dictionary"
"Error: Couldn't read xref table"

NOTE: This error does not happen on OSX. Everything works as expected in our dev environment.

Docker Build

During deployment, we are trying to get the smallest file down for the Docker image.

Node Alpine is "Size": 117240360
Our docker is now "Size": 726653809

This is theDockerfile:

FROM node:14.5.0-alpine3.12

RUN apk add --no-cache \
    alpine-sdk \
    build-base \
    cairo \
    cairo-dev \
    poppler \
    poppler-qt5-dev

CMD [ "node" ]

So... pretty simple. All those dev files do take up a lot of space to be sure.

Possible Issues?

During the npm install we are seeing a number of warnings that I thought we could share:

> pdf-fill-form@5.0.1 install /app/node_modules/pdf-fill-form
> node-gyp rebuild

make: Entering directory '/app/node_modules/pdf-fill-form/build'
  CXX(target) Release/obj.target/pdf_fill_form/src/pdf-fill-form.o
In file included from ../src/pdf-fill-form.cc:1:
../../nan/nan.h: In function 'void Nan::AsyncQueueWorker(Nan::AsyncWorker*)':
../../nan/nan.h:2294:62: warning: cast between incompatible function types from 'void (*)(uv_work_t*)' {aka 'void (*)(uv_work_s*)'} to 'uv_after_work_cb' {aka 'void (*)(uv_work_s*, int)'} [-Wcast-function-type]
 2294 |     , reinterpret_cast<uv_after_work_cb>(AsyncExecuteComplete)
      |                                                              ^
In file included from ../../nan/nan.h:56,
                 from ../src/pdf-fill-form.cc:1:
../src/pdf-fill-form.cc: At global scope:
/root/.cache/node-gyp/14.5.0/include/node/node.h:738:43: warning: cast between incompatible function types from 'void (*)(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE)' {aka 'void (*)(v8::Local<v8::Object>)'} to 'node::addon_register_func' {aka 'void (*)(v8::Local<v8::Object>, v8::Local<v8::Value>, void*)'} [-Wcast-function-type]
  738 |       (node::addon_register_func) (regfunc),                          \
      |                                           ^
/root/.cache/node-gyp/14.5.0/include/node/node.h:772:3: note: in expansion of macro 'NODE_MODULE_X'
  772 |   NODE_MODULE_X(modname, regfunc, NULL, 0)  // NOLINT (readability/null_usage)
      |   ^~~~~~~~~~~~~
../src/pdf-fill-form.cc:27:1: note: in expansion of macro 'NODE_MODULE'
   27 | NODE_MODULE(pdf_fill_form, InitAll)
      | ^~~~~~~~~~~
  CXX(target) Release/obj.target/pdf_fill_form/src/NodePopplerAsync.o
In file included from ../src/NodePopplerAsync.cc:1:
../../nan/nan.h: In function 'void Nan::AsyncQueueWorker(Nan::AsyncWorker*)':
../../nan/nan.h:2294:62: warning: cast between incompatible function types from 'void (*)(uv_work_t*)' {aka 'void (*)(uv_work_s*)'} to 'uv_after_work_cb' {aka 'void (*)(uv_work_s*, int)'} [-Wcast-function-type]
 2294 |     , reinterpret_cast<uv_after_work_cb>(AsyncExecuteComplete)
      |                                                              ^
  CXX(target) Release/obj.target/pdf_fill_form/src/NodePoppler.o
In file included from ../src/NodePoppler.cc:1:
../../nan/nan.h: In function 'void Nan::AsyncQueueWorker(Nan::AsyncWorker*)':
../../nan/nan.h:2294:62: warning: cast between incompatible function types from 'void (*)(uv_work_t*)' {aka 'void (*)(uv_work_s*)'} to 'uv_after_work_cb' {aka 'void (*)(uv_work_s*, int)'} [-Wcast-function-type]
 2294 |     , reinterpret_cast<uv_after_work_cb>(AsyncExecuteComplete)
      |                                                              ^
../src/NodePoppler.cc: In function 'Nan::NAN_METHOD_RETURN_TYPE ReadBufferSync(Nan::NAN_METHOD_ARGS_TYPE)':
../src/NodePoppler.cc:539:7: warning: variable 'n' set but not used [-Wunused-but-set-variable]
  539 |   int n = 0;
      |       ^
../src/NodePoppler.cc: In function 'Nan::NAN_METHOD_RETURN_TYPE ReadSync(Nan::NAN_METHOD_ARGS_TYPE)':
../src/NodePoppler.cc:565:7: warning: variable 'n' set but not used [-Wunused-but-set-variable]
  565 |   int n = 0;
      |       ^
  SOLINK_MODULE(target) Release/obj.target/pdf_fill_form.node
  COPY Release/pdf_fill_form.node
make: Leaving directory '/app/node_modules/pdf-fill-form/build'
npm WARN savvy-docker-node@1.0.0 No repository field.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@2.1.3 (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.1.3: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})

For our tests, we are running this docker file called testing.Dockerfile

FROM docker-pdf-fill-form:testing

WORKDIR /app/
COPY . /app/

RUN npm install
CMD [ "npm", "run", "test" ]

And, since we are here, this is the unit test:

const { readBuffer, writeBuffer } = require('pdf-fill-form');
const fs = require('fs');

describe('Get Fields from PDF', () => {
  const testFilename = 'unlocked.pdf';
  const testWriteFilename = 'filled.pdf';
  const testValue = 'COUNTY_SET_VALUE_FROM_TEST';

  it('Returns fields', async () => {
    const pdfSource1 = fs.readFileSync(`${__dirname}/${testFilename}`);
    const result = await readBuffer(pdfSource1);
    console.log(result[1]);
    expect(result[1].page).toEqual(0);
    expect(result[1].id).toEqual(65537);
    expect(result[1].type).toEqual('text');
    expect(result[1].name).toEqual('PI_County');
    expect(result[1].value).toEqual('');
  });

  it('Can fill out a form', async () => {
    const pdfSource1 = fs.readFileSync(`${__dirname}/${testFilename}`);
    const filledPdf = await writeBuffer(
      pdfSource1,
      { PI_County: 'COUNTY_SET_VALUE_FROM_TEST' },
      { save: 'pdf', antialias: true }
    );

    expect(filledPdf).toBeDefined();
    
    fs.writeFileSync(`${__dirname}/${testWriteFilename}`, filledPdf);

    const pdfSource2 = fs.readFileSync(`${__dirname}/${testWriteFilename}`);
    const result = await readBuffer(pdfSource2);
    console.log(result[1]);
    expect(result[1].page).toEqual(0);
    expect(result[1].id).toEqual(65537);
    expect(result[1].type).toEqual('text');
    expect(result[1].name).toEqual('PI_County');
    expect(result[1].value).toEqual(testValue);
  });
});

I'll work on getting this on github to easily run, but really you can create both Dockerfile and testing.Dockerfile.
Create a node project with the the test jest --verbose and add in the above test in the same directory as your PDF file. I use __tests__.
Then here are my docker commands:

Build main Docker Image: docker build -t docker-pdf-fill-form:testing .

Build testing Docker Image: docker build -t form-test -f testing.Dockerfile .

Run testing Docker Image: docker run form-test

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions