123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339(*
* Copyright 2011 The Savonet Team
*
* This file is part of ocaml-mm.
*
* ocaml-mm is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* ocaml-mm is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with ocaml-mm; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* As a special exception to the GNU Library General Public License, you may
* link, statically or dynamically, a "work that uses the Library" with a publicly
* distributed version of the Library to produce an executable file containing
* portions of the Library, and distribute that executable file under terms of
* your choice, without any of the additional requirements listed in clause 6
* of the GNU Library General Public License.
* By "a publicly distributed version of the Library", we mean either the unmodified
* Library as distributed by The Savonet Team, or a modified version of the Library that is
* distributed under the conditions defined in clause 3 of the GNU Library General
* Public License. This exception does not however invalidate any other reasons why
* the executable file might be covered by the GNU Library General Public License.
*
*)openImageBasemoduleBGRA=ImageBGRAmoduleColor=structtypet=int*int*int*intendtypedata=(int,Bigarray.int8_unsigned_elt,Bigarray.c_layout)Bigarray.Array1.ttypet={(* Order matters for C callbacks! *)data:data;width:int;height:int;stride:int;}letwidthbuf=buf.widthletheightbuf=buf.heightletdimensionsbuf=(buf.width,buf.height)letdatabuf=buf.dataletsizebuf=Bigarray.Array1.dimbuf.dataletstridebuf=buf.strideletmake?stridewidthheightdata=letstride=matchstridewithSomev->v|None->4*widthin{data;width;height;stride}letcreate?stridewidthheight=letstride=matchstridewithSomev->v|None->4*widthinletstride,data=Data.rounded_planestrideheightinmake~stridewidthheightdataletcopyf=letnf=create~stride:f.stridef.widthf.heightinBigarray.Array1.blitf.datanf.data;nf(* Remove the optional stride argument. *)letcreatewidthheight=createwidthheightexternalblit:t->t->unit="caml_rgb_blit"externalblit_off:t->t->int->int->bool->unit="caml_rgb_blit_off"externalblit_off_scale:t->t->int*int->int*int->bool->unit="caml_rgb_blit_off_scale"letblit_allsrcdst=assert(src.width=dst.width&&src.height=dst.height&&src.stride=dst.stride);blitsrcdstletblit?(blank=true)?(x=0)?(y=0)?w?hsrcdst=match(w,h)with|None,None->blit_offsrcdstxyblank|Somew,Someh->blit_off_scalesrcdst(x,y)(w,h)blank|_,_->assertfalseexternalfill_all:t->Color.t->unit="caml_rgb_fill"externalblank_all:t->unit="caml_rgb_blank"letblank=blank_allexternalfill_alpha:t->int->unit="caml_rgb_fill_alpha"externalof_RGB24_string:t->string->unit="caml_rgb_of_rgb8_string"letof_RGB24_stringdatawidth=letheight=String.lengthdata/3/widthinletans=createwidthheightinof_RGB24_stringansdata;ansexternalof_BGRA:t->BGRA.t->unit="caml_rgba_of_bgra"letof_BGRAbgra=letimg=createbgra.BGRA.widthbgra.BGRA.heightinof_BGRAimgbgra;imgexternalto_BGRA:BGRA.t->t->unit="caml_rgba_of_bgra"letto_BGRAimg=letbgra=BGRA.createimg.widthimg.heightinto_BGRAbgraimg;bgraexternalto_Gray8:t->Data.t->unit="caml_mm_RGBA8_to_Gray8"letto_Gray8rgbgray=to_Gray8rgbgray.Gray8.dataletto_Gray8_creatergb=letgray=Gray8.create(widthrgb)(heightrgb)into_Gray8rgbgray;grayexternalget_pixel:t->int->int->Color.t="caml_rgb_get_pixel"externalset_pixel:t->int->int->Color.t->unit="caml_rgb_set_pixel"letset_pixelimgij=assert(0<=i&&i<img.width);assert(0<=j&&j<img.height);set_pixelimgijletget_pixel_rgba=get_pixelletset_pixel_rgba=set_pixelexternalrandomize_all:t->unit="caml_rgb_randomize"letrandomize=randomize_allmoduleScale=structtypekind=Linear|Bilinearexternalscale_coef:t->t->int*int->int*int->unit="caml_rgb_scale"externalbilinear_scale_coef:t->t->float->float->unit="caml_rgb_bilinear_scale"letscale_coef_kindksrcdst(dw,sw)(dh,sh)=matchkwith|Linear->scale_coefsrcdst(dw,sw)(dh,sh)|Bilinear->letx=floatdw/.floatswinlety=floatdh/.floatshinbilinear_scale_coefsrcdstxyletonto?(kind=Linear)?(proportional=false)srcdst=letsw,sh=(src.width,src.height)inletdw,dh=(dst.width,dst.height)inifdw=sw&&dh=shthenblit_allsrcdstelseifnotproportionalthenscale_coef_kindkindsrcdst(dw,sw)(dh,sh)else(letn,d=ifdh*sw<sh*dwthen(dh,sh)else(dw,sw)inscale_coef_kindkindsrcdst(n,d)(n,d))letcreate?kind?(copy=true)?proportionalsrcwh=if(notcopy)&&widthsrc=w&&heightsrc=hthensrcelse(letdst=createwhinonto?kind?proportionalsrcdst;dst)endletscale?proportionalsrcdst=Scale.onto?proportionalsrcdstexternalto_BMP:t->string="caml_rgb_to_bmp"externalto_RGB24_string:t->string="caml_image_to_rgb24"exceptionInvalid_formatofstringletof_PPM?alphadata=letw,h,d,o=try(* TODO: make it useable without bound checks *)assert(data.[0]='P');assert(data.[1]='6');assert(data.[2]='\n');letn=ref3inletread_int()=letans=ref0inlet(!!)=int_of_charinwhile!!'0'<=!!(data.[!n])&&!!(data.[!n])<=!!'9'doans:=(!ans*10)+!!(data.[!n])-!!'0';incrndone;assert(data.[!n]=' '||data.[!n]='\n');incrn;!ansinifdata.[!n]='#'then(incrn;whiledata.[!n]<>'\n'doincrndone;incrn);letw=read_int()inleth=read_int()inletd=read_int()in(w,h,d,!n)with_->raise(Invalid_format"Not a PPM file.")inletdatalen=String.lengthdata-oinifd<>255thenraise(Invalid_format(Printf.sprintf"Files of color depth %d are not handled."d));ifdatalen<3*w*hthenraise(Invalid_format(Printf.sprintf"Got %d bytes of data instead of expected %d."datalen(3*w*h)));letans=createwhinforj=0toh-1dofori=0tow-1doletr,g,b=(int_of_chardata.[o+(3*((j*w)+i))+0],int_of_chardata.[o+(3*((j*w)+i))+1],int_of_chardata.[o+(3*((j*w)+i))+2])inleta=matchalphawith|Some(ra,ga,ba)->ifr=ra&&g=ga&&b=bathen0x00else0xff|None->0xffinset_pixelansij(r,g,b,a)donedone;ansexternalto_int_image:t->intarrayarray="caml_rgb_to_color_array"(*
let to_int_image buf =
let w = buf.width in
let h = buf.height in
Array.init
h
(fun j ->
Array.init
w
(fun i ->
let r,g,b,a = get_pixel buf i j in
(r lsl 16) + (g lsl 8) + b
)
)
*)externaladd:t->t->unit="caml_rgb_add"letadd_fast=addexternaladd_off:t->t->int->int->unit="caml_rgb_add_off"externaladd_off_scale:t->t->int*int->int*int->unit="caml_rgb_add_off_scale"letadd?(x=0)?(y=0)?w?hsrcdst=match(w,h)with|None,None->ifx=0&&y=0&&src.width=dst.width&&src.height=dst.heightthenadd_fastsrcdstelseadd_offsrcdstxy|Somew,Someh->add_off_scalesrcdst(x,y)(w,h)|_,_->assertfalseexternalswap_rb:t->unit="caml_rgba_swap_rb"moduleEffect=structexternalgreyscale:t->bool->unit="caml_rgb_greyscale"letsepiabuf=greyscalebuftrueletgreyscalebuf=greyscalebuffalseexternalinvert:t->unit="caml_rgb_invert"externalrotate:t->float->unit="caml_rgb_rotate"externalaffine:t->float->float->int->int->unit="caml_rgb_affine"(* TODO: faster implementation? *)lettranslatefxy=affinef1.1.xyexternalflip:t->unit="caml_rgb_flip"externalmask:t->t->unit="caml_rgb_mask"externallomo:t->unit="caml_rgb_lomo"externalbox_blur:t->unit="caml_mm_RGBA8_box_blur"moduleAlpha=structexternalscale:t->float->unit="caml_rgb_scale_opacity"externalblur:t->unit="caml_rgb_blur_alpha"externaldisk:t->int->int->int->unit="caml_rgb_disk_opacity"externalof_color_simple:t->int*int*int->int->unit="caml_rgb_color_to_alpha_simple"(* TODO: this does not work yet. *)(* external of_color : t -> int * int * int -> float -> float -> unit = "caml_rgb_color_to_alpha" *)letof_color=of_color_simpleendendmoduleDraw=structexternalline:t->int*int*int*int->int*int->int*int->unit="caml_mm_RGBA8_draw_line"endmoduleMotion=struct(* TODO: compute old only once? *)letcomputebson=Gray8.Motion.computebs(to_Gray8_createo)(to_Gray8_createn)moduleMulti=structincludeMotion_multiletcomputebson=Gray8.Motion.Multi.computebs(to_Gray8_createo)(to_Gray8_createn)externalarrows:int->vectors_data->t->unit="caml_rgb_motion_multi_arrows"letarrowsvimg=arrowsv.block_sizev.vectorsimgendend