WMScreenShot.Mod 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. MODULE WMScreenShot; (** AUTHOR "TF"; PURPOSE "Screenshot utility"; *)
  2. IMPORT
  3. Commands, Plugins, Raster, WMGraphics, WMRectangles,
  4. WM := WMWindowManager;
  5. TYPE
  6. View = OBJECT (WM.ViewPort)
  7. VAR
  8. backbuffer : WMGraphics.Image;
  9. deviceRect : WMRectangles.Rectangle;
  10. c : WMGraphics.BufferCanvas;
  11. state : WMGraphics.CanvasState;
  12. fx, fy, inffx, inffy, factor, intfactor : REAL;
  13. PROCEDURE &New*(manager : WM.WindowManager; w, h : LONGINT);
  14. BEGIN
  15. SELF.manager := manager;
  16. NEW(backbuffer);
  17. Raster.Create(backbuffer, w, h, Raster.BGR565);
  18. NEW(c, backbuffer);
  19. c.SetFont(WMGraphics.GetDefaultFont());
  20. c.SaveState(state);
  21. deviceRect := WMRectangles.MakeRect(0, 0, w, h);
  22. factor := 1; intfactor := 1;
  23. fx := factor; fy := factor; inffx := 1 ; inffy := inffx;
  24. SetRange(0, 0, w, h, FALSE);
  25. manager.AddView(SELF); manager.RefreshView(SELF);
  26. END New;
  27. (** r in wm coordinates *)
  28. PROCEDURE Update*(r : WMRectangles.Rectangle; top : WM.Window);
  29. BEGIN
  30. Draw(WMRectangles.ResizeRect(r, 1), top.prev) (* assuming the src-domain is only 1 *)
  31. END Update;
  32. PROCEDURE Refresh*(top : WM.Window);
  33. BEGIN
  34. Update(WMRectangles.MakeRect(ENTIER(range.l)-1, ENTIER(range.t)-1, ENTIER(range.r) + 1, ENTIER(range.b) + 1), top)
  35. END Refresh;
  36. PROCEDURE SetRange*(x, y, w, h : REAL; showTransition : BOOLEAN);
  37. PROCEDURE Set(x, y, w, h : REAL);
  38. VAR tf : REAL;
  39. BEGIN
  40. range.l := x;
  41. range.t := y;
  42. factor := (backbuffer.width) / w;
  43. tf := (backbuffer.height) / h;
  44. IF factor > tf THEN factor := tf END;
  45. fx := factor; fy := factor; inffx := 1 / factor; inffy := inffx;
  46. range.r := x + backbuffer.width * inffx;
  47. range.b := y + backbuffer.height * inffy;
  48. intfactor := factor;
  49. manager.RefreshView(SELF);
  50. END Set;
  51. BEGIN
  52. IF w = 0 THEN w := 0.001 END;
  53. IF h = 0 THEN h := 0.001 END;
  54. Set(x, y, w, h)
  55. END SetRange;
  56. (* in wm coordinates *)
  57. PROCEDURE Draw(r : WMRectangles.Rectangle; top : WM.Window);
  58. VAR cur : WM.Window;
  59. wr, nr : WMRectangles.Rectangle;
  60. PROCEDURE InternalDraw(r : WMRectangles.Rectangle; cur : WM.Window);
  61. VAR nr, cb, dsr : WMRectangles.Rectangle;
  62. BEGIN
  63. IF cur.useAlpha & (cur.prev # NIL) THEN Draw(r, cur.prev)
  64. ELSE
  65. WHILE cur # NIL DO (* draw r in wm coordinates in all the windows from cur to top *)
  66. nr := r; cb := cur.bounds; WMRectangles.ClipRect(nr, cb);
  67. dsr.l := ENTIER((nr.l - range.l) * fx) ; dsr.t := ENTIER((nr.t - range.t) * fy);
  68. dsr.r := ENTIER((nr.r - range.l) * fx + 0.5); dsr.b := ENTIER((nr.b - range.t) * fy + 0.5);
  69. IF (~WMRectangles.RectEmpty(dsr)) & (WMRectangles.Intersect(dsr, deviceRect)) THEN
  70. c.SetClipRect(dsr); (* Set clip rect to dsr, clipped at current window *)
  71. c.ClipRectAsNewLimits(ENTIER((cur.bounds.l - range.l) * fx), ENTIER((cur.bounds.t - range.t) * fy));
  72. (* range can not be factored out because of rounding *)
  73. cur.Draw(c, ENTIER((cb.r - range.l)* fx) - ENTIER((cb.l - range.l) * fx),
  74. ENTIER((cb.b - range.t) * fy) - ENTIER((cb.t - range.t) * fy), 1);
  75. c.RestoreState(state);
  76. END;
  77. cur := cur.next
  78. END;
  79. END
  80. END InternalDraw;
  81. BEGIN
  82. cur := top;
  83. IF (cur # NIL) & (~WMRectangles.RectEmpty(r)) THEN
  84. wr := cur.bounds;
  85. IF ~WMRectangles.IsContained(wr, r) THEN
  86. IF WMRectangles.Intersect(r, wr) THEN
  87. (* r contains wr calculate r - wr and recursively call for resulting rectangles*)
  88. (* calculate top rectangle *)
  89. IF wr.t > r.t THEN WMRectangles.SetRect(nr, r.l, r.t, r.r, wr.t); Draw(nr, cur.prev) END;
  90. (* calculate bottom rectangle *)
  91. IF wr.b < r.b THEN WMRectangles.SetRect(nr, r.l, wr.b, r.r, r.b); Draw(nr, cur.prev) END;
  92. (* calculate left rectangle *)
  93. IF wr.l > r.l THEN WMRectangles.SetRect(nr, r.l, MAX(r.t, wr.t), wr.l, MIN(r.b, wr.b)); Draw(nr, cur.prev) END;
  94. (* calculate left rectangle *)
  95. IF wr.r < r.r THEN WMRectangles.SetRect(nr, wr.r, MAX(r.t, wr.t), r.r, MIN(r.b, wr.b)); Draw(nr, cur.prev) END;
  96. (* calculate overlapping *)
  97. nr := r; WMRectangles.ClipRect(nr, wr);
  98. IF ~WMRectangles.RectEmpty(nr) THEN InternalDraw(nr, cur) END
  99. ELSE Draw(r, cur.prev)
  100. END
  101. ELSE InternalDraw(r, cur)
  102. END
  103. END
  104. END Draw;
  105. PROCEDURE Close;
  106. BEGIN
  107. manager.RemoveView(SELF)
  108. END Close;
  109. END View;
  110. (** Parameters : filename [viewname] [width] [height] *)
  111. PROCEDURE SnapShotView*(context : Commands.Context);
  112. VAR manager : WM.WindowManager;
  113. viewportName, fn : ARRAY 100 OF CHAR;
  114. viewport : WM.ViewPort;
  115. sv : View;
  116. p : Plugins.Plugin;
  117. w, h: LONGINT; res: WORD;
  118. BEGIN
  119. context.arg.SkipWhitespace; context.arg.String(fn);
  120. IF ~((context.arg.Peek() >= '0') & (context.arg.Peek() <= '9')) THEN
  121. context.arg.String(viewportName);
  122. END;
  123. manager := WM.GetDefaultManager();
  124. p := manager.viewRegistry.Get(viewportName);
  125. IF p # NIL THEN viewport := p(WM.ViewPort) ELSE viewport := WM.GetDefaultView() END;
  126. w := MAX(ENTIER(viewport.range.r - viewport.range.l), 1);
  127. h := MAX(ENTIER(viewport.range.b - viewport.range.t), 1);
  128. context.arg.SkipWhitespace;
  129. IF (context.arg.Peek() >= '0') & (context.arg.Peek() <= '9') THEN context.arg.Int(w, FALSE) END;
  130. context.arg.SkipWhitespace;
  131. IF (context.arg.Peek() >= '0') & (context.arg.Peek() <= '9') THEN context.arg.Int(h, FALSE) END;
  132. context.out.String("Screenshot : ");
  133. NEW(sv, manager, w, h);
  134. sv.SetRange(viewport.range.l, viewport.range.t, viewport.range.r, viewport.range.b, FALSE);
  135. WMGraphics.StoreImage(sv.backbuffer, fn, res);
  136. IF res = 0 THEN
  137. context.out.String(" Click"); context.out.Ln; context.out.String("--> WMPicView.Open ");
  138. context.out.String(fn); context.out.String(" ~"); context.out.Ln;
  139. ELSE
  140. context.error.String("Failed not written : "); context.error.String(fn); context.error.Ln;
  141. END;
  142. sv.Close;
  143. END SnapShotView;
  144. (** Parameters : filename width height [(left top)|(left top width height)]*)
  145. PROCEDURE SnapShotRange*(context : Commands.Context);
  146. VAR manager : WM.WindowManager;
  147. fn : ARRAY 100 OF CHAR;
  148. sv : View;
  149. w, h, rl, rt, rw, rh: LONGINT; res: WORD;
  150. BEGIN
  151. context.arg.SkipWhitespace; context.arg.String(fn);
  152. context.arg.SkipWhitespace; context.arg.Int(w, FALSE);
  153. IF w <1 THEN w := 1 END; IF w > 10000 THEN w := 10000 END;
  154. context.arg.SkipWhitespace; context.arg.Int(h, FALSE);
  155. IF h <1 THEN h := 1 END; IF h > 10000 THEN h := 10000 END;
  156. context.arg.SkipWhitespace;
  157. IF (context.arg.Peek() >= '0') & (context.arg.Peek() <= '9') OR (context.arg.Peek() = '-')THEN
  158. context.arg.SkipWhitespace; context.arg.Int(rl, FALSE);
  159. context.arg.SkipWhitespace; context.arg.Int(rt, FALSE);
  160. END;
  161. rw := w; rh := h;
  162. context.arg.SkipWhitespace;
  163. IF (context.arg.Peek() >= '0') & (context.arg.Peek() <= '9') THEN
  164. context.arg.SkipWhitespace; context.arg.Int(rw, FALSE);
  165. context.arg.SkipWhitespace; context.arg.Int(rh, FALSE);
  166. END;
  167. IF rw <= 0 THEN rw := 1 END;
  168. IF rh <= 0 THEN rh := 1 END;
  169. context.out.String("Screenshot : ");
  170. manager := WM.GetDefaultManager();
  171. NEW(sv, manager, w, h);
  172. context.out.Int(rl, 0); context.out.String(", "); context.out.Int(rt, 0); context.out.String(", ");
  173. context.out.Int(rl + rw, 0); context.out.String(", "); context.out.Int(rt + rh, 0);
  174. sv.SetRange(rl, rt, rw, rh, FALSE);
  175. context.out.String(" Click"); context.out.Ln;
  176. WMGraphics.StoreImage(sv.backbuffer, fn, res);
  177. IF res = 0 THEN
  178. context.out.String("--> WMPicView.Open "); context.out.String(fn); context.out.String(" ~"); context.out.Ln;
  179. ELSE
  180. context.error.String("Failed not written : "); context.error.String(fn); context.error.Ln;
  181. END;
  182. sv.Close;
  183. END SnapShotRange;
  184. END WMScreenShot.
  185. System.Free WMScreenShot ~
  186. Take a snap shot of the default view store it in test.bmp
  187. WMScreenShot.SnapShotView test.bmp ~
  188. Take a snap shot of the default view store it in test.bmp scaled to 100 by 100 pixels
  189. WMScreenShot.SnapShotView test.bmp 100 100~
  190. Take a snap shot of the View#0 store it in test.bmp
  191. WMScreenShot.SnapShotView test.bmp View#0 ~
  192. Take a snap shot of the View#0 store it in test.bmp scaled to 200 by 200 pixels
  193. WMScreenShot.SnapShotView test.bmp View#0 200 200 ~
  194. To a image of 300 by 300 pixels store a snapshot of range -100 -100 to 200 200 in the display space
  195. WMScreenShot.SnapShotRange test.bmp 300 300 -100 -100 300 300 ~
  196. WMPicView.Open test.bmp ~