SHOW:
|
|
- or go back to the newest paste.
1 | package test; | |
2 | ||
3 | /* | |
4 | * A simple example of how to invert/modify bitmaps with java. | |
5 | * | |
6 | * Copyright (C) 2012 Ma_Sys.ma | |
7 | * | |
8 | * This program is free software: you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License as published by | |
10 | * the Free Software Foundation, either version 3 of the License, or | |
11 | * (at your option) any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
20 | */ | |
21 | ||
22 | // Basic Imports that could be helpful | |
23 | import javax.imageio.*; | |
24 | import java.awt.*; | |
25 | import java.awt.image.*; | |
26 | import java.io.*; | |
27 | import java.lang.*; | |
28 | import java.lang.reflect.*; | |
29 | import java.util.*; | |
30 | ||
31 | public class InvertColors { | |
32 | ||
33 | public static class LoopInverter extends DistributedLoopThread { | |
34 | ||
35 | private BufferedImage img; | |
36 | ||
37 | public LoopInverter(Integer start, Integer end, DistributedLoop ownerLoop) { | |
38 | super(start, end, ownerLoop); | |
39 | } | |
40 | ||
41 | public void pass(Object...data) { | |
42 | img = (BufferedImage)data[0]; | |
43 | } | |
44 | ||
45 | protected void execLoop() { | |
46 | int width = img.getWidth(); | |
47 | - | int j; |
47 | + | int ems = END - START; // end minus start |
48 | - | int[] line; |
48 | + | // Get an area of pixels |
49 | - | for(int i = START; i < END; i++) { |
49 | + | int[] pixels = img.getRGB(0, START, img.getWidth(), ems, null, 0, width); |
50 | - | // Get a single line of pixels |
50 | + | for(int j = 0; j < pixels.length; j++) { |
51 | - | line = img.getRGB(0, i, img.getWidth(), 1, null, 0, width); |
51 | + | // Actual inversion |
52 | - | for(j = 0; j < line.length; j++) { |
52 | + | pixels[j] = 0xffffff ^ pixels[j]; |
53 | - | // Actual inversion |
53 | + | |
54 | - | line[j] = 0xffffff ^ line[j]; |
54 | + | // Store the pixels back into the image |
55 | img.setRGB(0, START, width, ems, pixels, 0, width); | |
56 | - | // Store the pixels back into the image |
56 | + | |
57 | - | img.setRGB(0, i, width, 1, line, 0, width); |
57 | + | |
58 | } | |
59 | ||
60 | public static void main(String[] args) { | |
61 | System.out.println("Invert Colors 1.0, Copyright (c) 2012 Ma_Sys.ma."); | |
62 | System.out.println("For further info send an e-mail to Ma_Sys.ma@web.de."); | |
63 | System.out.println(); | |
64 | if(args.length != 1) { | |
65 | System.out.println("Usage: java test.InvertColors [image]"); | |
66 | System.exit(1); | |
67 | } | |
68 | ||
69 | int extensionPosition = args[0].lastIndexOf('.'); | |
70 | if(extensionPosition == -1) { | |
71 | System.out.println("Unable to determine input filetype."); | |
72 | System.exit(1); | |
73 | } | |
74 | ||
75 | // Read image data | |
76 | BufferedImage img; | |
77 | try { | |
78 | img = ImageIO.read(new File(args[0])); | |
79 | } catch(IOException ex) { | |
80 | System.err.println("Unable to read image from " + args[0]); | |
81 | ex.printStackTrace(); | |
82 | System.exit(2); | |
83 | return; // "Variable might not have been initialized." | |
84 | } | |
85 | ||
86 | long start = System.currentTimeMillis(); // Measure time | |
87 | ||
88 | // Invert all pixels using all processors | |
89 | // See LoopInverter for the actual calculation | |
90 | DistributedLoop loop; | |
91 | try { | |
92 | loop = new DistributedLoop(DistributedLoop.AUTO_DETERMINE_THREADS, 0, img.getHeight(), LoopInverter.class, null, null); | |
93 | } catch(InstantiationException ex) { | |
94 | System.err.println("Unable to create distributed loop."); | |
95 | ex.printStackTrace(); | |
96 | System.exit(4); | |
97 | return; // s. o. | |
98 | } | |
99 | loop.passArgumentsOnAll(img); | |
100 | loop.startAll(); | |
101 | ||
102 | System.out.println("Took " + (System.currentTimeMillis() - start) + " ms for the actual calculation."); | |
103 | ||
104 | // Write image data | |
105 | try { | |
106 | ImageIO.write(img, "png", new File(args[0].substring(0, extensionPosition) + "_inverted.png")); | |
107 | } catch(IOException ex) { | |
108 | System.err.println("Unable to write PNG image file."); | |
109 | ex.printStackTrace(); | |
110 | System.exit(3); | |
111 | } | |
112 | } | |
113 | ||
114 | } | |
115 | ||
116 | // --------------------------------------- | |
117 | // From the Tools Library in Version 2.0 | |
118 | // --------------------------------------- | |
119 | ||
120 | /** | |
121 | * <p> | |
122 | * Ermöglicht es, Rechenlast auf mehrere Kerne zu verteilen, indem eine | |
123 | * Schleife in mehrere Teile aufgesplittet wird. Somit lassen sich Schleifen | |
124 | * mit mehr Einträgen als Kerne vorhanden sind problemlos parallelisieren, wenn | |
125 | * innerhalb der Schleife kein Ergebnis des vorherigen Durchganges benötigt wird. | |
126 | * </p><p> | |
127 | * Die Nutzung ist alles andere als einfach und soll deshalb am Beispiel gezeigt | |
128 | * werden. | |
129 | * </p><p> | |
130 | * Alle Werte eines Arrays sollen initialisiert werden, indem | |
131 | * komplexe Objekte erzeugt werden, deren Erstellung lange dauert: | |
132 | * <br /> | |
133 | * <pre> | |
134 | package ma.tools.concurrent; | |
135 | ||
136 | import ma.tools.concurrent.DistributedLoop; | |
137 | import ma.tools.concurrent.DistributedLoopThread; | |
138 | ||
139 | public class DistributedLoopExample { | |
140 | ||
141 | private static int nr = 1; | |
142 | ||
143 | public DistributedLoopExample() { | |
144 | super(); | |
145 | int objects = 32; | |
146 | long start; | |
147 | ||
148 | // 1. Test mit normaler Schleife | |
149 | start = System.currentTimeMillis(); | |
150 | ComplexObject[] allObjects = new ComplexObject[objects]; | |
151 | for(int i = 0; i < objects; i++) { | |
152 | allObjects[i] = new ComplexObject(); | |
153 | } | |
154 | System.out.println("Normalerweise braucht man " + (System.currentTimeMillis() - start) + " ms zum Erstellen der Objekte."); | |
155 | ||
156 | // 2. Test mit verteilter Schleife | |
157 | start = System.currentTimeMillis(); | |
158 | allObjects = new ComplexObject[objects]; | |
159 | DistributedLoop loop; | |
160 | try { | |
161 | loop = new DistributedLoop(DistributedLoop.AUTO_DETERMINE_THREADS, 0, objects, CreatorInstance.class, null, this); | |
162 | } catch(InstantiationException ex) { | |
163 | ex.printStackTrace(); | |
164 | return; | |
165 | } | |
166 | // Wir wollen das Array nicht als mehrere Argumente übergeben | |
167 | loop.passArgumentsOnAll((Object)allObjects); | |
168 | loop.startAll(); | |
169 | System.out.println("Verteilt dauert es (nur?) " + (System.currentTimeMillis() - start) + " ms"); | |
170 | } | |
171 | ||
172 | public class CreatorInstance extends DistributedLoopThread { | |
173 | ||
174 | private ComplexObject[] allObjects; | |
175 | ||
176 | public CreatorInstance(Integer start, Integer end, DistributedLoop ownerLoop) { | |
177 | super(start, end, ownerLoop); | |
178 | } | |
179 | ||
180 | protected void pass(Object...data) { | |
181 | allObjects = (ComplexObject[])data[0]; | |
182 | } | |
183 | ||
184 | protected void execLoop() { | |
185 | for(int i = START; i < END; i++) { | |
186 | allObjects[i] = new ComplexObject(); | |
187 | } | |
188 | } | |
189 | ||
190 | } | |
191 | ||
192 | private class ComplexObject { | |
193 | ||
194 | public ComplexObject() { | |
195 | int cnr = nr++; | |
196 | System.out.println("Komplexes Objekt " + cnr + " erstellen..."); | |
197 | // Zeit die es braucht um ein Objekt zu erstellen (hier künstlich verlangsamt) | |
198 | try { | |
199 | Thread.sleep(250); | |
200 | } catch(InterruptedException ex) { | |
201 | System.out.println("Komplexes Objekt " + cnr + ": Erstellung abgebrochen: " + ex.toString()); | |
202 | } | |
203 | System.out.println("Komplexes Objekt " + cnr + " fertig."); | |
204 | } | |
205 | } | |
206 | ||
207 | public static void main(String[] args) { | |
208 | new DistributedLoopExample(); | |
209 | } | |
210 | ||
211 | } | |
212 | * </pre> | |
213 | * <br /> | |
214 | * Wenn man die "künstlich verlängernden" Zeilen wegnimmt, sieht man | |
215 | * sehr gut, dass es einen Overhead (auf dem Testsystem rund 3ms) durch | |
216 | * die Paralelisierung gibt. Deshalb lohnt es sich nur bei der Erstellung | |
217 | * von Objekten, die zusammen "relativ lange" brauchen, was auch schon bei | |
218 | * z.B. 200 ms der Fall ist. Dadurch lohnt sich das Verteilte Rechnen an | |
219 | * vielen Stellen. | |
220 | * </p> | |
221 | * <p> | |
222 | * Hinweis #1: Bei Spiecherintensiven Anwendungen könnte es anders sein. | |
223 | * Hier hilft es, beides zu testen. | |
224 | * Das ist sehr einfach möglich, indem man dem Constructor als | |
225 | * "preferredThreadCount" die Zahl 1 (keine parallelisierung) | |
226 | * übergibt. Dies vermindert den Overhead aber nur sehr geringfügig. | |
227 | * Wenn es knapp ist, sollte man eine "richtige" Schleife testen. | |
228 | * </p><p> | |
229 | * Hinweis #2: Rechenintensive Anwendungen profitieren eventuell vom | |
230 | * Java Native Interface. | |
231 | * </p><p> | |
232 | * Hinweis #3: Optimieren Sie auch den Inhalt der Schleifen | |
233 | * Sollte eigentlich klar sein. | |
234 | * </p> | |
235 | * | |
236 | * @version 1.0.1 | |
237 | * @author Linux-Fan, Ma_Sys.ma | |
238 | */ | |
239 | class DistributedLoop { | |
240 | ||
241 | public static final int AUTO_DETERMINE_THREADS = -1; | |
242 | ||
243 | private DistributedLoopThread[] allThreads; | |
244 | ||
245 | private int readyThreads; | |
246 | ||
247 | private boolean started; | |
248 | ||
249 | private DistributedLoopUser owner; | |
250 | ||
251 | private ArrayList<Exception> theExceptions; | |
252 | ||
253 | public DistributedLoop(int preferredThreadCount, int lStart, int lEnd, Class<? extends DistributedLoopThread> threadClass, DistributedLoopUser owner, Object enclosing) throws InstantiationException { | |
254 | super(); | |
255 | this.owner = owner; | |
256 | theExceptions = new ArrayList<Exception>(); | |
257 | int realThreadCount = 0; | |
258 | if(preferredThreadCount == AUTO_DETERMINE_THREADS) { | |
259 | realThreadCount = Runtime.getRuntime().availableProcessors(); | |
260 | } else { | |
261 | realThreadCount = preferredThreadCount; | |
262 | } | |
263 | int range = lEnd - lStart; | |
264 | if(range < realThreadCount) { | |
265 | realThreadCount = range; | |
266 | } | |
267 | allThreads = new DistributedLoopThread[realThreadCount]; | |
268 | readyThreads = 0; | |
269 | started = false; | |
270 | int perThread = range / allThreads.length; | |
271 | for(int i = 0; i < allThreads.length; i++) { | |
272 | final int cStart = lStart + perThread * i; | |
273 | final int cEnd; | |
274 | if(i == (allThreads.length - 1)) { | |
275 | cEnd = lEnd; | |
276 | } else { | |
277 | cEnd = lStart + perThread * (i + 1); | |
278 | } | |
279 | try { | |
280 | if(enclosing == null) { | |
281 | allThreads[i] = threadClass.getConstructor(Integer.class, Integer.class, getClass()).newInstance(cStart, cEnd, this); | |
282 | } else { | |
283 | allThreads[i] = threadClass.getConstructor(enclosing.getClass(), Integer.class, Integer.class, getClass()).newInstance(enclosing, cStart, cEnd, this); | |
284 | } | |
285 | allThreads[i].setName("Distributed Loop Thread " + (i + 1)); | |
286 | } catch(Exception ex) { | |
287 | InstantiationException er = new InstantiationException("Unable to create distributed loop thread."); | |
288 | er.initCause(ex); | |
289 | throw er; | |
290 | } | |
291 | } | |
292 | } | |
293 | ||
294 | public Iterator<Exception> startAll() { | |
295 | if(!started) { | |
296 | started = true; | |
297 | for(int i = 0; i < allThreads.length; i++) { | |
298 | allThreads[i].start(); | |
299 | } | |
300 | if(owner == null) { | |
301 | for(int i = 0; i < allThreads.length; i++) { | |
302 | try { | |
303 | allThreads[i].join(); | |
304 | } catch(InterruptedException ex) { | |
305 | System.err.println("ma.tools.concurrent.DistributedLoop: Thread interrupted: " + ex.toString()); | |
306 | } catch(IllegalThreadStateException ex) { | |
307 | System.err.println("ma.tools.concurrent.DistributedLoop: " + ex.toString()); | |
308 | } | |
309 | } | |
310 | return theExceptions.iterator(); | |
311 | } else { | |
312 | return null; | |
313 | } | |
314 | } else { | |
315 | throw new IllegalThreadStateException("Distributed loop was already started."); | |
316 | } | |
317 | } | |
318 | ||
319 | public void interruptAll() { | |
320 | for(int i = 0; i < allThreads.length; i++) { | |
321 | if(allThreads[i].isAlive()) { | |
322 | allThreads[i].interrupt(); | |
323 | } | |
324 | } | |
325 | } | |
326 | ||
327 | public Object[] callOnAll(Method m, Object...params) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { | |
328 | Object[] allRets = new Object[allThreads.length]; | |
329 | for(int i = 0; i < allThreads.length; i++) { | |
330 | allRets[i] = m.invoke(allThreads[i], params); | |
331 | } | |
332 | return allRets; | |
333 | } | |
334 | ||
335 | public DistributedLoopThread[] getThreads() { | |
336 | return allThreads; | |
337 | } | |
338 | ||
339 | public void passArgumentsOnAll(Object...data) { | |
340 | for(int i = 0; i < allThreads.length; i++) { | |
341 | allThreads[i].pass(data); | |
342 | } | |
343 | } | |
344 | ||
345 | protected void readyCountUp() { | |
346 | readyThreads++; | |
347 | if(readyThreads == allThreads.length && owner != null) { | |
348 | owner.distributedThreadsReady(theExceptions.toArray(new Exception[theExceptions.size()])); | |
349 | } | |
350 | } | |
351 | ||
352 | protected void passException(Exception ex) { | |
353 | theExceptions.add(ex); | |
354 | } | |
355 | ||
356 | public Iterator<Exception> getExceptions() { | |
357 | return theExceptions.iterator(); | |
358 | } | |
359 | ||
360 | } | |
361 | ||
362 | abstract class DistributedLoopThread extends Thread { | |
363 | ||
364 | protected final int START; | |
365 | protected final int END; | |
366 | protected final DistributedLoop OWNER; | |
367 | ||
368 | public DistributedLoopThread(Integer start, Integer end, DistributedLoop ownerLoop) { | |
369 | super(); | |
370 | this.START = start; | |
371 | this.END = end; | |
372 | this.OWNER = ownerLoop; | |
373 | } | |
374 | ||
375 | public void run() { | |
376 | try { | |
377 | execLoop(); | |
378 | } catch(Exception ex) { | |
379 | OWNER.passException(ex); | |
380 | } | |
381 | OWNER.readyCountUp(); | |
382 | } | |
383 | ||
384 | protected void pass(@SuppressWarnings("unused") Object...data) {} | |
385 | ||
386 | protected abstract void execLoop() throws Exception; | |
387 | ||
388 | } | |
389 | ||
390 | /** | |
391 | * <p>Veraltetes Interface.</p> | |
392 | * <p> | |
393 | * Kann genutzt werden, wenn man beim beenden alle Threads in | |
394 | * eine andere Methode springen will. | |
395 | * </p> | |
396 | * | |
397 | * @version 1.0.0.1 | |
398 | * @author Linux-Fan, Ma_Sys.ma | |
399 | * @deprecated | |
400 | * Mittlerweile ist es möglich, dass {@link DistributedLoop#startAll()} | |
401 | * auf das Beenden der Threads wartet, ohne einen eigenen Wartethread zu | |
402 | * erzeugen. | |
403 | */ | |
404 | interface DistributedLoopUser { | |
405 | ||
406 | public void distributedThreadsReady(Exception[] passed); | |
407 | ||
408 | } |