123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952(*
* 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.
*
*)letoption_valueo~default=matchowithSomev->v|None->defaultletoption_get=functionSomev->v|None->invalid_arg"option is None"moduleData=structtypet=(int,Bigarray.int8_unsigned_elt,Bigarray.c_layout)Bigarray.Array1.t(* Creates an 16-bytes aligned plane. Returns (stride*plane). *)(* external create_rounded_plane : int -> int -> int * t = "caml_data_aligned_plane" *)letallocn=Bigarray.Array1.createBigarray.int8_unsignedBigarray.C_layoutn(** [round n k] rounds [n] to the nearest upper multiple of [k]. *)letroundkn=((n+(k-1))/k)*k(** [aligned k n] allocates [n] bytes at a multiple of [k]. *)externalaligned:int->int->t="caml_data_aligned"(* Creates an 16-bytes aligned plane. Returns (stride*plane). *)letrounded_planewidthheight=letalign=16inletstride=round16widthinletdata=alignedalign(height*stride)in(stride,data)externalto_string:t->string="caml_data_to_string"externalto_bytes:t->bytes="caml_data_to_string"externalof_string:string->t="caml_data_of_string"letblit_allsrcdst=Bigarray.Array1.blitsrcdstexternalblit:t->int->t->int->int->unit="caml_data_blit_off"(* [@@noalloc] *)externalcopy:t->t="caml_data_copy"letsubbufofslen=Bigarray.Array1.subbufofslenletlengthimg=Bigarray.Array1.dimimgletsizeimg=lengthimgletget=Bigarray.Array1.getletfillbufx=Bigarray.Array1.fillbufxendmodulePixel=structtypergba=int*int*int*inttypergb=int*int*inttypeyuv=int*int*inttypeyuva=(int*int*int)*intexternalyuv_of_rgb:rgb->yuv="caml_yuv_of_rgb"externalrgb_of_yuv:yuv->rgb="caml_rgb_of_yuv"endmoduleDraw=struct(* Besenham algorithm. *)letlinep(sx,sy)(dx,dy)=letsteep=abs(dy-sy)>abs(dx-sx)inletsx,sy,dx,dy=ifsteepthen(sy,sx,dy,dx)else(sx,sy,dx,dy)inletsx,sy,dx,dy=ifsx>dxthen(dx,dy,sx,sy)else(sx,sy,dx,dy)inletdeltax=dx-sxinletdeltay=abs(dy-sy)inleterror=ref(deltax/2)inletystep=ifsy<dythen1else-1inletj=refsyinfori=sxtodx-1doifsteepthenp!jielsepi!j;error:=!error-deltay;if!error<0then(j:=!j+ystep;error:=!error+deltax)doneendmoduleMotion_multi=structtypevectors_data=(int,Bigarray.nativeint_elt,Bigarray.c_layout)Bigarray.Array1.ttypevectors={vectors:vectors_data;vectors_width:int;block_size:int;}externalmedian_denoise:int->vectors_data->unit="caml_rgb_motion_multi_median_denoise"letmedian_denoisev=median_denoisev.vectors_widthv.vectorsexternalmean:int->vectors_data->int*int="caml_rgb_motion_multi_mean"letmeanv=meanv.vectors_widthv.vectorsendmoduleRGB8=structmoduleColor=structtypet=int*int*intletof_intn=ifn>0xffffffthenraise(Invalid_argument"Not a color");((nlsr16)land0xff,(nlsr8)land0xff,nland0xff)endendmoduleGray8=struct(* TODO: stride ? *)typet={data:Data.t;width:int}letmakewd={data=d;width=w}(* Don't use create_rounded_plane here since there is not stride.. *)letcreatewh=makew(Bigarray.Array1.createBigarray.int8_unsignedBigarray.c_layout(w*h))moduleMotion=structexternalcompute:int->int->Data.t->Data.t->int*int="caml_mm_Gray8_motion_compute"letcomputebson=computebsn.widtho.datan.datamoduleMulti=structincludeMotion_multiexternalcompute:int->int->Data.t->Data.t->vectors_data="caml_mm_Gray8_motion_multi_compute"letcomputebson={vectors=computebsn.widtho.datan.data;vectors_width=n.width/bs;block_size=bs;}endendendmoduleBGRA=structtypedata=Data.ttypet={data:data;width:int;height:int;stride:int}letmake?stridewidthheightdata=letstride=matchstridewithSomev->v|None->4*widthin{data;width;height;stride}letcreate?stridewidthheight=letstride=matchstridewithSomev->v|None->4*widthinletstride,data=Data.rounded_planestrideheightinmake~stridewidthheightdataletdataimg=img.dataendmoduleRGBA32=structmoduleColor=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.vectorsimgendendendmoduleYUV420=structtypet={mutabley:Data.t;mutabley_stride:int;mutableu:Data.t;mutablev:Data.t;mutableuv_stride:int;width:int;height:int;mutablealpha:Data.toption;(* alpha stride is y_stride *)}letwidthimg=img.widthletheightimg=img.heightletdimensionsimg=(widthimg,heightimg)letyimg=img.ylety_strideimg=img.y_strideletuimg=img.uletvimg=img.vletuv_strideimg=img.uv_strideletdataimg=(img.y,img.u,img.v)letalphaimg=img.alphaletset_alphaimgalpha=img.alpha<-alphaletsizeimg=Data.sizeimg.y+Data.sizeimg.u+Data.sizeimg.vletmakewidthheightyy_strideuvuv_stride={y;y_stride;u;v;uv_stride;width;height;alpha=None}letmake_datawidthheightdatay_strideuv_stride=assert(Data.lengthdata=height*(y_stride+uv_stride));lety=Data.subdata0(height*y_stride)inletu=Data.subdata(height*y_stride)(height/2*uv_stride)inletv=Data.subdata((height*y_stride)+(height/2*uv_stride))(height/2*uv_stride)inmakewidthheightyy_strideuvuv_stride(* Default alignment. *)letalign=Sys.word_size/8letdefault_stridewidthy_strideuv_stride=lety_stride=option_value~default:(Data.roundalignwidth)y_strideinletuv_stride=option_value~default:(Data.roundalign((width+1)/2))uv_stridein(y_stride,uv_stride)letcreate?y_stride?uv_stridewidthheight=lety_stride,uv_stride=default_stridewidthy_strideuv_strideinlety=Data.alignedalign(height*y_stride)inletu,v=letheight=Data.round2((height+1)/2)in(Data.alignedalign(height*uv_stride),Data.alignedalign(height*uv_stride))inmakewidthheightyy_strideuvuv_strideletensure_alphaimg=ifimg.alpha=Nonethen(leta=Data.alloc(img.height*img.y_stride)inData.filla0xff;img.alpha<-Somea)lethas_alphaimg=img.alpha<>Noneletremove_alphaimg=img.alpha<-Noneletof_YUV420_string?y_stride?uv_strideswidthheight=(* let y_stride, uv_stride = default_stride width y_stride uv_stride in *)lety_stride=option_value~default:widthy_strideinletuv_stride=option_value~default:(width/2)uv_strideinletdata=Data.of_stringsinmake_datawidthheightdatay_strideuv_strideexternalof_RGB24_string:t->string->unit="caml_yuv420_of_rgb24_string"letof_RGB24_stringswidth=letheight=String.lengths/(3*width)inletimg=createwidthheightinof_RGB24_stringimgs;imgexternalof_RGBA32:RGBA32.t->t->unit="caml_yuv420_of_rgba32"letof_RGBA32rgb=letwidth=RGBA32.widthrgbinletheight=RGBA32.heightrgbinletimg=createwidthheightinensure_alphaimg;of_RGBA32rgbimg;imgexternalto_RGBA32:t->RGBA32.t->unit="caml_yuv420_to_rgba32"letto_RGBA32img=letwidth=img.widthinletheight=img.heightinletrgb=RGBA32.createwidthheightinto_RGBA32imgrgb;rgbletof_PPMs=letimg=of_RGBA32(RGBA32.of_PPMs)inremove_alphaimg;imgletcopyimg=letdst=create~y_stride:img.y_stride~uv_stride:img.uv_strideimg.widthimg.heightinBigarray.Array1.blitimg.ydst.y;Bigarray.Array1.blitimg.udst.u;Bigarray.Array1.blitimg.vdst.v;letalpha=matchimg.alphawithNone->None|Somealpha->Some(Data.copyalpha)indst.alpha<-alpha;dstexternalfill:t->Pixel.yuv->unit="caml_yuv420_fill"letfill_alphaimga=ifa=0xffthenimg.alpha<-Noneelse(ensure_alphaimg;Bigarray.Array1.fill(option_getimg.alpha)a)letblankimg=fillimg(Pixel.yuv_of_rgb(0,0,0))letblank_all=blankletblit_allsrcdst=assert(src.width=dst.width);assert(src.height=dst.height);ifsrc.y_stride=dst.y_stride&&src.uv_stride=dst.uv_stridethen(Data.blitsrc.y0dst.y0(dst.height*dst.y_stride);Data.blitsrc.u0dst.u0(dst.height/2*dst.uv_stride);Data.blitsrc.v0dst.v0(dst.height/2*dst.uv_stride);matchsrc.alphawith|None->dst.alpha<-None|Somealpha->(matchdst.alphawith|None->dst.alpha<-Some(Data.copyalpha)|Somealpha'->Bigarray.Array1.blitalphaalpha'))else(dst.y<-Data.copysrc.y;dst.u<-Data.copysrc.u;dst.v<-Data.copysrc.v;dst.y_stride<-src.y_stride;dst.uv_stride<-src.uv_stride;matchsrc.alphawith|None->dst.alpha<-None|Somealpha->dst.alpha<-Some(Data.copyalpha))letblitsrcdst=blit_allsrcdstexternalrandomize:t->unit="caml_yuv_randomize"externaladd:t->int->int->t->unit="caml_yuv420_add"letaddsrc?(x=0)?(y=0)dst=addsrcxydstexternalset_pixel_rgba:t->int->int->Pixel.rgba->unit="caml_yuv420_set_pixel_rgba"(* [@@noalloc] *)letset_pixel_rgbaimgij((_,_,_,a)asp)=assert(0<=i&&i<img.width&&0<=j&&j<img.height);ifa<>0xffthenensure_alphaimg;set_pixel_rgbaimgijp(*
let set_pixel_rgba img i j (r,g,b,a) =
let data = img.data in
let width = img.width in
let height = img.height in
if img.alpha <> None || a <> 0xff then
(
ensure_alpha img;
Bigarray.Array1.set (option_get img.alpha) (j * width + i) a
);
let y,u,v = Pixel.yuv_of_rgb (r,g,b) in
Bigarray.Array1.set data (j * width + i) y;
Bigarray.Array1.set data (height * width + (j / 2) * (width / 2) + i / 2) u;
Bigarray.Array1.set data (height * width * 5 / 4 + (j / 2) * (width / 2) + i / 2) v
*)letget_pixel_yimgij=Data.getimg.y((j*img.y_stride)+i)letget_pixel_uimgij=Data.getimg.u((j/2*img.uv_stride)+(i/2))letget_pixel_vimgij=Data.getimg.v((j/2*img.uv_stride)+(i/2))externalget_pixel_rgba:t->int->int->Pixel.rgba="caml_yuv420_get_pixel_rgba"externalto_int_image:t->intarrayarray="caml_yuv420_to_int_image"externalscale_full:t->t->unit="caml_yuv420_scale"letscale_fullsrcdst=ifhas_alphasrcthenensure_alphadst;scale_fullsrcdstexternalscale_coef:t->t->int*int->int*int->unit="caml_yuv420_scale_coef"letscale_proportionalsrcdst=ifhas_alphasrcthenensure_alphadst;letsw,sh=(src.width,src.height)inletdw,dh=(dst.width,dst.height)inifdw=sw&&dh=shthenblit_allsrcdstelse(letn,d=ifdh*sw<sh*dwthen(dh,sh)else(dw,sw)inscale_coefsrcdst(n,d)(n,d))letscale?(proportional=false)srcdst=ifproportionalthenscale_proportionalsrcdstelsescale_fullsrcdstexternalscale_alpha:t->float->unit="caml_yuv_scale_alpha"letscale_alphaimga=ifa<>1.then(ensure_alphaimg;scale_alphaimga)externaldisk_alpha:t->int->int->int->unit="caml_yuv_disk_alpha"letdisk_alphaimgxyr=ensure_alphaimg;disk_alphaimgxyrexternalbox_alpha:t->int->int->int->int->float->unit="caml_yuv_box_alpha_bytecode""caml_yuv_box_alpha_native"letbox_alphaimgxyr=ensure_alphaimg;box_alphaimgxyrmoduleEffect=structexternalgreyscale:t->unit="caml_yuv_greyscale"letsepia_=failwith"Not implemented: sepia"letinvert_=failwith"Not implemented: invert"letlomo_=failwith"Not implemented: lomo"moduleAlpha=structletscale=scale_alphaletdisk=disk_alphaendendendmoduleGeneric=structexceptionNot_implementedmodulePixel=structtypergb_format=|RGB24(* 24 bit RGB. Each color is an uint8_t. Color order is RGBRGB *)|BGR24(* 24 bit BGR. Each color is an uint8_t. Color order is BGRBGR *)|RGB32(* 32 bit RGB. Each color is an uint8_t. Color order is RGBXRGBX, where X is unused *)|BGR32(* 32 bit BGR. Each color is an uint8_t. Color order is BGRXBGRX, where X is unused *)|RGBA32(* 32 bit RGBA. Each color is an uint8_t. Color order is RGBARGBA *)typeyuv_format=|YUV422(* Planar YCbCr 4:2:2. Each component is an uint8_t *)|YUV444(* Planar YCbCr 4:4:4. Each component is an uint8_t *)|YUV411(* Planar YCbCr 4:1:1. Each component is an uint8_t *)|YUV410(* Planar YCbCr 4:1:0. Each component is an uint8_t *)|YUVJ420(* Planar YCbCr 4:2:0. Each component is an uint8_t,
* luma and chroma values are full range (0x00 .. 0xff) *)|YUVJ422(* Planar YCbCr 4:2:2. Each component is an uint8_t,
* luma and chroma values are full range (0x00 .. 0xff) *)|YUVJ444(* Planar YCbCr 4:4:4. Each component is an uint8_t, luma and
* chroma values are full range (0x00 .. 0xff) *)typeformat=RGBofrgb_format|YUVofyuv_formatletsize=function|RGBx->(matchxwithRGB24|BGR24->3|RGB32|BGR32|RGBA32->4)|YUV_->raiseNot_implementedletstring_of_format=function|RGBx->(matchxwith|RGB24->"RGB24"|BGR24->"BGR24"|RGB32->"RGB32"|BGR32->"BGR32"|RGBA32->"RGBA32")|YUVx->(matchxwith|YUV422->"YUV422"|YUV444->"YUV444"|YUV411->"YUV411"|YUV410->"YUV410"|YUVJ420->"YUVJ420"|YUVJ422->"YUVJ422"|YUVJ444->"YUVJ444")endtypedata=(int,Bigarray.int8_unsigned_elt,Bigarray.c_layout)Bigarray.Array1.ttypergb={rgb_pixel:Pixel.rgb_format;rgb_data:data;rgb_stride:int}typeyuv={yuv_pixel:Pixel.yuv_format;y:data;y_stride:int;u:data;v:data;uv_stride:int;}typet_data=RGBofrgb|YUVofyuvtypet={data:t_data;width:int;height:int}letrgb_dataimg=matchimg.datawith|RGBrgb->(rgb.rgb_data,rgb.rgb_stride)|_->assertfalseletyuv_dataimg=matchimg.datawith|YUVyuv->((yuv.y,yuv.y_stride),(yuv.u,yuv.v,yuv.uv_stride))|_->assertfalseletwidthimg=img.widthletheightimg=img.heightletpixel_formatimg=matchimg.datawith|RGBrgb->Pixel.RGBrgb.rgb_pixel|YUVyuv->Pixel.YUVyuv.yuv_pixelletmake_rgbpix?stridewidthheightdata=letstride=matchstridewith|Somes->s|None->width*Pixel.size(Pixel.RGBpix)inletrgb_data={rgb_pixel=pix;rgb_data=data;rgb_stride=stride}in{data=RGBrgb_data;width;height}letof_RGBA32img=letrgb_data={rgb_pixel=Pixel.RGBA32;rgb_data=img.RGBA32.data;rgb_stride=img.RGBA32.stride;}in{data=RGBrgb_data;width=img.RGBA32.width;height=img.RGBA32.height;}letto_RGBA32img=letrgb_data=matchimg.datawithRGBd->d|_->assertfalseinassert(rgb_data.rgb_pixel=Pixel.RGBA32);{RGBA32.data=rgb_data.rgb_data;width=img.width;height=img.height;stride=rgb_data.rgb_stride;}letof_YUV420img=letyuv_data={yuv_pixel=Pixel.YUVJ420;y=img.YUV420.y;y_stride=img.YUV420.y_stride;u=img.YUV420.u;v=img.YUV420.v;uv_stride=img.YUV420.uv_stride;}in{data=YUVyuv_data;width=img.YUV420.width;height=img.YUV420.height;}letto_YUV420img=letyuv=matchimg.datawithYUVyuv->yuv|_->assertfalseinassert(yuv.yuv_pixel=Pixel.YUVJ420);YUV420.makeimg.widthimg.heightyuv.yyuv.y_strideyuv.uyuv.vyuv.uv_strideexternalrgba32_to_bgr32:data->int->data->int->int*int->unit="caml_RGBA32_to_BGR32"externalrgb24_to_rgba32:data->int->data->int->int*int->unit="caml_RGB24_to_RGBA32"externalrgb32_to_rgba32:data->int->data->int->int*int->unit="caml_RGB32_to_RGBA32"letblankimg=matchimg.datawith|RGBrgb->(matchrgb.rgb_pixelwith|Pixel.RGBA32->RGBA32.blank(to_RGBA32img)|_->failwith"Not implemented")|YUVyuv->(matchyuv.yuv_pixelwith|Pixel.YUVJ420->YUV420.blank(to_YUV420img)|_->failwith"Not implemented")letconvert?(proportional=true)?scale_kindsrcdst=match(src.data,dst.data)with|RGBs,RGBdwhens.rgb_pixel=Pixel.RGBA32&&d.rgb_pixel=Pixel.RGBA32->letsrc=to_RGBA32srcinletdst=to_RGBA32dstinRGBA32.Scale.onto?kind:scale_kind~proportionalsrcdst|YUVs,RGBdwhens.yuv_pixel=Pixel.YUVJ420&&d.rgb_pixel=Pixel.RGBA32->letsrc=to_YUV420srcinletsrc=YUV420.to_RGBA32srcinletdst=to_RGBA32dstinRGBA32.Scale.onto?kind:scale_kind~proportionalsrcdst|RGBs,YUVdwhens.rgb_pixel=Pixel.RGBA32&&d.yuv_pixel=Pixel.YUVJ420->letsrc=to_RGBA32srcinletsrc=YUV420.of_RGBA32srcinletdst=to_YUV420dstinYUV420.scale~proportionalsrcdst|RGBs,RGBdwhens.rgb_pixel=Pixel.RGBA32&&d.rgb_pixel=Pixel.BGR32->ifsrc.width=dst.width&&src.height=dst.heightthenrgba32_to_bgr32s.rgb_datas.rgb_strided.rgb_datad.rgb_stride(src.width,src.height)elseraiseNot_implemented|RGBs,RGBdwhens.rgb_pixel=Pixel.RGB24&&d.rgb_pixel=Pixel.RGBA32->ifsrc.width=dst.width&&src.height=dst.heightthenrgb24_to_rgba32s.rgb_datas.rgb_strided.rgb_datad.rgb_stride(src.width,src.height)elseraiseNot_implemented|RGBs,RGBdwhens.rgb_pixel=Pixel.RGB32&&d.rgb_pixel=Pixel.RGBA32->ifsrc.width=dst.width&&src.height=dst.heightthenrgb32_to_rgba32s.rgb_datas.rgb_strided.rgb_datad.rgb_stride(src.width,src.height)elseraiseNot_implemented|_->raiseNot_implementedend