123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375(***********************************************************************)(* *)(* Objective Caml *)(* *)(* Jun Furuse, projet Cristal, INRIA Rocquencourt *)(* *)(* Copyright 1999-2004, *)(* Institut National de Recherche en Informatique et en Automatique. *)(* Distributed only by permission. *)(* *)(***********************************************************************)(* $Id: ps.ml,v 1.2 2008/06/16 22:35:42 furuse Exp $ *)openImagesopenRgb24openUtiltypebounding_box=(int*int*int*int)optionletdebug=tryignore(Sys.getenv"DEBUG_PS");truewith_->falseletdebug_endline=ifdebugthenprerr_endlineelsefun_->()letcheck_headerfilename=letic=open_in_binfilenameintrylets=input_lineicinifString.subs04<>"%!PS"&&String.subs04<>"%PDF"thenraiseExit;close_inic;{header_width=-1;header_height=-1;header_infos=[];}with|_->close_inic;raiseWrong_file_typeletget_bounding_boxfile=letic=open_in_binfileinletbbox=refNoneinletbbox_head="%%BoundingBox:"intrywhiletruedoletline=input_lineicinifString.subline01<>"%"thenraiseExit;tryifString.subline0(String.lengthbbox_head)=bbox_headthenbeginletrem=String.subline(String.lengthbbox_head)(String.lengthline-String.lengthbbox_head)inletx1,y1,x2,y2=matchList.mapint_of_string(Mstring.split_str(function' '->true|_->false)rem)with|[x1;y1;x2;y2]->x1,y1,x2,y2|_->assertfalseinbbox:=Some(x1,y1,x2,y2);raiseExitendwith|_->()done;Nonewith|_->close_inic;!bboxletload_psfilebbox_optoptions=ifnotCamlimages.lib_psthenfailwith"ps is not supported"elseletpath_gs=matchCamlimages.path_gswithSomex->x|_->assertfalseinletresx,resy=matchload_resolutionoptionswith|Some(rx,ry)->rx,ry|None->72.0,72.0inletbbox=matchbbox_optwith|Somebbox->Somebbox|None->get_bounding_boxfileinlettmpfile=Tmpfile.new_tmp_file_name"temp"inletcommand=matchbboxwith|None->Printf.sprintf"%s -sDEVICE=ppmraw -r%fx%f -q -dSAFER -dNOPAUSE \
-sOutputFile=%s %s -c showpage -c quit"path_gsresxresytmpfilefile|Some(x1,y1,x2,y2)->letratiox=resx/.72.0inletratioy=resy/.72.0inletwidth=truncate(float(x2-x1+1)*.ratiox)inletheight=truncate(float(y2-y1+1)*.ratioy)inPrintf.sprintf"%s -sDEVICE=ppmraw -r%fx%f -g%dx%d -q -dSAFER -dNOPAUSE \
-sOutputFile=%s -c %d %d translate -f %s -c showpage -c quit"path_gsresxresywidthheighttmpfile(-x1)(-y1)fileindebug_endlinecommand;ifSys.commandcommand<>0thenbeginTmpfile.remove_tmp_filetmpfile;failwith"gs interpretation failed"endelseletimg=Ppm.loadtmpfile[]inTmpfile.remove_tmp_filetmpfile;imgletloadfileoptions=load_psfileNoneoptionsopenPrintftyperot=Rot0|Rot90|Rot180|Rot270|RotMaxtypeat=|TopLeftoffloat*float|TopRightoffloat*float|BottomLeftoffloat*float|BottomRightoffloat*float|Centeroffloat*float|A4Centertypecrop={mutablecx:int;mutablecy:int;mutablecw:int;mutablech:int;}typesize=|A4MaxSize|DPIoffloat|MaxBoxoffloat*float|MinBoxoffloat*floattypeconf={mutablecrop:cropoption;mutablerot:rot;mutablesize:size;mutablepos:at;mutablemirror:bool;mutablemono:bool;}letsuper_savefileconfcommentsshowpageimages=(* paper properties *)letpaper_width=595.0andpaper_height=842.0andborder=15.0inletbbx1=ref0.0andbby1=ref0.0andbbx2=ref0.0andbby2=ref0.0inletfirst_image=reftrueinletset_bboxx1y1x2y2=if!first_imagethenbeginbbx1:=x1;bby1:=y1;bbx2:=x2;bby2:=y2;first_image:=falseendelsebeginif!bbx1>x1thenbbx1:=x1;if!bby1>y1thenbby1:=y1;if!bbx2<x2thenbbx2:=x2;if!bby2<y2thenbby2:=y2;endin(* printer *)letoc=open_out_binfileinletps=output_stringocs;output_charoc'\n'inletp_=output_stringocinletoutput_image_funcimage=(* maximum printing area *)letlimitw,limith=matchconf.sizewith|MaxBox(w,h)->w,h|MinBox(w,h)->w,h|_->paper_width-.border*.2.0,paper_height-.border*.2.0in(* open file just for getting image size info. *)letimgw,imgh=image.width,image.heightin(* cropping area *)letw,h,x1,y1=matchconf.cropwith|Somecrop->(* check cropping area *)ifcrop.cx+crop.cw>imgwthencrop.cw<-imgw-crop.cx;ifcrop.cy+crop.ch>imghthencrop.ch<-imgh-crop.cy;crop.cw,crop.ch,crop.cx,crop.cy|None->imgw,imgh,0,0in(* auto rotation *)ifconf.rot=RotMaxthenbeginletratio0=letrw=limitw/.floatwandrh=limith/.floathinmatchconf.sizewith|MinBox_->ifrw<rhthenrhelserw|_->ifrw>rhthenrhelserwinletratio90=letrw=limith/.floatwandrh=limitw/.floathinmatchconf.sizewith|MinBox_->ifrw<rhthenrhelserw|_->ifrw>rhthenrhelserwinmatchconf.sizewith|MinBox_->(* smaller is better *)conf.rot<-ifratio0<ratio90thenRot0elseRot90|_->(* larger is better *)conf.rot<-ifratio0>ratio90thenRot0elseRot90end;(* from the point of view of the image *)letlimitw,limith=matchconf.rotwith|Rot0|Rot180->limitw,limith|Rot90|Rot270->limith,limitw|_->assertfalsein(* dpi *)letratio=matchconf.sizewith|DPIdpi->debug_endline(sprintf"%f dpi"dpi);paper_width/.8.26/.dpi|_->letratio=iflimitw/.floatw*.floath<limiththenlimitw/.floatwelselimith/.floathin(*
let dpi = paper_width /. 8.26 /. ratio in
debug_endline (sprintf "%f dpi" dpi);
*)ratioinletrw=floatw*.ratioandrh=floath*.ratioin(* now on the paper ... *)letprw,prh=matchconf.rotwith|Rot0|Rot180->rw,rh|Rot90|Rot270->rh,rw|_->assertfalseinletpaper_x1,paper_y1=letx,y=matchconf.poswith|BottomLeft(x,y)->x,y|TopLeft(x,y)->x,y-.prh|BottomRight(x,y)->x+.prw,y|TopRight(x,y)->x+.prw,y-.prh|Center(x,y)->x-.prw/.2.0,y-.prh/.2.0|A4Center->(paper_width-.prw)/.2.0,(paper_height-.prh)/.2.0inmatchconf.rotwith|Rot0->x,y|Rot180->prw+.x,prh+.y|Rot90->x,prh+.y|Rot270->prw+.x,y|_->assertfalseinset_bboxpaper_x1paper_y1(paper_x1+.prw)(paper_y1+.prh);(fun()->ifcommentsthenp"% Translate for offset";p"gsave";p(sprintf"%f %f translate"paper_x1paper_y1);p(sprintf"%d rotate"beginmatchconf.rotwith|Rot0->0|Rot90->-90|Rot180->-180|Rot270->-270|_->assertfalseend);p(sprintf"%f -%f scale"rwrh);ifcommentsthenp"% Variable to keep one line of raster data";p(sprintf"/scanline %d 3 mul string def"w);ifcommentsthenp"% Image geometry";p(sprintf"%d %d 8"wh);ifcommentsthenp"% Transformation matrix";p(sprintf"[ %d 0 0 %d 0 %d ]"whh);p"{ currentfile scanline readhexstring pop } false 3";p"colorimage";letprevperdec=ref(-1)infory=y1toy1+h-1doletperdec=(y-y1)*10/hinif!prevperdec<>perdecthenbegin(*
debug_endline (sprintf "%d0 %% done" perdec);
*)prevperdec:=perdecend;letbuf=Rgb24.get_scanlineimageyinbeginletprint_pixel=ifnotconf.monothenfunctionx->letadrs=x*3infori=0to2dop_(sprintf"%02x"(buf@%adrs+i))doneelseletmonorgb=(r*256/3+g*256/2+b*256/6)/256infunctionx->letadrs=x*3inletm=mono(buf@%adrs)(buf@%adrs+1)(buf@%adrs+2)infor_i=0to2dop_(sprintf"%02x"m)doneinifnotconf.mirrorthenforx=x1tox1+w-1doprint_pixelxdoneelseforx=x1+w-1downtox1doprint_pixelxdoneend;p""done;debug_endline"100 % done";p"grestore")inletfuncs=List.mapoutput_image_funcimagesin(* Header *)ifcommentsthenbeginp"%!PS-Adobe-3.0";p"%%Creator: Camlimages PS writer by Jun FURUSE";p("%%Title: "^file);p"%%DocumentData: Clean7Bit";p"%%Pages: 1";p(sprintf"%%%%BoundingBox: %f %f %f %f"!bbx1!bby1!bbx2!bby2);p"%%EndComments";p"%%BeginProlog";p"% Use own dictionary to avoid conflicts";p"5 dict begin";p"%%EndProlog";ifshowpagethenp"%%Page: 1 1";end;List.iter(funf->f())funcs;ifshowpagethenp"showpage";ifcommentsthenp"%%Trailer";p"end";ifcommentsthenp"%%EOF";close_outocletdefault_conf={crop=None;rot=Rot0;size=A4MaxSize;pos=A4Center;mirror=false;mono=false;}letsavefile_optionsim=matchimwith|Rgb24img->super_savefiledefault_conftruefalse[img]|_->raiseWrong_image_typelet()=add_methodsPs{check_header=check_header;load=Someload;save=Somesave;load_sequence=None;save_sequence=None;}