Uses 1482K of libraries. Click here for Pure Java version (10357L/55K).
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 | |
18 | PersistableThrowable lastProcessingError; |
19 | transient WithTimestamp<OKOrError<BufferedImage>> lastScreen; |
20 | transient new Average screenShotTime; |
21 | transient new Average iiTime; |
22 | transient Timestamp loopStarted; |
23 | transient new RestartableCountdown screenShotCountdown; |
24 | //transient ImageSurface imageSurface; |
25 | transient IIImageSurface imageSurface; |
26 | transient Throwable currentProcessingError; |
27 | transient BufferedImage previewImage; |
28 | transient JButton popDownButton; |
29 | transient JComponent topControls; |
30 | transient long screenShotsTaken; |
31 | transient double fps; |
32 | transient Compression ongoingCompression, completedCompression; |
33 | transient S longTermCompressionProbability; |
34 | transient S longTermCompressionScore; |
35 | transient JComponent topControls2; |
36 | |
37 | Rect area() { |
38 | ret screenBounds(min(lookAtScreen, screenCount()-1)); |
39 | } |
40 | |
41 | class Compression { |
42 | settable BufferedImage image; |
43 | settable BWIntegralImage ii; |
44 | CompressionSearch_AnyType search; |
45 | int baseLineLength; // length of trivial compression |
46 | GridCodec1 codec; |
47 | double compressionPercentage; |
48 | |
49 | S score() { |
50 | var submission = search?.bestSubmission(); |
51 | Int compressedSize = or(submission.compressedSize(), baseLineLength); |
52 | compressionPercentage = doubleRatio(compressedSize, baseLineLength)*100; |
53 | ret formatDouble(compressionPercentage, 3) + "%"; |
54 | } |
55 | |
56 | IProbabilisticScheduler scheduler() { |
57 | ret search?.scheduler(); |
58 | } |
59 | |
60 | S probability() { |
61 | var scheduler = scheduler(); |
62 | if (scheduler == null) ret "-"; |
63 | var prob = scheduler.lastExecutedProbability(); |
64 | ret formatDouble(prob, 3); |
65 | } |
66 | |
67 | event compressionDone; |
68 | |
69 | run { |
70 | int lHex = pixelCount(image)*8; |
71 | baseLineLength = calculateLengthOfFunctionCall imageFromHex(lHex+2); |
72 | print(+baseLineLength); |
73 | |
74 | codec = new GridCodec1(image); |
75 | codec.rows = gridRows; |
76 | search = codec.forward(); |
77 | //showImage(codec.renderCellsLinearly()); |
78 | |
79 | thread "Gazelle Visual" { |
80 | repeat 60 { |
81 | stepForNSeconds(1, search); |
82 | //print(stepCount := search.scheduler().stepCount()); |
83 | setFields( |
84 | longTermCompressionProbability := probability(), |
85 | longTermCompressionScore := score()); |
86 | } |
87 | |
88 | try { |
89 | compressionDone(); |
90 | |
91 | L<IJavaExpr> cellCompressions = codec.strat.codeForElements(); |
92 | //showText("Compression", lines(map shorten_str(cellCompressions))); |
93 | |
94 | /*S code = str(codec.winnerCode()); |
95 | S name = "Screenshot " + ymdMinusHMS(); |
96 | File f = makeFileNameUnique_beforeExtension( |
97 | javaxDataDir("Compressed Screenshots/" + name + ".javax")); |
98 | saveTextFile(f, code); |
99 | printFileInfo(f); |
100 | saveGZTextFile(f = replaceExtension(f, ".jgz"), code); |
101 | printFileInfo(f);*/ |
102 | |
103 | /* |
104 | print("Evaling " + nChars(code)); |
105 | //LL<Int> lol = cast dm_javaEval(code); |
106 | BufferedImage restored = cast dm_javaEval(code); |
107 | assertImagesIdentical(restored, image); |
108 | print("Image restored!"); |
109 | |
110 | dm_showImage("Restored from " + nChars(code), restored); |
111 | */ |
112 | } catch e { printStackTrace(e); } |
113 | } |
114 | } |
115 | |
116 | void drawOverlay(ImageSurface is, Graphics2D g) pcall { |
117 | codec.drawOverlay(is, g); |
118 | } |
119 | } |
120 | |
121 | start-thread { |
122 | dm_registerAs_direct gazelleV(); |
123 | dm_watchField enabled(r { if (enabled) dm_reload(); }); |
124 | |
125 | // TODO: react to event sent by OS |
126 | dm_doEvery(1.0, r { |
127 | if (dm_moduleIsPoppedOut()) adjustUIForPoppedOutWindow(); |
128 | }); |
129 | |
130 | print("Screen bounds: " + allScreenBounds()); |
131 | |
132 | dm_doEvery(min(statsEvery, 10.0), statsEvery, r { if (enabled) printStats(); }); |
133 | |
134 | loopStarted = tsNow(); |
135 | shoot(); |
136 | } |
137 | |
138 | void shoot enter { |
139 | if (!enabled) ret; |
140 | |
141 | long targetTime = sysNow()+iround(1000/maxFPS); |
142 | long time = nanoTime(); |
143 | |
144 | try { |
145 | lastScreen = withTimestamp(okOrError(-> screenshot(area()))); |
146 | ++screenShotsTaken; |
147 | setField(fps := doubleRatio(screenShotsTaken, elapsedSeconds(loopStarted))); |
148 | screenShotTime.add(nanosToSeconds(nanoTime()-time)); |
149 | time = nanoTime(); |
150 | if (lastScreen->isOK()) { |
151 | var img = lastScreen!!; |
152 | var ii = BWIntegralImage(img); |
153 | //var ii = BWIntegralImage_luminosity(lastScreen!!); |
154 | iiTime.add(nanosToSeconds(nanoTime()-time)); |
155 | |
156 | if (eq(previewMode, "showLatestGrabbed")) |
157 | imageSurface?.setImage(ii, img); |
158 | |
159 | if (ongoingCompression == null) |
160 | startCompression(ii); |
161 | } |
162 | |
163 | cpuTotal(); |
164 | currentProcessingError = null; |
165 | } catch print e { |
166 | setField(lastProcessingError := currentProcessingError = e); |
167 | sleepSeconds(60); // errors in processing are no good |
168 | } |
169 | |
170 | screenShotCountdown.setTargetTime(targetTime, r shoot); |
171 | } |
172 | |
173 | void startCompression(BWIntegralImage ii) { |
174 | if (ongoingCompression == null) { |
175 | ongoingCompression = new Compression() |
176 | .image(lastScreen!!) |
177 | .ii(ii); |
178 | ongoingCompression.onCompressionDone(-> { |
179 | completedCompression = ongoingCompression; |
180 | ongoingCompression = null; |
181 | |
182 | imageSurface?.setImage(completedCompression.ii, completedCompression.image); |
183 | imageSurface.setOverlay(g -> completedCompression.drawOverlay(imageSurface, g)); |
184 | }); |
185 | ongoingCompression.run(); |
186 | } |
187 | } |
188 | |
189 | void printStats() { print(stats()); } |
190 | |
191 | S stats() { |
192 | var screen = lastScreen?!; |
193 | ret formatColonProperties_noNulls( |
194 | "Monitored area", area(), |
195 | "Error", screen?.getError(), |
196 | "Last screenshot taken", lastScreen?.timeStamp(), |
197 | "Average time to take a screenshot", screenShotTime, |
198 | "Average time to make integral image", iiTime, |
199 | "Capacity left in first core", percentRatioStrOneDigit(freeInCore()), |
200 | "Total CPU used", cpuTotal(), |
201 | ); |
202 | } |
203 | |
204 | S cpuTotal() { |
205 | ret setFieldAndReturn(cpuTotal := percentRatioStrOneDigit((1-freeInCore())/numberOfCores())); |
206 | } |
207 | |
208 | double freeInCore() { |
209 | ret ratio(toSeconds(screenShotCountdown.totalSleepTime), |
210 | elapsedSeconds(loopStarted)); |
211 | } |
212 | |
213 | replace jSection with jCenteredSection. |
214 | {} |
215 | visualize { |
216 | imageSurface = new IIImageSurface; |
217 | setDoubleBuffered(imageSurface, true); |
218 | imageSurface.noAlpha = true; |
219 | |
220 | var screenSelectors = jRadioButtons( |
221 | countIteratorAsList(screenCount(), |
222 | i -> "Screen " + (i+1))); |
223 | onRadioButtonChange(screenSelectors, i -> { lookAtScreen = i; }); |
224 | |
225 | ret hsplit(northAndCenterWithMargin( |
226 | topControls = hgrid( |
227 | jSection("FPS", dm_calculatedCenteredLabel(() -> iround(fps))), |
228 | jSection("Compression", dm_centeredFieldLabel longTermCompressionScore()), |
229 | jSection("Probability", dm_centeredFieldLabel longTermCompressionProbability()), |
230 | jSection("CPU (" + numberOfCores() + ")", dm_centeredFieldLabel cpuTotal()) |
231 | ), |
232 | super.visualize() /* print log */), |
233 | northAndCenterWithMargin( |
234 | topControls2 = jCenteredLine(listPlus(wideningListCast Component(buttonsInGroup(screenSelectors)), |
235 | dm_spinnerWithLabel gridRows(1, 500))), |
236 | jscroll_center(imageSurface))); |
237 | } |
238 | |
239 | BufferedImage lastScreenImage() { ret getVar(getVar(lastScreen)); } |
240 | |
241 | void adjustUIForPoppedOutWindow swing { |
242 | if (popDownButton == null) { |
243 | Window window = cast getWindow(dm_vis()); |
244 | |
245 | var popBackInButton = findButton(window, "Pop Back In"); |
246 | var parent = getParent(popBackInButton); |
247 | print(+parent); |
248 | |
249 | removeFromParent(parent); // hide controls |
250 | |
251 | popDownButton = jPopDownButton_noText( |
252 | "Pop Back In", r { dm_popInModule(me()) }, |
253 | jCheckBoxMenuItem("Always On Top", isAlwaysOnTop(window), |
254 | rEnter dm_toggleAlwaysOnTop), |
255 | ); |
256 | addControl(popDownButton); |
257 | } |
258 | } |
259 | } |
Began life as a copy of #1033309
download show line numbers debug dex old transpilations
Travelled to 2 computer(s): bhatertpkbcr, mqqgnosmbjvj
No comments. add comment
Snippet ID: | #1033508 |
Snippet name: | Gazelle V, New UI [compacted, HEAD] |
Eternal ID of this version: | #1033508/30 |
Text MD5: | bd7d10c8bdc89e397aa60b3f87a1db17 |
Transpilation MD5: | 004f911c2f86b1d408ea8fce1769d700 |
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-10-30 18:45:21 |
Source code size: | 8561 bytes / 259 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 185 / 329 |
Version history: | 29 change(s) |
Referenced in: | [show references] |