1 | !7 |
2 | |
3 | !include early #1033506 // Compact Module Include Gazelle V |
4 | |
5 | module GazelleV > DynPrintLogAndEnabled { |
6 | /*switchable int x1; |
7 | switchable int y1; |
8 | switchable int w = screenWidth(); |
9 | switchable int h = screenHeight();*/ |
10 | switchable double maxFPS = 10; |
11 | switchable int previewWidth = 200; |
12 | switchable double statsEvery = 5; |
13 | switchable volatile bool brokenMethod; |
14 | int lookAtScreen; |
15 | S previewMode; |
16 | int gridRows = 20; |
17 | bool scaleDownPreviewImage; |
18 | int previewPosterization = 256; |
19 | S uiURL = "Home"; |
20 | //bool deepCompression; |
21 | |
22 | PersistableThrowable lastProcessingError; |
23 | transient WithTimestamp<OKOrError<BufferedImage>> lastScreen; |
24 | transient new Average screenShotTime; |
25 | transient new Average iiTime; |
26 | transient Timestamp loopStarted; |
27 | transient Sleeping screenShotCountdown; |
28 | transient long screenShotCountdownTotalSleepTime; |
29 | //transient ImageSurface imageSurface; |
30 | transient IIImageSurface imageSurface; |
31 | transient Throwable currentProcessingError; |
32 | transient JButton popDownButton; |
33 | transient JComponent topControls; |
34 | transient long screenShotsTaken; |
35 | transient double fps; |
36 | transient Compression ongoingCompression, completedCompression; |
37 | transient S longTermCompressionProbability; |
38 | transient S longTermCompressionScore; |
39 | transient JComponent topControls2; |
40 | transient JTabbedPane tabs; |
41 | transient ThreadPool threadPool; |
42 | transient SingleComponentPanel mainArea; |
43 | |
44 | // key: ui URL |
45 | // value: component maker |
46 | transient Map<S, IF0<JComponent>> uiMap = syncCIMap(); |
47 | |
48 | // ping source for everything we do in the background, including |
49 | // analyzing current screen. |
50 | // normally limited to 50% of one core. |
51 | transient PingSource backgroundPingSource; |
52 | |
53 | transient OnOffOscillator onOffOscillator; |
54 | |
55 | Rect area() { |
56 | ret screenBounds(min(lookAtScreen, screenCount()-1)); |
57 | } |
58 | |
59 | class Compression { |
60 | settable BufferedImage image; |
61 | settable BWIntegralImage ii; |
62 | CompressionSearch_AnyType search; |
63 | int baseLineLength; // length of trivial compression |
64 | GridCodec1 codec; |
65 | double compressionPercentage; |
66 | |
67 | S score() { |
68 | var submission = search?.bestSubmission(); |
69 | Int compressedSize = or(submission.compressedSize(), baseLineLength); |
70 | compressionPercentage = 100-doubleRatio(compressedSize, baseLineLength)*100; |
71 | ret iround(compressionPercentage) + "%"; |
72 | } |
73 | |
74 | IProbabilisticScheduler scheduler() { |
75 | ret search?.scheduler(); |
76 | } |
77 | |
78 | S probability() { |
79 | var scheduler = scheduler(); |
80 | if (scheduler == null) ret "-"; |
81 | var prob = scheduler.lastExecutedProbability(); |
82 | ret formatDouble(prob, 3); |
83 | } |
84 | |
85 | event compressionDone; |
86 | |
87 | run { |
88 | int lHex = pixelCount(image)*8; |
89 | baseLineLength = calculateLengthOfFunctionCall imageFromHex(lHex+2); |
90 | print(+baseLineLength); |
91 | |
92 | codec = new GridCodec1(image); |
93 | codec.rows = gridRows; |
94 | search = codec.forward(); |
95 | //showImage(codec.renderCellsLinearly()); |
96 | |
97 | repeat 60 { |
98 | stepForNSeconds(1, search); |
99 | //print(stepCount := search.scheduler().stepCount()); |
100 | setFields( |
101 | longTermCompressionProbability := probability(), |
102 | longTermCompressionScore := score()); |
103 | } |
104 | |
105 | try { |
106 | compressionDone(); |
107 | |
108 | L<IJavaExpr> cellCompressions = codec.strat.codeForElements(); |
109 | //showText("Compression", lines(map shorten_str(cellCompressions))); |
110 | |
111 | /*S code = str(codec.winnerCode()); |
112 | S name = "Screenshot " + ymdMinusHMS(); |
113 | File f = makeFileNameUnique_beforeExtension( |
114 | javaxDataDir("Compressed Screenshots/" + name + ".javax")); |
115 | saveTextFile(f, code); |
116 | printFileInfo(f); |
117 | saveGZTextFile(f = replaceExtension(f, ".jgz"), code); |
118 | printFileInfo(f);*/ |
119 | |
120 | /* |
121 | print("Evaling " + nChars(code)); |
122 | //LL<Int> lol = cast dm_javaEval(code); |
123 | BufferedImage restored = cast dm_javaEval(code); |
124 | assertImagesIdentical(restored, image); |
125 | print("Image restored!"); |
126 | |
127 | dm_showImage("Restored from " + nChars(code), restored); |
128 | */ |
129 | } catch e { printStackTrace(e); } |
130 | } |
131 | |
132 | void drawOverlay(ImageSurface is, Graphics2D g) pcall { |
133 | codec.drawOverlay(is, g); |
134 | } |
135 | |
136 | int gridCols() { ret widthForHeight(ii.getWidth(), ii.getHeight(), gridRows); } |
137 | } // end of Compression |
138 | |
139 | int gridCols(MakesBufferedImage ii) { ret widthForHeight(ii.getWidth(), ii.getHeight(), gridRows); } |
140 | |
141 | start { |
142 | if (threadPool == null) threadPool = maxThreadPool(); |
143 | |
144 | backgroundPingSource = new PingSource(threadPool, "Background"); |
145 | |
146 | onOffOscillator = new OnOffOscillator(backgroundPingSource); |
147 | ownResource(onOffOscillator); |
148 | onOffOscillator.start(); |
149 | |
150 | componentFieldsToKeep = litset("tabs"); |
151 | |
152 | dm_registerAs_direct gazelleV(); |
153 | dm_watchField enabled(r { if (enabled) dm_reload(); }); |
154 | |
155 | // TODO: react to event sent by OS |
156 | dm_doEvery(1.0, r { |
157 | if (dm_moduleIsPoppedOut()) adjustUIForPoppedOutWindow(); |
158 | }); |
159 | |
160 | print("Screen bounds: " + allScreenBounds()); |
161 | |
162 | initUIMap(); |
163 | |
164 | // We are making some UI elements even if the module is hidden |
165 | // because that's easier. |
166 | |
167 | tabs = jtabs( |
168 | "Log", super.visualize(), |
169 | "Local Data", jcenteredlabel("TODO")); |
170 | |
171 | dm_doEvery(min(statsEvery, 10.0), statsEvery, r { if (enabled) printStats(); }); |
172 | |
173 | loopStarted = tsNow(); |
174 | shootAndAnalyze(); |
175 | } |
176 | |
177 | void shootAndAnalyze { |
178 | backgroundPingSource.do(r shootAndAnalyze_impl); |
179 | } |
180 | |
181 | void shootAndAnalyze_impl enter { |
182 | if (!enabled) ret; |
183 | |
184 | var targetTime = tsNow().plus(1.0/maxFPS); |
185 | long time = nanoTime(); |
186 | |
187 | try { |
188 | lastScreen = withTimestamp(okOrError(-> screenshot(area()))); |
189 | ++screenShotsTaken; |
190 | setField(fps := doubleRatio(screenShotsTaken, elapsedSeconds(loopStarted))); |
191 | screenShotTime.add(nanosToSeconds(nanoTime()-time)); |
192 | time = nanoTime(); |
193 | ping(); |
194 | if (lastScreen->isOK()) { |
195 | var img = lastScreen!!; |
196 | var ii = BWIntegralImage(img); |
197 | //var ii = BWIntegralImage_luminosity(lastScreen!!); |
198 | iiTime.add(nanosToSeconds(nanoTime()-time)); |
199 | |
200 | if (!deepCompression()) |
201 | showPreview(ii, null); |
202 | else |
203 | startCompression(ii); |
204 | } |
205 | |
206 | cpuTotal(); |
207 | currentProcessingError = null; |
208 | } catch print e { |
209 | setField(lastProcessingError := currentProcessingError = e); |
210 | //sleepSeconds(60); // errors in processing are no good |
211 | } |
212 | |
213 | screenShotCountdown = sleeper().doLater(targetTime, r shootAndAnalyze); |
214 | screenShotCountdownTotalSleepTime += screenShotCountdown.remainingMS(); |
215 | } |
216 | |
217 | bool deepCompression() { ret !scaleDownPreviewImage; } |
218 | |
219 | void showPreview(BWIntegralImage ii, Compression completedCompression) { |
220 | IBWIntegralImage ii2 = ii; |
221 | if (scaleDownPreviewImage) { |
222 | ii2 = ScaledIBWIntegralImage(gridCols(ii2), gridRows, ii2); |
223 | ii2 = TruncatedIBWIntegralImage(ii2); |
224 | |
225 | if (previewPosterization < 256) |
226 | imageSurface?.setImage(posterizeIBWImage(previewPosterization, ii2)); |
227 | else |
228 | imageSurface?.setImage(ii2); |
229 | |
230 | imageSurface.setOverlay(null); |
231 | } else { |
232 | imageSurface?.setImage(completedCompression.ii, completedCompression.image); |
233 | if (completedCompression != null) |
234 | imageSurface.setOverlay(g -> completedCompression.drawOverlay(imageSurface, g)); |
235 | } |
236 | } |
237 | |
238 | void startCompression(BWIntegralImage ii) { |
239 | if (ongoingCompression == null) { |
240 | ping(); |
241 | ongoingCompression = new Compression() |
242 | .image(lastScreen!!) |
243 | .ii(ii); |
244 | ongoingCompression.onCompressionDone(-> { |
245 | completedCompression = ongoingCompression; |
246 | ongoingCompression = null; |
247 | |
248 | showPreview(ii, completedCompression); |
249 | }); |
250 | ongoingCompression.run(); |
251 | } |
252 | } |
253 | |
254 | void printStats() { print(stats()); } |
255 | |
256 | S stats() { |
257 | var screen = lastScreen?!; |
258 | ret formatColonProperties_noNulls( |
259 | "Monitored area", area(), |
260 | "Error", screen?.getError(), |
261 | "Last screenshot taken", lastScreen?.timeStamp(), |
262 | "Average time to take a screenshot", screenShotTime, |
263 | "Average time to make integral image", iiTime, |
264 | "Capacity left in first core", percentRatioStrOneDigit(freeInCore()), |
265 | "Total CPU used", cpuTotal(), |
266 | ); |
267 | } |
268 | |
269 | S cpuTotal() { |
270 | ret setFieldAndReturn(cpuTotal := percentRatioStrOneDigit((1-freeInCore())/numberOfCores())); |
271 | } |
272 | |
273 | double freeInCore() { |
274 | ret ratio(toSeconds(screenShotCountdownTotalSleepTime), |
275 | elapsedSeconds(loopStarted)); |
276 | } |
277 | |
278 | replace jSection with jCenteredSection. |
279 | {} |
280 | visualize { |
281 | imageSurface = new IIImageSurface; |
282 | imageSurface.setAutoZoomToDisplay(true); |
283 | setDoubleBuffered(imageSurface, true); |
284 | imageSurface.setPixelated(true); |
285 | imageSurface.noAlpha = true; |
286 | |
287 | var vis = northAndCenterWithMargin( |
288 | withMargin(withLabel("Show", |
289 | comboBoxAndButton( |
290 | onSelectedItem( |
291 | bindComboBoxToLiveValue(centerComboBox(autoComboBox(uiURL, cloneKeys(uiMap))), dm_fieldLiveValue uiURL()), |
292 | url -> showUIURL(url) |
293 | ), |
294 | "Go", url -> showUIURL(url)))), |
295 | mainArea = singleComponentPanel(renderUIUrl(uiURL))); |
296 | setHorizontalMarginForAllButtons(vis, 4); |
297 | ret vis; |
298 | } |
299 | |
300 | BufferedImage lastScreenImage() { ret getVar(getVar(lastScreen)); } |
301 | |
302 | void adjustUIForPoppedOutWindow swing { |
303 | if (popDownButton == null) { |
304 | Window window = cast getWindow(dm_vis()); |
305 | |
306 | var popBackInButton = findButton(window, "Pop Back In"); |
307 | var parent = getParent(popBackInButton); |
308 | print(+parent); |
309 | |
310 | removeFromParent(parent); // hide controls |
311 | |
312 | popDownButton = jPopDownButton_noText( |
313 | "Pop Back In", r { dm_popInModule(me()) }, |
314 | jCheckBoxMenuItem("Always On Top", isAlwaysOnTop(window), |
315 | rEnter dm_toggleAlwaysOnTop), |
316 | ); |
317 | addControl(popDownButton); |
318 | } |
319 | } |
320 | |
321 | public bool useErrorHandling() { false; } |
322 | |
323 | JComponent renderUIUrl aka renderUIURL aka uiGet(S url) { |
324 | var maker = uiMap.get(url); |
325 | var component = callF(maker); |
326 | if (component != null) ret component; |
327 | ret jCenteredLabel("URL not found: " + url); |
328 | } |
329 | |
330 | void showUIURL(S url) enter { |
331 | url = trim(url); |
332 | setComponent(mainArea, renderUIUrl(url)); |
333 | } |
334 | |
335 | <A extends JComponent> A uiMapPut(S url, IF0<A> maker) { |
336 | uiMap.put(url, -> maker!); |
337 | ret maker!; |
338 | } |
339 | |
340 | void uiPut(S url, IF0<JComponent> maker) { |
341 | uiMap.put(url, maker); |
342 | } |
343 | |
344 | void initUIMap { |
345 | uiPut("FPS", -> jSection("FPS", dm_calculatedCenteredLabel(() -> iround(fps)))); |
346 | |
347 | uiPut("Screen Selector", -> { |
348 | var screenSelectors = jRadioButtons( |
349 | countIteratorAsList(screenCount(), |
350 | i -> "Screen " + (i+1))); |
351 | selectRadioButton(screenSelectors, lookAtScreen); |
352 | onRadioButtonChange(screenSelectors, i -> { setField(lookAtScreen := i); }); |
353 | ret jline(buttonsInGroup(screenSelectors)); |
354 | }); |
355 | |
356 | uiPut("Screenshot with controls", -> northAndCenterWithMargin( |
357 | topControls2 = /*jflowCenter*/ jPanel(new WrapLayout, flattenList2( |
358 | dm_checkBox enabled(), |
359 | getChildren(renderUIURL("Screen Selector")), |
360 | dm_spinnerWithLabel gridRows("Rows", 1, 500), |
361 | dm_checkBox("Scale down", "scaleDownPreviewImage"), |
362 | dm_spinnerWithLabel previewPosterization("Posterize", 2, 256) |
363 | )), |
364 | jscroll_center(imageSurface))); |
365 | |
366 | uiPut("Enabled", -> dm_checkBox enabled()); |
367 | |
368 | uiPut("Home", -> |
369 | hsplit(northAndCenterWithMargin( |
370 | topControls = hgrid( |
371 | renderUIUrl("FPS"), |
372 | jSection("Compression", dm_centeredFieldLabel longTermCompressionScore()), |
373 | //jSection("Probability", dm_centeredFieldLabel longTermCompressionProbability()), |
374 | jSection("CPU (" + numberOfCores() + ")", dm_centeredFieldLabel cpuTotal()) |
375 | ), |
376 | tabs), |
377 | renderUIUrl("Screenshot with controls") |
378 | )); |
379 | } |
380 | } // end of module |
Began life as a copy of #1033653
download show line numbers debug dex old transpilations
Travelled to 2 computer(s): bhatertpkbcr, mqqgnosmbjvj
No comments. add comment
Snippet ID: | #1033656 |
Snippet name: | GazelleV 22 backup |
Eternal ID of this version: | #1033656/1 |
Text MD5: | 750e0afd7072be6f0e85ce531ab12688 |
Author: | stefan |
Category: | javax / screen recognition |
Type: | JavaX source code (Dynamic Module) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2021-12-26 15:37:20 |
Source code size: | 12404 bytes / 380 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 159 / 140 |
Referenced in: | [show references] |