Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file bitmap.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581(***********************************************************************)(* *)(* 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: bitmap.ml,v 1.7 2009/07/04 03:39:28 furuse Exp $*)openUtilletdebug=reftrueletdebugss=if!debugthenprerr_endlinesletmaximum_live=ref0(* around 3M words for example *)letmaximum_block_size=ref(!maximum_live/10)(* default 300K words *)(* see Temp to set temp file directory *)typeblock_data=|InMemoryofbytes|Swapped|Destroyedtypeblock={block_width:int;block_height:int;block_size:int;mutableblock_data:block_data;mutablelast_used:float;swap:stringoption}letswappable_blocks=ref[](* wrapped Bytes.create *)letbytes_creates=tryBytes.createswithInvalid_argument_->raiseOut_of_memorymoduleBlock=structtypet={width:int;height:int;x:int;y:int;dump:bytes;}endmoduletypeBitdepth=sigvalbytes_per_pixel:intendmoduleMake(B:Bitdepth)=structopenBtypet={(* The whole size *)width:int;height:int;(* block partition size *)block_size_width:int;block_size_height:int;(* number of block partitions *)blocks_x:int;blocks_y:int;data:blockarrayarray;access:int->int->(bytes*int);}(****************************************************************************)(* Destruction *)(****************************************************************************)letdestroy_t=()(* do nothing... *)letdestroy_blockblk=ifblk.block_data=Destroyedthen()elsebeginmatchblk.swapwith|Somefname->beginmatchblk.block_datawith|Swapped->Sys.removefname;blk.block_data<-Destroyed|InMemory_|Destroyed->()end|None->()end;swappable_blocks:=List.fold_right(funblk'st->ifblk==blk'thenstelseblk'::st)!swappable_blocks[]letfill_bytesbufinit=(* fill bytes with init quickly (hopefully) *)letfulllength=Bytes.lengthbufinlethalflength=fulllength/2inletrecsub=function|0->letlen=Bytes.lengthinitinBytes.unsafe_blitinit0buf0len;sublen|xwhenx<=halflength->Bytes.unsafe_blitbuf0bufxx;sub(x*2)|x(* when x > halflength *)->Bytes.unsafe_blitbuf0bufx(fulllength-x)insub0letcheck_initinit=matchinitwith|Somev->ifBytes.lengthv<>bytes_per_pixelthenfailwith"bitmap fill value is incorrect"|None->()letmemorywidthheightinit=(* try to have it whole in memory *)check_initinit;(* we can have hsize lines at maximum in one bytes *)lethsize=Sys.max_string_length/(width*bytes_per_pixel)inlethsize=minheighthsizein(* how many caml bytess required? *)letblocks_y=(height-1)/hsize+1inletbuf_size_heights=Array.initblocks_y(funby->letheight=ifby=blocks_y-1thenletm=heightmodhsizeinifm=0thenhsizeelsemelsehsizein(* CR jfuruse: check overflow *)letsize=width*height*bytes_per_pixelinbytes_createsize,size,height)inletbufs=Array.map(fun(buf,_,_)->buf)buf_size_heightsinbeginmatchinitwith|Somev->Array.iter(funs->fill_bytessv)bufs;|None->()end;{width=width;height=height;block_size_width=width;block_size_height=hsize;blocks_x=1;blocks_y=blocks_y;data=[|Array.initblocks_y(funh->letbuf,size,height=buf_size_heights.(h)in{block_width=width;block_height=height;block_data=InMemorybuf;block_size=size;last_used=0.0;swap=None;})|];access=ifblocks_y=1then(funxy->bufs.(0),(y*width+x)*bytes_per_pixel)else(funxy->bufs.(y/hsize),((ymodhsize)*width+x)*bytes_per_pixel)}letswap_out=function|{block_data=Destroyed}->failwith"swap_out: Already destroyed"|{swap=None}->failwith"No swap file set"|{swap=Somefname;block_data=InMemorys;block_size=size}asblk->begintrydebugs(Printf.sprintf"swap out %s"fname(* blk.block_size*));letoc=open_out_binfnameinoutputocs0size;close_outoc;blk.block_data<-Swappedwith|e->prerr_endline"Swap-out failed";raiseeend|_->()lettouch_blockblk=blk.last_used<-Sys.time()letswap_out_eldestwords=letsorted=List.sort(funb1b2->compareb1.last_usedb2.last_used)!swappable_blocksinletrecswappersortedi=matchsortedwith|[]->()|x::xs->swap_outx;swapperxs(i-(x.block_size+Camlimages.word_size-1)/Camlimages.word_size)inswappersortedwordsletrequirebytes=letwords=(bytes+Camlimages.word_size-1)/Camlimages.word_sizeinletstat=Gc.stat()inletover=stat.Gc.live_words+words-!maximum_liveinifover>0thenswap_out_eldestoverletswap_in=function|{block_data=Destroyed}->raise(Failure"swap_in: Already destroyed")|{block_data=InMemorys}asblk->touch_blockblk;s|{swap=Somefname;block_data=Swapped;block_size=size}asblk->begintrydebugs("swap in "^fname);requiresize;letic=open_in_binfnameinlets=bytes_createsizeinreally_inputics0size;close_inic;blk.block_data<-InMemorys;Sys.removefname;touch_blockblk;swith|e->prerr_endline(Printf.sprintf"Swap-in failed (%s)"(Printexc.to_stringe));raiseeend|_->assertfalseletalloc_swappable_blockwidthheightinit=(* CR jfuruse: check overflow *)letsize=bytes_per_pixel*width*heightinrequiresize;lets=bytes_createsizeinbeginmatchinitwith|Somev->fill_bytessv|None->()end;letblk={block_width=width;block_height=height;block_size=size;block_data=InMemorys;last_used=Sys.time();swap=Some(Tmpfile.new_tmp_file_name"swap")}inGc.finalisedestroy_blockblk;swappable_blocks:=blk::!swappable_blocks;blk(****************************************************************************)(* Creation functions *)(****************************************************************************)letcreatewidthheightinit=if!maximum_live<=0thenmemorywidthheightinitelsebegincheck_initinit;(* determine the block size *)letrecget_block_sizep=(* CR jfuruse: check overflow *)letwhole_words=(bytes_per_pixel*width*height+Camlimages.word_size-1)/Camlimages.word_sizeinletpp=p*pinifwhole_words/pp>!maximum_block_sizethenget_block_size(p+1)elsepinletrecalloc_test_blockp=letblock_size_width=width/p+(ifwidthmodp<>0then1else0)andblock_size_height=height/p+(ifheightmodp<>0then1else0)intry(* CR jfuruse: check overflow *)p,bytes_create(block_size_width*block_size_height*bytes_per_pixel)with|Out_of_memory->alloc_test_block(p+1)inletblocks,test_block=alloc_test_block(get_block_size1)in(* use the block so that it is not GCed too early *)test_block<<0&'0';(* Create bitmap *)letblocks_x=blocksandblocks_y=blocksinletblock_size_width=width/blocks_x+(ifwidthmodblocks_x<>0then1else0)andblock_size_height=height/blocks_x+(ifheightmodblocks_x<>0then1else0)indebugs(Printf.sprintf"creating %d x %d blocks (%dx%d)"blocksblocksblock_size_widthblock_size_height);letdata=(* CR jfuruse: check overflow *)Array.initblocks_x(funx->Array.initblocks_y(funy->letw=ifx<>blocks_x-1thenblock_size_widthelsewidth-block_size_width*(blocks_x-1)andh=ify<>blocks_y-1thenblock_size_heightelseheight-block_size_height*(blocks_y-1)inalloc_swappable_blockwhinit))inlett={width=width;height=height;block_size_width=block_size_width;block_size_height=block_size_height;blocks_x=blocks_x;blocks_y=blocks_y;data=data;access=(ifblocks_x=1&&blocks_y=1thenbeginletthe_blk=data.(0).(0)infunxy->letstr=swap_inthe_blkinletpos=(the_blk.block_width*(ymodblock_size_height)+(xmodblock_size_width))*bytes_per_pixelinstr,posendelsebeginfunxy->letbx=x/block_size_widthandby=y/block_size_heightinletblk=data.(bx).(by)inletstr=swap_inblkinletpos=(blk.block_width*(ymodblock_size_height)+(xmodblock_size_width))*bytes_per_pixelinstr,posend);}intendletcreate_withwidthheightbuf={width=width;height=height;block_size_width=width;block_size_height=height;blocks_x=1;blocks_y=1;data=[|[|{block_width=width;block_height=height;block_data=InMemorybuf;(* CR jfuruse: check overflow *)block_size=width*height*bytes_per_pixel;last_used=0.0;swap=None;}|]|];access=(funxy->buf,(y*width+x)*bytes_per_pixel);}letcreate_with_scanlineswidthheightscanlines=(* CR jfuruse: check overflow *)letblock_size=width*bytes_per_pixelinifArray.lengthscanlines<>heightthenbeginFormat.eprintf"scanline error %d (height=%d) (bpp=%d)@."(Array.lengthscanlines)heightbytes_per_pixel;assertfalseend;fory=0toheight-1doifBytes.lengthscanlines.(y)<>block_sizethenbeginFormat.eprintf"scanline error %d = block_size %d = %d * %d (y=%d)@."(Bytes.lengthscanlines.(y))block_sizewidthbytes_per_pixely;assertfalseenddone;{width=width;height=height;block_size_width=width;block_size_height=1;blocks_x=1;blocks_y=height;data=[|Array.mapi(fun_yscanline->{block_width=width;block_height=1;block_data=InMemoryscanline;block_size=block_size;last_used=0.0;swap=None})scanlines|];access=(funxy->scanlines.(y),x*bytes_per_pixel);}(****************************************************************************)(* Tool functions *)(****************************************************************************)letaccesst=t.access(* strip access *)(* Here, "strip" is a rectangle region with height 1 *)letget_striptxyw=(* No region checks for performance. You should wrap this to make safe
in your applications. *)matcht.blocks_x,t.blocks_ywith|1,_->(* optimized *)letbly=y/t.block_size_heightinlety'=ymodt.block_size_heightinletblk=t.data.(0).(bly)inletsrc=swap_inblkinletsize=w*bytes_per_pixelinletadrs=(blk.block_width*y'+x)*bytes_per_pixelinletstr=bytes_createsizeinBytes.unsafe_blitsrcadrsstr0size;str|_,_->letbly=y/t.block_size_heightinlety'=ymodt.block_size_heightinletstr=bytes_create(w*bytes_per_pixel)inletblx_start=x/t.block_size_widthinletblx_last=(x+w-1)/t.block_size_widthinforblx=blx_starttoblx_lastdoletblk=t.data.(blx).(bly)inletsrc=swap_inblkinletx1=ifblx=blx_startthenxmodt.block_size_widthelse0inletx2=ifblx=blx_lastthen(x+w-1)modt.block_size_widthelse(blk.block_width-1)inletw'=x2-x1+1inletsize=w'*bytes_per_pixelinletadrs=(blk.block_width*y'+x1)*bytes_per_pixelinletoffset=ifblx=blx_startthen0else(t.block_size_width*blx-x)*bytes_per_pixelinBytes.unsafe_blitsrcadrsstroffsetsizedone;strletset_striptxywstr=(* No region checks for performance. You should wrap this to make safe
in your applications. *)matcht.blocks_x,t.blocks_ywith|1,_->(* optimized *)letbly=y/t.block_size_heightinlety'=ymodt.block_size_heightinletblk=t.data.(0).(bly)inletdst=swap_inblkinletsize=w*bytes_per_pixelinletadrs=(blk.block_width*y'+x)*bytes_per_pixelinBytes.unsafe_blitstr0dstadrssize|_,_->letbly=y/t.block_size_heightinlety'=ymodt.block_size_heightinletblx_start=x/t.block_size_widthinletblx_last=(x+w-1)/t.block_size_widthinforblx=blx_starttoblx_lastdoletblk=t.data.(blx).(bly)inletdst=swap_inblkinletx1=ifblx=blx_startthenxmodt.block_size_widthelse0inletx2=ifblx=blx_lastthen(x+w-1)modt.block_size_widthelse(blk.block_width-1)inletw'=x2-x1+1inletsize=w'*bytes_per_pixelinletadrs=(blk.block_width*y'+x1)*bytes_per_pixelinletoffset=ifblx=blx_startthen0else(t.block_size_width*blx-x)*bytes_per_pixelinBytes.unsafe_blitstroffsetdstadrssizedone(* scanline access (special case of strip access) *)letget_scanlinety=get_stript0yt.width(* returns the scan line address and how many lines we can get *)letget_scanline_ptrt=matcht.blocks_x,t.blocks_ywith|1,1->(* optimized *)Some(funy->letblk=t.data.(0).(0)inletsrc=swap_inblkinletadrs=(blk.block_width*y)*bytes_per_pixelin(src,adrs),blk.block_height-y)|1,_->(* optimized *)Some(funy->letbly=y/t.block_size_heightinlety'=ymodt.block_size_heightinletblk=Array.unsafe_get(Array.unsafe_gett.data0)blyinletsrc=swap_inblkinletadrs=(blk.block_width*y')*bytes_per_pixelin(src,adrs),blk.block_height-y')|_,_->Noneletset_scanlinetystr=(* CR jfuruse: check overflow *)ifBytes.lengthstr<>t.width*B.bytes_per_pixelthenfailwith(Printf.sprintf"scan=%d width=%d bbp=%d"(Bytes.lengthstr)t.widthB.bytes_per_pixel);set_stript0yt.widthstr(* dump : of course this does not work for large images *)letdumpt=(* CR jfuruse: check overflow *)letsize=bytes_per_pixel*t.width*t.heightinmatcht.blocks_x,t.blocks_ywith|1,1->swap_int.data.(0).(0)|1,h->lets=bytes_createsizeinletscanline_size=bytes_per_pixel*t.widthinfory=0toh-1doletstr=swap_int.data.(0).(y)inBytes.unsafe_blitstr0s(scanline_size*y)scanline_sizedone;s|w,h->lets=bytes_createsizeinforx=0tow-1dofory=0toh-1doletblk=t.data.(x).(y)inletstr=swap_inblkinletscanline_size=bytes_per_pixel*blk.block_widthinfori=0toblk.block_height-1doBytes.unsafe_blitstr(scanline_size*i)s(((y*t.block_size_height+i)*t.width+x*t.block_size_width)*bytes_per_pixel)scanline_sizedonedonedone;s(* sub-bitmap *)letsubtxywh=Region.checkt.widtht.heightxy;Region.checkt.widtht.height(x+w-1)(y+h-1);letdst=createwhNoneintryfori=0toh-1doset_scanlinedsti(get_striptx(y+i)w)done;dstwith|e->destroydst;raiseeletcopyt=subt00t.widtht.heightletblitsrcsxsydstdxdywh=Region.checksrc.widthsrc.heightsxsy;Region.checksrc.widthsrc.height(sx+w-1)(sy+h-1);Region.checkdst.widthdst.heightdxdy;Region.checkdst.widthdst.height(dx+w-1)(dy+h-1);fori=0toh-1doset_stripdstdx(dy+i)w(get_stripsrcsx(sy+i)w)doneletblocksbmp=bmp.blocks_x,bmp.blocks_yletdump_blockbmpxy=letblk=bmp.data.(x).(y)inletat_x=x*bmp.block_size_widthinletat_y=y*bmp.block_size_heightinletw=ifx=bmp.blocks_x-1thenbmp.width-at_xelsebmp.block_size_widthinleth=ify=bmp.blocks_y-1thenbmp.height-at_yelsebmp.block_size_heightin{Block.width=w;height=h;x=at_x;y=at_y;dump=swap_inblk}end