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 [email protected].");
| |
| 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 | } |