pike.git / lib / modules / _Image_PS.pmod

version» Context lines:

pike.git/lib/modules/_Image_PS.pmod:28:   //! to be used instead.   //! @member int(0..1) "force_gs"   //! Forces use of Ghostscript for EPS files instead   //! of Pikes native support.   //! @member int(0..1) "eps_crop"   //! Use -dEPSCrop option to Ghostscript to crop the   //! BoundingBox for a EPS file.   //! @member int(0..1) "cie_color"   //! Use -dUseCIEColor option to Ghostscript for   //! mapping color values through a CIE color space. + //! @member string "file" + //! Filename to read. If this is specified, it will be + //! passed along to the @tt{gs@} binary, so that it can + //! read the file directly. If this is specified @[data] + //! may be set to @expr{0@} (zero).   //! @endmapping -  + //! + //! @note + //! Some versions of @tt{gs@} on MacOS X have problems with + //! reading files on stdin. If this occurrs, try writing to + //! a plain file and specifying the @tt{file@} option. + //! + //! @note + //! @tt{gs@} versions 7.x and earlier don't support rendering + //! of EPSes if they are specified with the @{file@} option. + //! If this is a problem, upgrade to @tt{gs@} version 8.x or + //! later.   object decode( string data, mapping|void options )   { -  +  if(!options) options = ([]); +  if (data) {    if(has_prefix(data, "\xc5\xd0\xd3\xc6")) {    // DOS EPS Binary Header.    int ps_start, ps_len, meta_start, meta_len, tiff_start, tiff_len, sum;    sscanf(data, "%*4c%-4c%-4c%-4c%-4c%-4c%-4c%-2c", -  ps_start, ps_len, meta_start, meta_len, tiff_start, tiff_len, sum); +  ps_start, ps_len, meta_start, meta_len, +  tiff_start, tiff_len, sum);   #if constant(Image.TIFF.decode)    if (tiff_start && tiff_len) { -  // werror("Decoding TIFF.\n"); +     return Image.TIFF.decode(data[tiff_start..tiff_start + tiff_len-1]);    }   #endif    data = data[ps_start..ps_start+ps_len-1];    }    if(data[0..3] != "%!PS")    error("This is not a postscript file!\n");    -  if(!options) options = ([]); +     if(!options->force_gs)    { - #if 1 +     if (has_prefix(data, "%!PS-Adobe-3.0 EPSF-3.0")) {    int width, height, bits, ncols;    int nbws, width2, encoding;    string init_tag;    if ((sscanf(data,    "%*s%%ImageData:%*[ ]%d%*[ ]%d%*[ ]%d%*[ ]%d%"    "*[ ]%d%*[ ]%d%*[ ]%d%*[ ]\"%s\"",    width, height, bits, ncols,    nbws, width2, encoding, init_tag) > 7) &&    (width == width2) && (width > 0) && (height > 0) && (bits == 8) &&
pike.git/lib/modules/_Image_PS.pmod:105:    string grey = "";    int i;    for(i = ncols; i < sizeof(rows); i += ncols+nbws) {    grey += rows[i];    }    return Image.Image(width, height, "rgb", grey, grey, grey);    }    }    }    } -  // return 0; - #endif +     } -  +  }    -  int llx, lly; -  int urx, ury; -  +     Stdio.File fd = Stdio.File();    object fd2 = fd->pipe();       Stdio.File fd3 = Stdio.File();    object fd4 = fd3->pipe();    -  if(sscanf(data, "%*s%%%%BoundingBox: %s%*[\r\n]", string bbox) == 3 && !options->eps_crop) -  { -  int x0,x1,y0,y1; -  sscanf(bbox, "%d %d %d %d", x0,y0,x1,y1 ); -  llx = (int)((x0/72.0) * (options->dpi||100)+0.01); -  lly = (int)((y0/72.0) * (options->dpi||100)+0.01); -  urx = (int)((x1/72.0) * (options->dpi||100)+0.01); -  ury = (int)((y1/72.0) * (options->dpi||100)+0.01); -  } -  +     array command = ({    options->binary||find_in_path("gs")||("/bin/sh -c gs "),    "-quiet",    "-sDEVICE="+(options->device||"ppmraw"), -  // "-sPAPERSIZE=a8", +     "-r"+(options->dpi||100), -  +  "-dBATCH",    "-dNOPAUSE"});       if(options->eps_crop)    command += ({"-dEPSCrop"});       if(options->cie_color)    command += ({"-dUseCIEColor"});       command += ({    "-sOutputFile=-", -  "-", -  "-c quit 2>/dev/null"}); +  options->file || "-", +  "-c", +  "quit", +  });       Process.Process pid = Process.create_process( command, ([    "stdin":fd,    "stdout":fd4,    "stderr":fd4,    ])); -  destruct(fd); -  destruct(fd4); +  fd->close(); +  fd4->close(); +  +  // FIXME: Create a new backend instead of using the default. +     // Kill the gs binary after 30 seconds in case it hangs.    mixed co = call_out(lambda(Process.Process pid) {    if (!pid->status()) {    pid->kill(9);    }    }, 30, pid); -  fd2->write( data ); +  if(!options->file) +  {    if(!has_value(data, "showpage")) -  fd2->write( "\nshowpage\n" ); -  destruct(fd2); -  object i= Image.PNM.decode( fd3->read() ); +  data += "\nshowpage\n"; +  Stdio.sendfile(({ data }), 0, 0, sizeof(data), 0, fd2, +  lambda(int n) { +  fd2->close(); +  }); +  } else { +  fd2->close(); +  } +  string output = ""; +  fd3->set_nonblocking(lambda(mixed ignored, string s) { +  output += s; +  }, 0, +  lambda() { +  fd3->close(); +  destruct(fd3); +  }); +  mixed err = catch { +  while (fd3) { +  Pike.DefaultBackend(1.0); +  } +  }; + #if 0 +  if (err) { +  werror("Backend failed: %s\n", describe_backtrace(err)); +  } + #endif    remove_call_out(co); -  +  int ret_code = pid->wait(); +  if(ret_code) +  error("Ghostscript failed with exit code: %O:\n%s\n", ret_code, output); +  object i= Image.PNM.decode( output );    - #if 1 +  if (data) { +  +  if(data && sscanf(data, "%*s\n%%%%BoundingBox: %s\n", string bbox) == 2 && !options->eps_crop) +  { +  int x0,x1,y0,y1; +  sscanf(bbox, "%d %d %d %d", x0,y0,x1,y1 ); +  int llx = (int)((x0/72.0) * (options->dpi||100)+0.01); +  int lly = (int)((y0/72.0) * (options->dpi||100)+0.01); +  int urx = (int)((x1/72.0) * (options->dpi||100)+0.01); +  int ury = (int)((y1/72.0) * (options->dpi||100)+0.01); +     if(urx && ury)    i = i->mirrory()->copy(llx,lly,urx,ury)->mirrory(); - #endif +  } +  }    return i;   }      //! Calls decode and returns the image in the "image"   //! index of the mapping. This method is present for   //! API reasons.   mapping _decode( string data, mapping|void options )   {    return ([ "image":decode( data,options ) ]);   }