b_image.ml1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115(** a simple image display *) module Theme = B_theme module Var = B_var module Draw = B_draw type resize = | Crop of int (* cut the image at origin x *) | Fit (* fit in given area *) | KeepRatio (* keep aspect ratio and fit inside area *) | Expand (* expand if too small. Do not shrink *) | Shrink (* shrink if too big. Do not expand *) | Size of int (* make it this size *) type t = { file : string Var.t; width : int; (* width of the area *) height : int; (* height of the area *) xsize : resize; (* NOT used anymore. control the width of the image within the area *) ysize : resize; (* NOT used anymore. control the height of the image .. *) xpos : Draw.align; (* NOT used anymore. horizontal centering *) ypos : Draw.align; (* NOT used anymore. vertical ... *) background : Draw.color; render : (Draw.texture option) Var.t; };; let size img = img.width, img.height;; (* use noscale = true to keep original pixel size. *) (* TODO: noscale=true is not completely accurate because this leads to * performing scale (size / scale), thus we loose some units due to integer rounding. To be exact, we should keep a flag "original size" and modify the blit to use exact size *) let create ?width ?height ?(noscale = false) ?(bg = Draw.(opaque black)) file = let width, height = match width, height with | Some w, Some h -> (w,h) | _ -> begin let (w0,h0) = Draw.image_size file in match width, height with | None, Some h -> (w0 * h) / h0, h | Some w, None -> w, (h0 * w) / w0 | _ -> w0, h0 end in let width, height = if noscale then Draw.unscale_size (width, height) else width, height in { file = Var.create file; xpos = Draw.Center; (* TODO, make this changeable *) ypos = Draw.Center; (* idem *) width; height; xsize = KeepRatio; (* idem *) ysize = KeepRatio; (* idem *) background = bg; (* idem *) render = Var.create None; };; (* NOTE once we have a more recent version (>= 2.0.2) of SDL_image, we should be able to directly load SVG. HOWEVER, it currently it doesn't scale the image, so it's not recommended. *) let create_from_svg ?width ?height ?(bg = Draw.(opaque black)) file = create ?width ?height ~bg (Draw.convert_svg ?w:width ?h:height file);; let unload img = match Var.get img.render with | None -> () | Some tex -> begin Draw.forget_texture tex; Var.set img.render None end;; (* TODO *) let free = unload;; (************* display ***********) let display canvas layer img g = let open Draw in let tex = match Var.get img.render with | Some t -> t | None -> let file = Theme.get_path (Var.get img.file) in (* printd debug_io "Image: Loading image file %s" file; *) (* let surf = sdl_image_load file in *) (* let box = create_surface ~like:surf ~color:img.background g.w g.h in *) (* let sw,sh = Sdl.get_surface_size surf in *) (* let bw, bh = match img.xsize, img.ysize with *) (* | Fit, Fit -> g.w, g.h *) (* | KeepRatio, KeepRatio -> let ratio = float sh /. float sw in *) (* if ratio *. (float g.w) <= float g.h then (g.w, round (float g.w *. ratio)) *) (* else (round (float g.h /. ratio), g.h) *) (* | _ -> failwith "resizing not implemented" in *) (* let x = align img.xpos 0 g.w bw in *) (* let y = align img.ypos 0 g.h bh in *) (* let r1 = Sdl.get_clip_rect surf in *) (* let r2 = Sdl.Rect.create ~x ~y ~w:bw ~h:bh in *) (* go (Sdl.blit_scaled ~src:surf r1 ~dst:box (Some r2)); *) (* let tex = create_texture_from_surface canvas.renderer box in *) (* Var.set img.render (Some tex); *) (* tex *) let tex = Draw.load_image canvas.renderer file in Var.set img.render (Some tex); tex (* TODO render on background *) (* it is better to render first the image at full resolution and then scale it, in case we later use some zoom animation. If one has a zoom from 0 to 1, then the first time the image will be rendered, the required size would be zero. So we have to be careful not to render at this size... *) in let dst = geom_to_rect g in [make_blit ~dst ~voffset:g.voffset canvas layer tex];;