# Fading and Zoom (image slideshow)

**URL:** https://discourse.processing.org/t/fading-and-zoom-image-slideshow/40812
**Category:** Coding Questions
**Created:** [February 2, 2023, 11:39pm UTC](https://discourse.processing.org/t/fading-and-zoom-image-slideshow/40812 "2023-02-02T23:39:04Z")
**Posts on this page:** 14
**Page:** 2

<div class="post-metadata">

### Author: ![JonnieNightTime](https://avatars.discourse-cdn.com/v4/letter/j/ecb155/32.png) [@JonnieNightTime](https://discourse.processing.org/u/JonnieNightTime)
#### Post date: [March 1, 2023, 12:08pm UTC](https://discourse.processing.org/t/fading-and-zoom-image-slideshow/40812/21 "2023-03-01T12:08:05Z")

</div>

I’m so confused, I’m not getting this at all…hmmm

---

<div class="post-metadata">

### Author: ![mnse](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/mnse/32/16520_2.png) [@mnse](https://discourse.processing.org/u/mnse)
#### Post date: [March 2, 2023, 3:42pm UTC](https://discourse.processing.org/t/fading-and-zoom-image-slideshow/40812/22 "2023-03-02T15:42:21Z")

</div>

Well, a bit too fency but by processing 4+ you can do s.th. like that for the image list… 😉

Cheers  
— mnse

```auto
PImage[] images;
int currentImage=0;
void setup() {
  size(500,500,P2D);
  File directory = new File(dataPath(""));    
  images = directory.isDirectory() // directory exists ?
         ? java.util.stream.Stream.of(directory.listFiles()) // get the list of File Objects
           .filter(f -> f.isFile()) // is it a regular file ?
           .map(File::getAbsolutePath) // convert to a path string
           .filter(f -> f.matches(".*(?i)(\\.(jpg|png))$")) // does extension fits in ? 
           .map(f -> loadImage(f)) // make it a PImage
           .filter(java.util.Objects::nonNull) // filter if loading failed
           .toArray(PImage[]::new) // convert to PImage array
         : new PImage[0]; // not a directory or not exists give empty default 
                 
  if(images.length > 0)
    printArray(images);
  else
    println("No valid images");  
}

void draw() {
  background(0);
  if (images.length > 0) {
    surface.setTitle("Image: " + currentImage);
    image(images[currentImage],0,0,width,height);
    if (frameCount % 120 == 0)
      currentImage = (currentImage + 1) % images.length;
  }  
}

```

---

<div class="post-metadata">

### Author: ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)
#### Post date: [March 2, 2023, 6:41pm UTC](https://discourse.processing.org/t/fading-and-zoom-image-slideshow/40812/23 "2023-03-02T18:41:07Z")

</div>

> [@JonnieNightTime](#):
>
> Does this indicate then that my images are not readable?

I just want to add that the names of the images must match exactly and it’s case-sensitive.

So 8.PNG won’t work. Not all file explorers / finder show the file extension correctly.

---

<div class="post-metadata">

### Author: ![mnse](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/mnse/32/16520_2.png) [@mnse](https://discourse.processing.org/u/mnse)
#### Post date: [March 2, 2023, 6:53pm UTC](https://discourse.processing.org/t/fading-and-zoom-image-slideshow/40812/24 "2023-03-02T18:53:41Z")

</div>

> [@mnse](#):
>
> `.*(?i)(\\.(jpg|png))$`

This matches case insensitive. To make it case sensitive remove the `(?!)`

Cheers  
— mnse

---

<div class="post-metadata">

### Author: ![JonnieNightTime](https://avatars.discourse-cdn.com/v4/letter/j/ecb155/32.png) [@JonnieNightTime](https://discourse.processing.org/u/JonnieNightTime)
#### Post date: [March 3, 2023, 10:16pm UTC](https://discourse.processing.org/t/fading-and-zoom-image-slideshow/40812/25 "2023-03-03T22:16:48Z")

</div>

Thanks for the guidance - noted

---

<div class="post-metadata">

### Author: ![JonnieNightTime](https://avatars.discourse-cdn.com/v4/letter/j/ecb155/32.png) [@JonnieNightTime](https://discourse.processing.org/u/JonnieNightTime)
#### Post date: [March 3, 2023, 10:21pm UTC](https://discourse.processing.org/t/fading-and-zoom-image-slideshow/40812/26 "2023-03-03T22:21:36Z")

</div>

Dear mnse - very fancy indeed - working well - I can see the potential here. What is the terminology to correctly refer to how you’ve done what you’ve done? i.e the lines from. How can I get a better grasp of the syntax you’ve used - all the . 's, → 's, : 's and ::'s!!

```auto
  images = directory.isDirectory() // directory exists ?
..
...
...
 : new PImage[0]; // not a directory or not exists give empty default

```

I’m also a bit lost about how to incorporate this with the earlier examples with fade and zoom - is there some advantage in using an PImage array here rather than a (hugely exotic sounding) ArrayList as earlier?

---

<div class="post-metadata">

### Author: ![mnse](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/mnse/32/16520_2.png) [@mnse](https://discourse.processing.org/u/mnse)
#### Post date: [March 4, 2023, 9:00am UTC](https://discourse.processing.org/t/fading-and-zoom-image-slideshow/40812/27 "2023-03-04T09:00:13Z")

</div>

Hi @JonnieNightTime,

Sorry! completely missed out that we are want working with ArrayList above … 🙂  
Here is an adjusted version which generates an ArrayList instead of an array…  
I’ve also adjusted the error handling because loadImage could result in two kinds of errors  
and also added some status messages for loading…

```auto
import java.util.stream.Stream;
import java.util.stream.Collectors;
import java.util.Objects;

ArrayList<PImage> images;
int currentImage=0;

void setup() {
  size(500, 500, P2D);
  textAlign(CENTER, CENTER);
  textSize(32);
  File directory = new File(dataPath(""));
  images = directory.isDirectory() // directory exists ?
         ? Stream.of(directory.listFiles()) // get a list of file objects as stream 
           .filter(File::isFile) // filter for regular files
           .map(File::getAbsolutePath) // convert to a path string
           .filter(str -> str.matches(".*(?i)(\\.(jpg|png))$")) // filter for wanted extensions
           .peek(str -> print("try loading image [" + str + "]: ")) // print info which image should be loaded
           .map(str -> loadImage(str)) // make it a PImage
           .peek(pimg -> println((pimg==null || pimg.width==-1) ? "failed!" : "succeeded!")) // print status of loading
           .filter(pimg -> pimg != null && pimg.width != -1) // filter for successfully loaded images
           .collect(Collectors.toCollection(ArrayList::new)) // convert to ArrayList of PImage
         : new ArrayList<>(); // not a valid directory set empty default

  if (images.size() < 1)
    print("No valid images found!");
  else
    print("images found: " + images.size());
}

void draw() {
  background(0);
  if (images.size() > 0) {
    surface.setTitle("Image: " + currentImage);
    image(images.get(currentImage), 0, 0, width, height);
    if (frameCount % 120 == 0)
      currentImage = (currentImage + 1) % images.size();
  } else {
    text("No valid images found!", width/2, height/2);
    return;
  }
}

```

* * *
The terminology is called java streams and lambda expressions introduced by java 8 (which is now possible to use since Processing 4 rolled out with a modern java version).
* * *
There are many resources which can be found for further information. I've attached two which should give you some information as a starting point below...

> **[A Guide to Java Streams in Java 8: In-Depth Tutorial With Examples](https://stackify.com/streams-guide-java-8/)**
>
> Java streams were a much anticipated Java feature. Learn how to use the supported operations to write cleaner and more concise code.

> **[Java Stream Filter with Lambda Expression | Baeldung](https://www.baeldung.com/java-stream-filter-lambda)**
>
> Learn how to use lambda expressions with Stream.filter() and handle checked exceptions

Hope that helps…

Cheers  
— mnse

---

<div class="post-metadata">

### Author: ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)
#### Post date: [March 4, 2023, 10:21am UTC](https://discourse.processing.org/t/fading-and-zoom-image-slideshow/40812/28 "2023-03-04T10:21:36Z")

</div>

> [@mnse](#):
>
> ```auto
> images = directory.isDirectory() // directory exists ?
> ? Stream.of..........................
> 
> ```

Yeah, the main bit is the ternary operator with

images = test ? expression1 : expression2

- `images =` is the target ArrayList
- test is `directory.isDirectory() `
- expression1 is the long java stream and lambda expressions
- expression2 is just `new ArrayList<>(); ` when it fails

see [?: (conditional) / Reference / Processing.org](https://processing.org/reference/conditional.html)

getting rid of the ternary operator gives us:

```auto
if(directory.isDirectory()) {
    // Yes 
    images = 
      Stream.of(directory.listFiles()) // get a list of file objects as stream 
           .filter(File::isFile) // filter for regular files
           .map(File::getAbsolutePath) // convert to a path string
           .filter(str -> str.matches(".*(?i)(\\.(jpg|png))$")) // filter for wanted extensions
           .peek(str -> print("try loading image [" + str + "]: ")) // print info which image should be loaded
           .map(str -> loadImage(str)) // make it a PImage
           .peek(pimg -> println((pimg==null || pimg.width==-1) ? "failed!" : "succeeded!")) // print status of loading
           .filter(pimg -> pimg != null && pimg.width != -1) // filter for successfully loaded images
           .collect(Collectors.toCollection(ArrayList::new)); // convert to ArrayList of PImage
}
else {
    // fail
    images = new ArrayList<>(); 
}

```

* * *

> [@mnse](#):
>
> `str.matches(".*(?i)(\\.(jpg|png))$"))`

this is a `regular expression` which is a smart way to analyze a String. Checks if the ending is jpg or png etc.

similar see [match() / Reference / Processing.org](https://processing.org/reference/match_.html)

---

<div class="post-metadata">

### Author: ![mnse](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/mnse/32/16520_2.png) [@mnse](https://discourse.processing.org/u/mnse)
#### Post date: [March 4, 2023, 12:47pm UTC](https://discourse.processing.org/t/fading-and-zoom-image-slideshow/40812/29 "2023-03-04T12:47:41Z")

</div>

Just for the sake of completeness another variant which uses exception handling and the advantages of the newly introduced `Files.list` Method by java 8 (which not loading the whole Files as a list at once, but rather as a lazy stream)

Cheers  
— mnse

```auto
import java.util.stream.Stream;
import java.util.stream.Collectors;
import java.util.Objects;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.Path;

ArrayList<PImage> images;
int currentImage=0;

void setup() {
  size(500, 500, P2D);
  textAlign(CENTER, CENTER);
  textSize(32);

  try (Stream<Path> stream = Files.list(Paths.get(dataPath("")))) {
    images = stream // get a list of file objects as stream
      .filter(Files::isRegularFile) // filter for regular files
      .map(Path::toAbsolutePath) // Get the Filename
      .map(Path::toString) // convert to a path string
      .filter(str -> str.matches(".*(?i)(\\.(jpg|png))$")) // filter for wanted extensions
      .peek(str -> print("try loading image [" + str + "]: ")) // print info which image should be loaded
      .map(str -> loadImage(str)) // make it a PImage
      .peek(pimg -> println((pimg==null || pimg.width==-1) ? "failed!" : "pass!")) // print loding info message  
      .filter(Objects::nonNull) // filter for successfully loaded images
      .filter(pimg -> pimg.width != -1) // filter for successfully loaded images
      .collect(Collectors.toCollection(ArrayList::new)); // convert to ArrayList of PImage
  }
  catch(Exception e) {
    println("Warning: " + e.getMessage());
    images = new ArrayList<>();
  }

  if (images.size() < 1)
    print("No valid images found!");
  else
    print("images found: " + images.size());
}

void draw() {
  background(0);
  if (images.size() > 0) {
    surface.setTitle("Image: " + currentImage);
    image(images.get(currentImage), 0, 0, width, height);
    if (frameCount % 120 == 0)
      currentImage = (currentImage + 1) % images.size();
  } else {
    text("No valid images found!", width/2, height/2);
    return;
  }
}

```

* * *
Further info:

[https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/file/Files.html#list(java.nio.file.Path)](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/file/Files.html#list(java.nio.file.Path))

---

<div class="post-metadata">

### Author: ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)
#### Post date: [March 4, 2023, 1:23pm UTC](https://discourse.processing.org/t/fading-and-zoom-image-slideshow/40812/30 "2023-03-04T13:23:17Z")

</div>

This is a much simpler solution to load all images from a sketch’s “data/” folder via [**listPaths()**](http://processing.github.io/processing-javadocs/core/processing/core/PApplet.html#listPaths-java.lang.String-java.lang.String...-): 📁

> [@How do I slowly layer photos to appear on top of eachother?](https://discourse.processing.org/t/how-do-i-slowly-layer-photos-to-appear-on-top-of-eachother/36698/5):
>
> This example loads all images inside subfolder “data/” and assign them to a PImage[] array: framed_picture /\*\* \* Load All Images (v1.0.0) \* GoToLoop (2022/May/04) \* \* https://Discourse.Processing.org/t/ \* how-do-i-slowly-layer-photos-to-appear-on-top-of-eachother/36698/5 \*/ static final String PICS\_EXTS = "extensions=,png,jpg,jpeg,gif,tif,tiff,tga,bmp"; static final float FPS = .25; PImage[] images; void setup() { size(600, 500); frameRate(FPS); imageMode(CENTER); images =…

---

<div class="post-metadata">

### Author: ![mnse](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/mnse/32/16520_2.png) [@mnse](https://discourse.processing.org/u/mnse)
#### Post date: [March 4, 2023, 2:08pm UTC](https://discourse.processing.org/t/fading-and-zoom-image-slideshow/40812/31 "2023-03-04T14:08:44Z")

</div>

Hi @GoToLoop,

Quite funny… Never stumbled about listPaths. 🙂

Nevertheless, the `loadAllImages` of your post missing some error handling, though.

Imo also don’t think it is really easier, but there are various methods to reach the goal. I only wanted to demonstrate a way that is almost safe and makes use of the “new” Java features. 😉

Cheers  
— mnse

---

<div class="post-metadata">

### Author: ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)
#### Post date: [March 4, 2023, 4:33pm UTC](https://discourse.processing.org/t/fading-and-zoom-image-slideshow/40812/32 "2023-03-04T16:33:04Z")

</div>

> [@mnse](#):
>
> Quite funny… Never stumbled about [**listPaths()**](http://processing.github.io/processing-javadocs/core/processing/core/PApplet.html#listPaths-java.lang.String-java.lang.String...-). 🙂

Well, it’s not listed at Processing’s online reference either: 🤷‍♂️

> **[Reference](https://processing.org/reference/)**
>
> Find further documentation of the Processing language

> [@mnse](#):
>
> IMO also don’t think it is really easier; but there are various methods to reach the goal.

Well, AFAIK, there’s not a single example about Java streams on Processing’s examples yet; b/c obviously it’s only now debuting on P4:

> **[Examples](https://processing.org/examples/)**
>
> Short, prototypical programs exploring the basics of programming with Processing.

And Java streams subject isn’t exactly beginner’s friendly, especially when considering Processing’s target audience.

And I guess every1 would agree cryptic RegExp is the hardest feature to master in programming. 😈

> [@mnse](#):
>
> … a way that is almost safe and makes use of the “new” Java features. 😉

B/c we’re still transitioning from P3 to P4 (P4 is still buggy btW! 🪲), it’s safer to code examples that’d run on both P3 & P4 for now.

So when we create a P4-only sketch, it’d be nice to also post a P3-compatible version if possible. 🥺

> [@mnse](#):
>
> Nevertheless, the **loadAllImages()** of your post is missing some error handling, though.

For simplification’s sake, indeed that function assumes that any image file found inside “data/” subfolders should load w/o any errors; which is likely true 99%. 😛

But for parity’s sake to your P4-only solution, I’ve upgraded my sketch w/ more checks & features: 😇

```auto
/**
 * Load All Images (v1.0.2)
 * GoToLoop (2023/Mar/04)
 *
 * https://Discourse.Processing.org/t/fading-and-zoom-image-slideshow/40812/32
 *
 * https://Discourse.Processing.org/t/
 * how-do-i-slowly-layer-photos-to-appear-on-top-of-eachother/36698/5
 */

static final String PICS_EXTS = "extensions=,png,jpg,jpeg,gif,bmp";
static final float FPS = .25;

PImage[] images;

void setup() {
  size(1200, 700);

  frameRate(FPS);
  imageMode(CENTER);

  images = loadAllImages();
  if (images.length == 0) exit();
}

void draw() {
  final int idx = frameCount % images.length;

  clear();
  image(images[idx], width >> 1, height >> 1);
  surface.setTitle("Index: " + idx);
}

PImage[] loadAllImages() {
  final File dir = dataFile("");
  println(dir);

  if (!dir.isDirectory()) {
    println("Sketch's subfolder \"data/\" hasn't been created yet!");
    return new PImage[0];
  }

  final String[] imagePaths =
    listPaths(dir.getPath(), "files", "recursive", PICS_EXTS);

  final int found = imagePaths.length;
  final ArrayList<PImage> imgs = new ArrayList<PImage>(found);

  java.util.Arrays.sort(imagePaths);
  printArray(imagePaths);

  for (final String path : imagePaths) {
    final PImage img = loadImage(path);
    if (img != null && img.width > 0) imgs.add(img);
  }

  final int valid = imgs.size(), rejected = found - valid;

  print("Found", found, "image file(s) and ");
  println(valid, "is/are valid (", rejected, "rejected ).");

  return imgs.toArray(new PImage[valid]);
}

```

---

<div class="post-metadata">

### Author: ![JonnieNightTime](https://avatars.discourse-cdn.com/v4/letter/j/ecb155/32.png) [@JonnieNightTime](https://discourse.processing.org/u/JonnieNightTime)
#### Post date: [March 5, 2023, 10:26pm UTC](https://discourse.processing.org/t/fading-and-zoom-image-slideshow/40812/33 "2023-03-05T22:26:04Z")

</div>

Just to say how appreciative I am of the input here - totally blown away by your knowledge, clarity and consideration.

I’ve landed on the below - and using some images based on microorganisms and adding Blob detection the result is looking pretty splendid. I’ll soon be working towards sending OSC messages from selected Blob values - mentioning this because there might be implications for my next question.

 ![Screenshot 2023-03-05 at 22.25.00](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/9/b/9b6cd262a8361f3e49597b8f478a0b396f661ae5.jpeg)

```auto
///////////////////////////////////////////////////////// IMPORT LIBS

import blobDetection.*;

import java.util.Date;
import java.util.stream.Stream;
import java.util.stream.Collectors;
import java.util.Objects;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.Path;

import milchreis.imageprocessing.*; //unused right now!@!@

import netP5.*;
import oscP5.*;
import processing.video.*;

///////////////////////////////////////////////////////// Blob Variables

PImage Blobimg;
BlobDetection theBlobDetection;
PImage img;

///////////////////////////////////////////////////////// Camera Variables (for BlobDetection)

Capture cam;
boolean newFrame=false;

///////////////////////////////////////////////////////// Graphics Variables

PGraphics canvas;

///////////////////////////////////////////////////////// Img Variables

ArrayList<PImage> images;
int currentImage=0;
int lastImageIndex = 0;
int nextImageIndex = 1;
int cImageIndex = 1;
float alphaValue = 0;
//float alphaShift = 0.0004; // very slow
//float alphaShift = 0.004; // slow
float alphaShift = 0.008; // MEDIUM
//float alphaShift = 0.04; // fast

int randomIndexFade;
float zoomFactor = 0.1;

///////////////////////////////////////////////////////// OSC / Network Variables
OscP5 oscP5;
NetAddress myRemoteLocation;

void setup() { /////////////////////////////////////////////////////////////// setup starts
  //fullScreen(P3D,0);

  //size(1920,1080, P3D); // HDTV 1080, FullHD, 1080p
  //size(1280, 720, P3D); //HD
  size(1024,576, P3D);
  
  canvas = createGraphics(width, height);
  
  cam = new Capture(this,160,120); // for Blob
  cam.start();
  
  // BlobDetection
  // img which will be sent to detection (a smaller copy of the cam frame);
  Blobimg = new PImage(80,60); 
  theBlobDetection = new BlobDetection(Blobimg.width, Blobimg.height);
  theBlobDetection.setPosDiscrimination(true);
  theBlobDetection.setThreshold(0.08); // will detect bright areas whose luminosity > 0.1;

  try (Stream<Path> stream = Files.list(Paths.get(dataPath("")))) {
    images = stream // get a list of file objects as stream
      .filter(Files::isRegularFile) // filter for regular files
      .map(Path::toAbsolutePath) // Get the Filename
      .map(Path::toString) // convert to a path string
      .filter(str -> str.matches(".*(?i)(\\.(jpg|png))$")) // filter for wanted extensions
      .peek(str -> print("try loading image [" + str + "]: ")) // print info which image should be loaded
      .map(str -> loadImage(str)) // make it a PImage
      .peek(pimg -> println((pimg==null || pimg.width==-1) ? "failed!" : "pass!")) // print loding info message  
      .filter(Objects::nonNull) // filter for successfully loaded images
      .filter(pimg -> pimg.width != -1) // filter for successfully loaded images
      .collect(Collectors.toCollection(ArrayList::new)); // convert to ArrayList of PImage
  }
  catch(Exception e) {
    println("Warning: " + e.getMessage());
    images = new ArrayList<>();
  }
    if (images.size() < 1)
    print("No valid images found!");
    else
    print("images found: " + images.size());
    
    myRemoteLocation = new NetAddress("192.168.2.10",12000); // to BlackIpad TouchOSC
    
    noStroke();
    frameRate(60);   

} //////////////////////////////////////////////////////////////////////////// setup ends

void captureEvent(Capture cam) //////////////////////////////////////////// captureEvent()
{
  cam.read();
  newFrame = true;
}

void draw() { ////////////////////////////////////////////////////////////////// draw loop
  background(0);
  
    if (images.size() > 0) {
    surface.setTitle("Image: " + currentImage);
    image(images.get(currentImage), 0, 0, width, height);
    if (frameCount % 120 == 0)
      currentImage = (currentImage + 1) % images.size();
  } else {
    text("No valid images found!", width/2, height/2);
    return;
  }

  int ListSize = images.size();
  float RandomIndex = random(ListSize);
  int RandomIndexInt = round (RandomIndex);

  fade(lastImageIndex, nextImageIndex, alphaValue, nextImageIndex % 2 != 0);
  if (alphaValue >= 1.0) {
    lastImageIndex = nextImageIndex;
    nextImageIndex = (lastImageIndex + RandomIndexInt) % images.size();
    cImageIndex = (lastImageIndex + RandomIndexInt) % images.size();
    alphaValue = 0;
  }
  alphaValue += alphaShift;
  
  if (newFrame)
  {
    newFrame=false;
    image(cam,0,0,0,0);
    Blobimg.copy(canvas, 0, 0, canvas.width, canvas.height, 0, 0, Blobimg.width, Blobimg.height);
    theBlobDetection.computeBlobs(Blobimg.pixels);
    drawBlobsAndEdges(true,true);
  }  
  
} ///////////////////////////////////////////////////////////////////////// draw loop end

void fade(int l, int n, float a, boolean zi) { //////////////////////////// fade Start

    canvas.beginDraw();
    canvas.background(0);
    canvas.pushMatrix();
    
    //canvas.image(outAB, 0,0); 

  if (l >= 0) {
    float invAlpha = 1.0-a;
    canvas.tint(#0000ff,invAlpha * 255);
    PImage limg=images.get(l);
    canvas.imageMode(CENTER);
    canvas.image(limg, width/2, height/2, width, height);
  }
    canvas.tint(#0000ff, a * 255);
    PImage nimg=images.get(n);
    canvas.imageMode(CENTER);
    canvas.image(nimg, width/2, height /2, width, height);

    canvas.popMatrix();
    canvas.endDraw();
    image(canvas, 0, 0);
  
} //////////////////////////////////////////////////////////////////////////////// fade End

void drawBlobsAndEdges(boolean drawBlobs, boolean drawEdges) { ////////////// BlobsAndEdges 

 strokeWeight(width /999); 

  Blob b;
  EdgeVertex eA,eB;
  for (int n=0 ; n<theBlobDetection.getBlobNb() ; n++)
  {
    b=theBlobDetection.getBlob(n);
    if (b!=null)
    {
      if (drawEdges) // Edges
      { 
        smooth();
        strokeWeight(3);
        stroke(255, 255, 255, 127);
        for (int m=0;m<b.getEdgeNb();m++)
        { eA = b.getEdgeVertexA(m); eB = b.getEdgeVertexB(m);
          if (eA !=null && eB !=null)
          line(eA.x * width, eA.y * height, eB.x * width, eB.y * height );
        
          //println(theBlobDetection.getBlobNb()+ " blobs"); use the first 8 blobs at any given time 
          //- send their x and y as SC
  }
      }
      
      if (drawBlobs) // Blobs
        noFill();
      {
        strokeWeight(1);
        stroke(0, 127, 255, 127);
        
        rect(b.xMin * width,b.yMin * height, b.w * width,b.h * height);}
        
        fill(#00ccff, 127);
        textSize(9);
        text(b.xMin, b.xMin * width,b.yMin * height);
        println(b.xMin + " x " + b.yMin + " y ");

    }
      }
} /////////////////////////////////////////////////////////////////////// BlobsAndEdges end

```

The next nut to crack, (and my brain melts at even trying to formulate the question) relates to this code’s role in the larger project I’m working on. GoToLoop and Chrisir might recall GoTo’s awesome solution to an earlier question [How should I organise this? 256 array with conditional content - Class? - #4 by GoToLoop](https://discourse.processing.org/t/how-should-i-organise-this-256-array-with-conditional-content-class/40290/4) Is it possible to put this Slideshow into an abstract class? Perhaps not because now “those cool stuffs don’t fit into a method”?

---

<div class="post-metadata">

### Author: ![JonnieNightTime](https://avatars.discourse-cdn.com/v4/letter/j/ecb155/32.png) [@JonnieNightTime](https://discourse.processing.org/u/JonnieNightTime)
#### Post date: [March 5, 2023, 10:31pm UTC](https://discourse.processing.org/t/fading-and-zoom-image-slideshow/40812/34 "2023-03-05T22:31:45Z")

</div>

i.e.  
Main sketch

```auto
void draw(){
..
    stuffs[PatternPlusBankOffSet].display(); // call createCoolStuff patterns
...
}

```

And Patterns

```auto
void createCoolStuffs() {
  
   stuffs[0] = new CoolStuff() { 
    @Override public void display() { 
      
// image slideshow here somehow
// also blob detection
// other methods?
   
    }
  }

```

[Previous page](https://discourse.processing.org/t/fading-and-zoom-image-slideshow/40812.md?page=1)
