# Crop multiple images to any (quad) shape and place them side by side filling the canvas (comic strip)

**URL:** <https://discourse.processing.org/t/crop-multiple-images-to-any-quad-shape-and-place-them-side-by-side-filling-the-canvas-comic-strip/41326>\
**Category:** Project Guidance\
**Created:** [March 16, 2023, 6:00pm UTC](https://discourse.processing.org/t/crop-multiple-images-to-any-quad-shape-and-place-them-side-by-side-filling-the-canvas-comic-strip/41326 "2023-03-16T18:00:08Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![Twooze](https://avatars.discourse-cdn.com/v4/letter/t/96bed5/32.png) [@Twooze](https://discourse.processing.org/u/Twooze)\
**Post date:** [March 16, 2023, 6:00pm UTC](https://discourse.processing.org/t/crop-multiple-images-to-any-quad-shape-and-place-them-side-by-side-filling-the-canvas-comic-strip/41326/1 "2023-03-16T18:00:08Z")

</div>

Hi all, I have been struggling with this for days and I can’t find an answer anywhere. Perhaps I am overlooking something obvious or perhaps its just not possible.

I am trying to write a code that takes images from my data set and puts them onto an ‘a4’ structuring randomly them like a comic or collage without any overlap. Now getting the full size images to do this was pretty easy, but this leaves a lot of white space between the images/on the side. So I used a the get() function to load in a image, get a piece of it (cropping the image) and drawing that so it fits better. But the next step is where I got stuck, I want more flexibility in the layout.

The first thing I thought, why not get() a different shape, a circle or a quad. This doens’t seem possible.  
Then I thought I could draw negative shapes and put the image behind it, like a shape cut out of paper. This how ever poses the problem that when I put images next to each other they overlap ‘behind the paper’ hiding part of the first image.  
Then I looked at masks, but that had the same problem as the previous one. It even had a bigger problem, masks dont seem to work if the image doesn’t have the same size as the entire canvas. So that doesn’t really work with multiple images or with images that don’t have dimensions of an a4  
The last option I looked at was to use texture(). This seemed perfect, I could just draw a quad to begin with and put an image on there as a texture. At first I thought it worked great, but the texture function warps the texture and doesn’t crop it.

If any one has any ideas on how to tackle this (even if the aswer is don’t use processing use …) I would love to know. I just came back to processing because I have used it a lot in the past. Here is a simple layout that could be generated.

 ![Comic_layout](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/9/c/9c4d35ad3abf100f0985ba628f7b15774c79d24c.webp)

---

<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 17, 2023, 9:17am UTC](https://discourse.processing.org/t/crop-multiple-images-to-any-quad-shape-and-place-them-side-by-side-filling-the-canvas-comic-strip/41326/2 "2023-03-17T09:17:04Z")

</div>

In my opinion a Desktop Publishing Program such as Indesign or canva would be more suitable to do this.

In processing, I would work with transparency.

When you store Comic\_layout as a png (or use PGraphics, you might have the actual “windows” (comic panes) transparent and the lines in between (the frames) opaque white.

Similarly when you have the images of the actual comic as png you can cut of a triangle in the corner (for you 2nd row for example) and make the triangle transparent.

I haven’t achieved this at all.

```auto

//

int[] listImagesPerRow = {
  2,
  3,
  2,
  2
};

PVector[] c1= {
  new PVector(20, 174),
  new PVector(209, 174),
  new PVector(129, 313),
  new PVector(20, 313)
};

PVector[] c2= {
  new PVector(228, 174),
  new PVector(373, 174),
  new PVector(292, 313),
  new PVector(148, 313)
};

ArrayList<PImage> images = new ArrayList<PImage>();

PImage pageLayout ;

// --------------------------------------------------------------------------------------------

void setup() {
  size(512, 640);

  String[] lines;

  File file = new File(dataPath(""));
  if (file.isDirectory()) {
    lines = file.list();
  } else {
    lines = null;
  }

  if (lines == null) {
    println("NO");
    exit();
    return;
  }

  // printArray(lines);

  for (String line : lines) {
    if (line.equals("Comic_layout.png"))
      continue; // skip
    PImage img = loadImage(line);
    img.resize(int(width/2.0)-20, height/listImagesPerRow.length);
    images.add(img);
  }//for

  pageLayout = loadImage ("Comic_layout.png");
  println(pageLayout.width);
  println(pageLayout.height);
  //
  println ("end of setup()");
}

void draw() {
  // noLoop();
  // background(0);

  int k=0;
  float x=10, y=10;
  for (int y22 : listImagesPerRow ) {

    x=10;
    for (int x1 = 0; x1 < y22; x1++ ) {

      if (y22 == 3)
        images.get(k).resize(int(width/3.0)-20, height/listImagesPerRow.length);

      image ( images.get(k), x, y );

      k++;
      if (y22 == 2)
        x+=width/2.0;
      else if (y22 == 3)
        x+=width/3.0;
    }
    //
    y+=height/listImagesPerRow.length + 10;
  }

  // -----------------------------------------------------------------------
  // image ( pageLayout, 0, 0);
  showList(c1);
  showList(c2);

  fill(0);
  text(mouseX+" "+mouseY, 12, 12);
}//func

void mousePressed() {
  println(mouseX+","+mouseY);
}

void showList (PVector [] list ) {
  noFill();
  stroke(0);
  beginShape();
  for (PVector pv : list)
    vertex(pv.x, pv.y);
  endShape(CLOSE);
}
// --------------------------------------------------------------------------------------------
//

```

---

<div class="post-metadata">

**Author:** ![Twooze](https://avatars.discourse-cdn.com/v4/letter/t/96bed5/32.png) [@Twooze](https://discourse.processing.org/u/Twooze)\
**Post date:** [March 17, 2023, 11:33am UTC](https://discourse.processing.org/t/crop-multiple-images-to-any-quad-shape-and-place-them-side-by-side-filling-the-canvas-comic-strip/41326/3 "2023-03-17T11:33:16Z")

</div>

Normaly I would also just do this by hand in Indesign, but I am trying to write a code that can loop though an big data set and export them as comic pages with a randomly generated layout so every page is different. My first thought was also to make an opague white frame first and put the image behind it, this way the images dont have to be stretched. But the problem comes when you try to put a second image next to it and it overlaps, so some how I need to cut out a triangle (or other shape) from an image. The get() solves this for squares, but I would love to have more flexibility in shapes. Perhaps this is just not possible in Processing. Here is an image for illustration:

 ![Example](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/d/6/d67231746680b463c9504f7f691f4612810144a4.jpeg)

---

<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 17, 2023, 11:46am UTC](https://discourse.processing.org/t/crop-multiple-images-to-any-quad-shape-and-place-them-side-by-side-filling-the-canvas-comic-strip/41326/4 "2023-03-17T11:46:53Z")

</div>

Did you look at `mask()`?

---

<div class="post-metadata">

**Author:** ![josephh](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/josephh/32/210_2.png) [@josephh](https://discourse.processing.org/u/josephh)\
**Post date:** [March 18, 2023, 4:29pm UTC](https://discourse.processing.org/t/crop-multiple-images-to-any-quad-shape-and-place-them-side-by-side-filling-the-canvas-comic-strip/41326/5 "2023-03-18T16:29:50Z")

</div>

Hi @Twooze,

Welcome to the forum! 😉

This is an interesting problem, I tried to solve it in my free time so thanks for that!

As pointed by @Chrisir, you can achieve that by using the [`mask()`](https://processing.org/reference/mask_.html) function. It uses grayscale data to mask parts of an image: dark for deleting parts and white for keeping them.

Let’s suppose you have an image and you want to crop it with a quad that has a shear angle of 20 degrees:

 ![quad_mask](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/1/d/1d76faf799a6545723e034f3f6d63d49808a58a7.png)

You can compute the coordinates of the quad to draw and display that on an empty image in white (to mask the rest):

```processing
PImage maskImageWithQuad(PImage img, float shearAngle) {
  // Use the same dimensions for mask()
  PGraphics quadMask = createGraphics(img.width, img.height); 
  
  // Compute the distance for the coordinates
  float shearDist = img.height * tan(radians(shearAngle));
  
  // Draw the quad on an off-screen canvas
  quadMask.beginDraw();
  quadMask.fill(255);
  quadMask.quad(0, 0, shearDist, img.height, img.width, img.height, img.width - shearDist, 0);
  quadMask.endDraw();
  
  // Make a copy of the image and apply the mask
  PImage maskedImage = img.copy();
  maskedImage.mask(quadMask);
  
  return maskedImage;
}

```

And use it like this:

```processing
PImage img = loadImage(...);
PImage masked = maskImageWithQuad(img, 20); // in degrees

```

You need to handle the edge cases where the first and last image are not masked with the same quad (the x coordinates of some points are not offset).

Now this is nice but you also need to randomly create the layout with rows of same height but different number of images / orientation. For each row, choose a random orientation (left, vertical or right) and a random number of images to display.

I won’t give the full code now but here are the different collage I am getting (using images from [Lorem Picsum](https://picsum.photos/)):

 ![comic_9](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/b/9/b92eb915e76d3dc6b7769a360245ea71bfab6ad7.jpeg) ![comic_40](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/4/9/49b84338b6ee03e7b04785a2e0089d22beeb59e2.jpeg)

 ![comic_69](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/c/4/c4fb9dd1497ff7db9847dedc9e862c173e2b62e0.jpeg)

Tell me if you have more questions!

---

<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 18, 2023, 4:42pm UTC](https://discourse.processing.org/t/crop-multiple-images-to-any-quad-shape-and-place-them-side-by-side-filling-the-canvas-comic-strip/41326/6 "2023-03-18T16:42:55Z")

</div>

extremely nice.

**remarks for the OP**

I think one thing is whether the initial image is landscape or portrait. You can determine it with checking `if(img.width>img.height)` I guess.

So maybe you want 2 layouts for a page, one with only landscape, the other with one or two portrait images possible.

Also, when you use resize: you can use 0 for x OR y to keep aspect ratio when you set the other (x or y).  
Maybe you still need to crop, but I think the 0 is helpful.

---

<div class="post-metadata">

**Author:** ![Twooze](https://avatars.discourse-cdn.com/v4/letter/t/96bed5/32.png) [@Twooze](https://discourse.processing.org/u/Twooze)\
**Post date:** [March 18, 2023, 10:25pm UTC](https://discourse.processing.org/t/crop-multiple-images-to-any-quad-shape-and-place-them-side-by-side-filling-the-canvas-comic-strip/41326/7 "2023-03-18T22:25:42Z")

</div>

Wow this looks really promissing! Thanks a lot for your time.  
I had something similar to this in my early tests, but the problem I had with the mask() function was that it kept telling me that to mask an image the image must have the same width and height as the window. I am still not sure how you got around that problem, but I’ll give your sollution a good try sometime next week and come back with my results!

---

<div class="post-metadata">

**Author:** ![Twooze](https://avatars.discourse-cdn.com/v4/letter/t/96bed5/32.png) [@Twooze](https://discourse.processing.org/u/Twooze)\
**Post date:** [March 18, 2023, 10:28pm UTC](https://discourse.processing.org/t/crop-multiple-images-to-any-quad-shape-and-place-them-side-by-side-filling-the-canvas-comic-strip/41326/8 "2023-03-18T22:28:08Z")

</div>

The 0 tip is a good one aswell! Thanks!

---

<div class="post-metadata">

**Author:** ![josephh](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/josephh/32/210_2.png) [@josephh](https://discourse.processing.org/u/josephh)\
**Post date:** [March 19, 2023, 12:20am UTC](https://discourse.processing.org/t/crop-multiple-images-to-any-quad-shape-and-place-them-side-by-side-filling-the-canvas-comic-strip/41326/9 "2023-03-19T00:20:51Z")

</div>

> [@Twooze](#):
>
> but the problem I had with the mask() function was that it kept telling me that to mask an image the image must have the same width and height as the window. I am still not sure how you got around that problem

From the [`mask()` reference page](https://processing.org/reference/mask_.html):

> The mask image needs to be the same size as the image to which it is applied.

So you need to construct a mask that has the same size as your image which is not too expensive and complicated 😉

---

<div class="post-metadata">

**Author:** ![Twooze](https://avatars.discourse-cdn.com/v4/letter/t/96bed5/32.png) [@Twooze](https://discourse.processing.org/u/Twooze)\
**Post date:** [March 20, 2023, 10:10pm UTC](https://discourse.processing.org/t/crop-multiple-images-to-any-quad-shape-and-place-them-side-by-side-filling-the-canvas-comic-strip/41326/10 "2023-03-20T22:10:36Z")

</div>

… Well I figured out why my previous code didn’t work. I wasn’t using a PGraphics to first fit the mask to the resized image, so the mask always took the width and height of the entire window. It was as simple as creating a graphic and resizing that to mask the image. Or simply just doing the image scaling after the mask is applied… then draw. I just had to switch one line of code hahaha, well thats coding in nutshell.  
Poeh thank you so much, I probably wouldn’t have figured this out without you!

---

<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 20, 2023, 10:13pm UTC](https://discourse.processing.org/t/crop-multiple-images-to-any-quad-shape-and-place-them-side-by-side-filling-the-canvas-comic-strip/41326/11 "2023-03-20T22:13:56Z")

</div>

Could you please be so kind and post your solution?

By the way I had a way to distribute images over the page with 2/3/2…

---

<div class="post-metadata">

**Author:** ![josephh](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/josephh/32/210_2.png) [@josephh](https://discourse.processing.org/u/josephh)\
**Post date:** [March 21, 2023, 8:51pm UTC](https://discourse.processing.org/t/crop-multiple-images-to-any-quad-shape-and-place-them-side-by-side-filling-the-canvas-comic-strip/41326/12 "2023-03-21T20:51:24Z")

</div>

Here it is 😇 (click to generate a new comic):

```processing
int seed = int(random(1000));

PImage getRandomImage(float w, float h) {
  String url = "https://picsum.photos/seed/" + seed + "/" + int(w) + "/" + int(h) + ".jpg";
  seed += 1;
  return loadImage(url);
}

PImage getRandomImageWithShear(float w, float h, float shearAngle, boolean flip, boolean shearLeft, boolean shearRight) {
  float shearDist = h * tan(radians(shearAngle));
  float imgFullWidth = w + shearDist;

  PImage img = getRandomImage(imgFullWidth, h);

  PGraphics quadMask = createGraphics(img.width, img.height);

  quadMask.beginDraw();
  if (flip) {
    quadMask.quad(
      0, 0,
      shearLeft ? shearDist : 0, img.height,
      img.width, img.height,
      img.width - (shearRight ? shearDist : 0), 0
      );
  } else {
    quadMask.quad(
      shearLeft ? shearDist : 0, 0,
      0, img.height,
      img.width - (shearRight ? shearDist : 0), img.height,
      img.width, 0
      );
  }
  quadMask.endDraw();

  img.mask(quadMask);
  return img;
}

int rows = 4;
int gap = 15;
int shearAngle = 20;
int maxImagesPerRow = 4;

void generateRandomComic() {
  background(255);

  float rowHeight = (height - ((rows + 1) * gap)) / rows;
  float rowWidth = width - 2 * gap;

  strokeWeight(2);
  noFill();
  translate(gap, gap);

  for (int row = 0; row < rows; row++) {
    float rowY = row * (rowHeight + gap);
    int divisions = int(random(1, maxImagesPerRow + 1));
    int orientation = int(random(3)) - 1;

    pushMatrix();
    translate(0, rowY);

    float pieceWidth = (rowWidth - (divisions - 1) * gap) / divisions;
    boolean shearFlip = orientation == 1;

    float angle = orientation == 0 ? 0 : shearAngle;
    float shearDist = rowHeight * tan(radians(angle));
    float pieceOffset = 0;

    for (int i = 0; i < divisions; i++) {
      boolean isFirst = i == 0;
      boolean isLast = i == divisions - 1;

      float pieceRealWidth = isFirst ? pieceWidth - shearDist : pieceWidth;
      PImage img = getRandomImageWithShear(pieceRealWidth, rowHeight, angle, shearFlip, !isFirst, !isLast);

      image(img, pieceOffset, 0);

      pieceOffset += pieceRealWidth + gap;
    }
    popMatrix();
  }
}

void setup() {
  size(560, 800);
  generateRandomComic();
}

void draw() {}

void mousePressed() {
  generateRandomComic();
}

```

It’s not commented and might be obscure without explanations thought 😏

You can also randomize the `rows`, `gap` and `shearAngle` global parameters to get interesting results!

 ![grid_98](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/7/6/76fa249a9508ed4f7f05bd55ac6c5da1a928908f.jpeg)

---

<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 21, 2023, 9:07pm UTC](https://discourse.processing.org/t/crop-multiple-images-to-any-quad-shape-and-place-them-side-by-side-filling-the-canvas-comic-strip/41326/13 "2023-03-21T21:07:25Z")

</div>

Thanks for that.

Still puzzles me that we crop big images.

In the format of the OP the images must be very wide and not very high…

* * *

**fullscreen comic page as a screensaver**

(not a screensaver as such, you need to start the Sketch)

```auto

// fullscreen comic page as a screen saver

int seed = int(random(1000));

int rows = 4;
int gap = 15;
int shearAngle = 20;
int maxImagesPerRow = 4;

// -------------------------------------------------------------------------------
// Two core functions

void setup() {
  // size(560, 800);
  fullScreen();
  // generateRandomComic();
  background(255);
}

void draw() {
  generateRandomComic();
}

// -------------------------------------------------------------------------------
// Input functions

void mousePressed() {
  generateRandomComic();
}

// -------------------------------------------------------------------------------
// 3 functions

void generateRandomComic() {

  // generate one page

  background(255);

  float rowHeight = (height - ((rows + 1) * gap)) / rows;
  float rowWidth = width - 2 * gap;

  strokeWeight(2);
  noFill();
  translate(gap, gap);

  for (int row = 0; row < rows; row++) {
    float rowY = row * (rowHeight + gap);
    int divisions = int(random(1, maxImagesPerRow + 1));
    int orientation = int(random(3)) - 1;

    pushMatrix();
    translate(0, rowY);

    float pieceWidth = (rowWidth - (divisions - 1) * gap) / divisions;
    boolean shearFlip = orientation == 1;

    float angle = orientation == 0 ? 0 : shearAngle;
    float shearDist = rowHeight * tan(radians(angle));
    float pieceOffset = 0;

    for (int i = 0; i < divisions; i++) {
      boolean isFirst = i == 0;
      boolean isLast = i == divisions - 1;

      float pieceRealWidth = isFirst ? pieceWidth - shearDist : pieceWidth;
      PImage img = getRandomImageWithShear(pieceRealWidth, rowHeight, angle, shearFlip, !isFirst, !isLast);

      image(img, pieceOffset, 0);

      pieceOffset += pieceRealWidth + gap; // x value
    }
    popMatrix();
  }
}

//

PImage getRandomImageWithShear(float w, float h,
  float shearAngle,
  boolean flip,
  boolean shearLeft, boolean shearRight) {
  //
  float shearDist = h * tan(radians(shearAngle));
  float imgFullWidth = w + shearDist;

  PImage img = getRandomImage(imgFullWidth, h);

  PGraphics quadMask = createGraphics(img.width, img.height);

  quadMask.beginDraw();
  if (flip) {
    quadMask.quad(
      0, 0,
      shearLeft ? shearDist : 0, img.height,
      img.width, img.height,
      img.width - (shearRight ? shearDist : 0), 0
      );
  } else {
    quadMask.quad(
      shearLeft ? shearDist : 0, 0,
      0, img.height,
      img.width - (shearRight ? shearDist : 0), img.height,
      img.width, 0
      );
  }
  quadMask.endDraw();

  img.mask(quadMask);
  return img;
}

//

PImage getRandomImage(float w, float h) {
  String url = "https://picsum.photos/seed/" + seed + "/" + int(w) + "/" + int(h) + ".jpg";
  // println(url);
  seed += 1;
  return loadImage(url);
}
//

```

* * *

**stripped it down to display just one image full screen for 4 seconds**

unsing the `picsum.photos/seed/...` idea.

```auto

// fullscreen image as a screen saver
// from https://discourse.processing.org/t/crop-multiple-images-to-any-quad-shape-and-place-them-side-by-side-filling-the-canvas/41326

int seed = int(random(1000));
PImage img;
int timer;

// -------------------------------------------------------------------------------
// Two core functions

void setup() {
  // size(560, 800);
  fullScreen();

  background(0);
  getRandomImage(width, height);
  timer=millis();
}

void draw() {
  background(0);

  if (millis()-timer>3999) {
    getRandomImage(width, height);
    timer=millis();
  }

  image(img, 0, 0);
}

// -------------------------------------------------------------------------------
// Input functions

void mousePressed() {
  getRandomImage(width, height);
}

// -------------------------------------------------------------------------------
// functions

void getRandomImage(float w, float h) {
  String url = "https://picsum.photos/seed/"
    + seed
    + "/"
    + int(w)
    + "/"
    + int(h)
    + ".jpg";
  // println(url);
  seed += 1;
  img = loadImage(url);
}
//

```

---

<div class="post-metadata">

**Author:** ![josephh](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/josephh/32/210_2.png) [@josephh](https://discourse.processing.org/u/josephh)\
**Post date:** [March 22, 2023, 12:39am UTC](https://discourse.processing.org/t/crop-multiple-images-to-any-quad-shape-and-place-them-side-by-side-filling-the-canvas-comic-strip/41326/14 "2023-03-22T00:39:45Z")

</div>

Yess it works quite nice in fullscreen!! 🤩

> [@Chrisir](#):
>
> Still puzzles me that we crop big images.

Yes there should be another way to crop the images without creating PGraphics of the same image size (it does not scale…)

---

<div class="post-metadata">

**Author:** ![Twooze](https://avatars.discourse-cdn.com/v4/letter/t/96bed5/32.png) [@Twooze](https://discourse.processing.org/u/Twooze)\
**Post date:** [March 23, 2023, 11:52am UTC](https://discourse.processing.org/t/crop-multiple-images-to-any-quad-shape-and-place-them-side-by-side-filling-the-canvas-comic-strip/41326/15 "2023-03-23T11:52:54Z")

</div>

Haha you two just keep going!

I have one small question then I am set to finnish this project (I will also let you now when I do!)  
Would there be a way to have the output size(5000,6000) or something but display it size(500,600) so I can see it but export the image at full dpi without needing to buy an 8K minitor to display it xD

---

<div class="post-metadata">

**Author:** ![josephh](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/josephh/32/210_2.png) [@josephh](https://discourse.processing.org/u/josephh)\
**Post date:** [March 23, 2023, 1:45pm UTC](https://discourse.processing.org/t/crop-multiple-images-to-any-quad-shape-and-place-them-side-by-side-filling-the-canvas-comic-strip/41326/16 "2023-03-23T13:45:23Z")

</div>

Yes, you can use an offscreen PGraphics just like we did earlier with the mask 😉 :

```auto
void setup() {
  size(500, 600);
  PGraphics buffer = createGraphics(5000, 6000);
  // Do your thing
  image(buffer, 0, 0, width, height); // Display it using the canvas size
}

```

(note that with my current implementation, doing a 5000x6000 view might take a while since it’s loading the images and croping them by creating large PGraphics buffer)

---

<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 23, 2023, 3:04pm UTC](https://discourse.processing.org/t/crop-multiple-images-to-any-quad-shape-and-place-them-side-by-side-filling-the-canvas-comic-strip/41326/17 "2023-03-23T15:04:42Z")

</div>

You could make 2 parallel  
PGraphics for the same images  
in 2 different sizes, one for the screen,  
one for the Hard Drive

---

<div class="post-metadata">

**Author:** ![Twooze](https://avatars.discourse-cdn.com/v4/letter/t/96bed5/32.png) [@Twooze](https://discourse.processing.org/u/Twooze)\
**Post date:** [March 23, 2023, 3:22pm UTC](https://discourse.processing.org/t/crop-multiple-images-to-any-quad-shape-and-place-them-side-by-side-filling-the-canvas-comic-strip/41326/18 "2023-03-23T15:22:17Z")

</div>

Yh I thought as much, starting to understand the whole PGraphics now.  
Making the whole thing in a ‘buffer’. Exporting that buffer to a png or pdf and drawing a scaled down version of the buffer on the canvas to check what it has made. That would work right and then just start and end pdf recording within the PGraphics, I’ll give it a try thx again!
