View difference between Paste ID: 6hy6Q89V and t20mjMRy
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 &lt; 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
}