/** * ImageLoader and related data fields pre-fetch the next JPEG PImage * in a separate thread. The data fields used for communication must * be thread-safe. fnames must be stable before a thread is started * on ImageLoader.run(). UPDATE FROM BlurPosterizeInteractive TO PosterizeSegmentInteractive: * Now send an array of PImage objects, with the actual image in [0], * and subimages partitioned by underlying dominant color found using * filter(POSTERSIZE,2), up to 8 additional PImages (2R * 2G * 2B), * making a max of nine possible. **/ final SynchronousQueue loaded = new SynchronousQueue(); volatile int curloc = 41 ; volatile CopyOnWriteArrayList fnames = null ; volatile float feathering = 0.0 ; volatile int blurfactor = 0; volatile int posterizefactor = 0 ; volatile float thresholdfactor = 0.0; volatile boolean isgray = false ; volatile boolean isSaturate = false ; class ImageLoader implements Runnable { final int [] posterFilters = { // set of colors when posterize at level 2. 0x0, // black 0x0ff0000, // red 0x0ffff00, // yellow 0x000ff00, // green 0x000ffff, // cyan 0x00000ff, // blue 0x0ff00ff, // magenta 0x0ffffff // white }; public void run() { PixelArrayVisitorColorSorterFactory vf = new PixelArrayVisitorColorSorterFactory(); while (true) { PImage myimg = loadImage(fnames.get(curloc)); myimg.resize(width, height); myimg.loadPixels(); if (isSaturate) { for (int i = 0 ; i < myimg.pixels.length ; i++) { int p = myimg.pixels[i]; if ((p & 0xff000000) != 0 && (p & 0x00ffffff) != 0) { // not transparent and not black int a = (p >> 24) & 0x00ff ; int r = (p >> 16) & 0x00ff ; int g = (p >> 8) & 0x00ff ; int b = p & 0x00ff ; int max = (r > g) ? r : g ; if (b > max) { max = b ; } if (max > 127) { if (r > g && r > b) { // r = (int)(255.0 * r / max); r = 255 ; if (abs(r-g) < 25) { g = 255 ; } if (abs(r-b) < 25) { b = 255 ; } } else if (g > r && g > b) { // g = (int)(255.0 * g / max); g = 255 ; if (abs(r-g) < 25) { r = 255 ; } if (abs(g-b) < 25) { b = 255 ; } } else { // b = (int)(255.0 * b / max); b = 255 ; if (abs(b-g) < 25) { g = 255 ; } if (abs(r-b) < 25) { r = 255 ; } } myimg.pixels[i] = (a << 24) | (r << 16) | (g << 8) | b ; } } } myimg.updatePixels(); myimg.loadPixels(); } PImage filtered = myimg.copy(); filtered.filter(POSTERIZE, 2); filtered.loadPixels(); int [][] blenders = new int[1][]; blenders[0] = filtered.pixels ; PImage [] result = new PImage [ posterFilters.length + 1 ]; TreeMap keywordParams = new TreeMap(); // DEBUG inside loop??? keywordParams.put("feathering", new Float(feathering)); for (int i = 0 ; i < posterFilters.length ; i++) { keywordParams.put("colormask", new Integer(posterFilters[i])); int [] newpix = PixelArrayMapReducer.mapThenReducePixelsArray( myimg.pixels, myimg.width, myimg.height, vf, blenders, keywordParams, false); PImage newimg = createImage(myimg.width, myimg.height, ARGB); newimg.loadPixels(); System.arraycopy(newpix, 0, newimg.pixels, 0, newpix.length); newimg.updatePixels(); result[i+1] = newimg ; } myimg.updatePixels(); result[0] = myimg ; if (blurfactor > 0 || posterizefactor > 1 || thresholdfactor > 0.0 || isgray) { for (PImage p : result) { if (blurfactor > 0) { p.filter(BLUR, blurfactor); } if (posterizefactor > 1) { p.filter(POSTERIZE, posterizefactor); } if (isgray) { p.filter(GRAY); } if (thresholdfactor > 0.0) { p.filter(THRESHOLD, thresholdfactor); } } } boolean pending = true ; while (pending) { try { loaded.put(result); pending = false ; } catch (java.lang.InterruptedException xx) { } } curloc = (curloc + 1) % fnames.size() ; } } } class PixelArrayVisitorColorSorterFactory implements PixelArrayVisitorFactory { public PixelArrayVisitor make(int[] pixels, int width, int height, int rowY, int[][] blenders, Map keyParams, boolean isMutate) { return new PixelArrayVisitorColorSorter(pixels, width, height, rowY, blenders, keyParams); } } int lastcolormask = -1 ; class PixelArrayVisitorColorSorter extends PixelArrayVisitorHelper { public PixelArrayVisitorColorSorter(int[] pixels, int width, int height, int rowY, int[][] blenders, Map keyParams) { super(pixels, width, height, rowY, blenders, keyParams, false); } public PixelArrayVisitorContainer call() { //System.err.println("DEBUG ENTER call") ; System.err.flush(); int [] blender = blenders[0]; int [] row = new int [ width ]; // initially all zeroes, including alpha int ix = rowY * width ; int blank = 0x00000000 ; //colorMode(255,255,255,0); //System.err.println("DEBUG call about to loop") ; System.err.flush(); int centerx = width >> 1 ; int centery = height >> 1 ; int radius = Math.min(centerx, centery); int deltay = rowY - centery ; int colormask = ((Integer)(sketchParams.get("colormask"))).intValue(); Float featherobj = ((Float)(sketchParams.get("feathering"))); for (int i = 0 ; i < row.length ; i++, ix++) { if ((blender[ix] & 0x0ffffff) == colormask) { // if (colormask != lastcolormask) { println("DEBUG COLORMASK " + colormask); lastcolormask = colormask;} row[i] = pixels[ix]; if (featherobj != null) { float feathering = featherobj.floatValue(); if (feathering > 0.0) { int deltax = i - centerx ; double proximtyToCenter = 1.0 - constrain(((float)Math.sqrt(deltax * deltax + deltay * deltay) / radius), 0.0, 1.0); int alpha = (int)Math.round(proximtyToCenter * 255.0 * feathering); row[i] = (row[i] & 0x00ffffff) | (alpha << 24); // print("dsketchArgs[0] = " + dsketchArgs[0] + ", alpha = " + alpha + " "); } } } else { row[i] = blank ; } } PixelArrayVisitorContainer result = new PixelArrayVisitorContainer(row, rowY); //System.err.println("DEBUG LEAVING call") ; System.err.flush(); return result ; } }