Yalantis/uCrop · error · CImgIOException

load_pdf_external(): Failed to load file '%s' with external

Error message

load_pdf_external(): Failed to load file '%s' with external command 'gs'.

What it means

On Unix, load_pdf_external() opens a pipe to 'gs -sDEVICE=ppmraw ...' with popen() and parses the PNM stream from the pipe. If parsing that stream (load_pnm) throws, this CImgIOException is thrown: ghostscript produced a stream that CImg could not decode as an image.

Source

Thrown at ucrop/src/main/jni/CImg.h:59923

    CImg<T>& load_pdf_external(const char *const filename, const unsigned int resolution=400) {
      if (!filename)
        throw CImgArgumentException(_cimg_instance
                                    "load_pdf_external(): Specified filename is (null).",
                                    cimg_instance);
      CImg<charT> command(1024), filename_tmp(256);
      const CImg<charT> s_filename = CImg<charT>::string(filename)._system_strescape();
#if cimg_OS==1
      std::FILE *file = 0;
      cimg_snprintf(command,command._width,"gs -q -dNOPAUSE -sDEVICE=ppmraw -o - -r%u \"%s\"",
                    resolution,s_filename.data());
      file = popen(command,"r");
      if (file) {
        const unsigned int omode = cimg::exception_mode();
        cimg::exception_mode(0);
        try { load_pnm(file); } catch (...) {
          pclose(file);
          cimg::exception_mode(omode);
          throw CImgIOException(_cimg_instance
                                "load_pdf_external(): Failed to load file '%s' with external command 'gs'.",
                                cimg_instance,
                                filename);
        }
        pclose(file);
        return *this;
      }
#endif
      do {
        cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.ppm",
                      cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());
      } while (cimg::path_exists(filename_tmp));
      cimg_snprintf(command,command._width,"gs -q -dNOPAUSE -sDEVICE=ppmraw -o \"%s\" -r%u \"%s\"",
                    CImg<charT>::string(filename_tmp)._system_strescape().data(),resolution,s_filename.data());
      cimg::system(command,"gs");
      if (!cimg::path_exists(filename_tmp)) {
        cimg::fclose(cimg::fopen(filename,"r"));
        throw CImgIOException(_cimg_instance

View on GitHub (pinned to f788b534b4)

Solutions

  1. Run 'gs -q -dNOPAUSE -sDEVICE=ppmraw -o out.ppm -r400 file.pdf' by hand to see ghostscript's real error.
  2. Check the PDF opens in a viewer / with 'gs -sDEVICE=nullpage file.pdf'; repair or decrypt it first.
  3. Verify a real ghostscript is installed and on PATH ('gs --version').
  4. Lower the -r resolution argument if rendering fails at very high DPI due to memory.
  5. Render to a temp file yourself with gs, then load the PPM/PNG with CImg::load() — this also surfaces gs errors directly.

Example fix

// before
img.load_pdf_external("doc.pdf", 400);
// after
try { img.load_pdf_external("doc.pdf", 400); }
catch (CImgIOException&) {
  if (cimg::system("gs -q -dNOPAUSE -sDEVICE=ppmraw -o doc.ppm -r150 doc.pdf"))
    throw std::runtime_error("ghostscript failed on doc.pdf");
  img.load("doc.ppm");
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!cimg::is_file(path)) throw std::invalid_argument("PDF missing");
if (cimg::system("gs --version","gs")!=0) throw std::runtime_error("ghostscript not installed");

Type guard

bool gsAvailable(){ return cimg::system("gs --version","gs")==0; }

Try / catch

try { img.load_pdf_external(path, res); }
catch (CImgIOException& e) {
  // gs stream undecodable: render to file yourself for a real exit status
  if (cimg::system("gs -q -dNOPAUSE -sDEVICE=ppmraw -o page.ppm -r150 <file>")==0)
    img.load("page.ppm");
  else throw;
}

Prevention

When it happens

Trigger: Calling load_pdf_external(filename, resolution) on Unix where gs ran but its stdout was not a valid PNM stream — gs printed an error to stdout, the PDF was encrypted/corrupt, gs failed mid-render (missing fonts), or the stream was empty.

Common situations: Ghostscript crashing on a malformed or password-protected PDF; 'gs' being a stub script that emits nothing; memory limits killing gs mid-render; gs version producing headers load_pnm cannot parse.

Related errors


AI-assisted analysis of Yalantis/uCrop@f788b534b4 (2026-09-08). Data as JSON: /api/errors/44bc8b272a0b1487. Report an issue: GitHub.