a580e12000-09-27Fredrik Hübinette (Hubbe) #pike __REAL_VERSION__
a20af62000-09-26Fredrik Hübinette (Hubbe) 
6562532002-12-14Martin Nilsson //! @appears Image.PS
4cd7152002-11-15Martin Nilsson //! Codec for the Adobe page description language PostScript. //! Uses Ghostscript for decoding. static string find_in_path( string file )
d7bd251999-04-15Per Hedbor { string path=getenv("PATH"); foreach(path ? path/":" : ({}) , path) if(file_stat(path=combine_path(path,file))) return path; }
4cd7152002-11-15Martin Nilsson //! Decodes the postscript @[data] into an image object //! using Ghostscript. //! @param options //! Optional decoding parameters. //! @mapping //! @member int "dpi" //! The resolution the image should be rendered in. //! Defaults to 100. //! @member string "device" //! The selected Ghostscript device. Defaults to "ppmraw". //! @member string "binary" //! Path to the Ghostscript binary to be used. If missing //! the environment paths will be searched for a file "gs" //! to be used instead. //! @endmapping
d7bd251999-04-15Per Hedbor object decode( string data, mapping|void options ) {
4cd7152002-11-15Martin Nilsson  if(data[0..3] != "%!PS") error("This is not a postscript file!\n");
6386572006-09-13Henrik Grubbström (Grubba)  if (has_prefix(data, "%!PS-Adobe-3.0 EPSF-3.0")) { int width, height, bits, ncols; int nbws, width2, unknown; string init_tag; if ((sscanf(data, "%*s%%ImageData:%*[ ]%d%*[ ]%d%*[ ]%d%*[ ]%d%" "*[ ]%d%*[ ]%d%*[ ]%d%*[ ]\"%s\"", width, height, bits, ncols, nbws, width2, unknown, init_tag) > 7) && (width == width2) && (width > 0) && (height > 0) && (bits == 8)) { // Image data present. int len; string term; string raw; if ((sscanf(data, "%*s%%%%BeginBinary:%*[ ]%d%[\r\n]%s", len, term, raw) == 5) && (len>0) && has_prefix(raw, init_tag + term)) { raw = raw[sizeof(init_tag+term)..len-1]; if (sizeof(raw) == width*height*(ncols+nbws)) { array(string) rows = raw/width; if (ncols) { array(string) channels = allocate(ncols, ""); int c; for (c = 0; c < ncols; c++) { int i; for (i = c; i < sizeof(rows); i += ncols+nbws) { channels[c] += rows[i]; } } return Image.Image(width, height, "cmyk", @channels); } 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); } } } }
d7bd251999-04-15Per Hedbor  if(!options) options = ([]); int llx, lly; int urx, ury;
4cd7152002-11-15Martin Nilsson  Stdio.File fd = Stdio.File(); object fd2 = fd->pipe();
d7bd251999-04-15Per Hedbor 
4cd7152002-11-15Martin Nilsson  Stdio.File fd3 = Stdio.File(); object fd4 = fd3->pipe();
d7bd251999-04-15Per Hedbor 
4cd7152002-11-15Martin Nilsson  if(sscanf(data, "%*s\n%%%%BoundingBox: %s\n", string bbox) == 2)
d7bd251999-04-15Per Hedbor  { int x0,x1,y0,y1; sscanf(bbox, "%d %d %d %d", x0,y0,x1,y1 );
3044d11999-04-22Per Hedbor  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);
d7bd251999-04-15Per Hedbor  } array command = ({
4cd7152002-11-15Martin Nilsson  options->binary||find_in_path("gs")||("/bin/sh -c gs "),
d7bd251999-04-15Per Hedbor  "-quiet", "-sDEVICE="+(options->device||"ppmraw"),
3044d11999-04-22Per Hedbor  "-r"+(options->dpi||100),
d7bd251999-04-15Per Hedbor  "-dNOPAUSE", "-sOutputFile=-", "-", "-c quit 2>/dev/null" }); Process.create_process( command, ([ "stdin":fd, "stdout":fd3, "stderr":fd3, ])); destruct(fd); destruct(fd3); fd2->write( data );
4cd7152002-11-15Martin Nilsson  if(!has_value(data, "showpage"))
3044d11999-04-22Per Hedbor  fd2->write( "\nshowpage\n" );
d7bd251999-04-15Per Hedbor  destruct(fd2); object i= Image.PNM.decode( fd4->read() ); if(urx && ury) i = i->mirrory()->copy(llx,lly,urx,ury)->mirrory(); return i; }
4cd7152002-11-15Martin Nilsson //! Calls decode and returns the image in the "image" //! index of the mapping. This method is present for //! API reasons.
d7bd251999-04-15Per Hedbor mapping _decode( string data, mapping|void options ) { return ([ "image":decode( data,options ) ]); }
3044d11999-04-22Per Hedbor 
4cd7152002-11-15Martin Nilsson //! Encodes the image object @[img] as a postscript 3.0 file. //! @param options //! Optional extra encoding parameters. //! @mapping //! @member int "dpi" //! The resolution of the encoded image. Defaults to 100. //! @member int(0..1) "eps" //! If the resulting image should be an eps instead of ps. //! Defaults to 0, no. //! @endmapping
3044d11999-04-22Per Hedbor string encode( object img, mapping|void options ) { int w = img->xsize(), h = img->ysize(); string i = (string)img; float scl = 72.0 / ((options&&options->dpi)||100); img = 0; string res; res =("%!PS-Adobe-3.0\n" "%%DocumentData: Clean8Bit\n" "%%BoundingBox: 0 0 "+(int)ceil(w*scl)+" "+(int)ceil(h*scl)+"\n" "%%EndComments\n" "%%BeginProlog\n" "30 dict begin\n" "/tmpstr 256 string def\n" "/dnl{currentfile tmpstr readline pop pop}bind def\n" "/di{dnl gsave scale 2 copy pop string/pxdat exch def\n" " 2 copy 8 [4 2 roll dup 0 0 4 2 roll neg 0 3 2 roll] {currentfile\n" " pxdat readstring pop}false 3 colorimage grestore}bind def\n" "%%EndProlog\n"); res += sprintf("%d %d %f %f di\n", w, h, scl*w, scl*h); res +="%%BeginData "+sizeof(i)+" Binary Bytes\n" + i +"\n%%EndData\n"; if( !options || !options->eps ) res += "showpage\n"; res += "%%Trailer\n" "end\n" "%%EOF\n"; return res; }
4cd7152002-11-15Martin Nilsson //! Same as encode. Present for API reasons.
3044d11999-04-22Per Hedbor function _encode = encode;