appscript.dev
Automation Intermediate Slides

Auto-align and resize images on every slide

Enforce consistent image placement across a Northwind deck — every photo same size, same spot.

Published Nov 23, 2025

When several people build a Northwind deck together, the images drift. One slide has a photo nudged slightly left, the next has it a touch too big, a third has it floating in the wrong corner. Individually each is minor; together they make a deck look unpolished. Fixing it by hand means clicking through every slide and dragging images into line.

This script enforces a single layout. It opens a deck, walks every slide, and sets each image to the same position and size — so every photo lands in exactly the same place. One run cleans up a whole deck.

What you’ll need

  • The ID of the Google Slides deck you want to normalise, taken from its URL.
  • A target layout: the left, top, width, and height in points that every image should snap to. The script ships with sensible defaults, which you can override per run.
  • Awareness that this is destructive — it overwrites the position and size of every image. Work on a copy of the deck first if you are not sure.

The script

// Default image layout in points. Override any of these per call by
// passing an options object as the second argument.
const DEFAULT_LAYOUT = { left: 50, top: 100, width: 600, height: 350 };

/**
 * Sets every image in a deck to the same position and size, so photos
 * land in an identical spot on every slide.
 *
 * @param {string} deckId   ID of the Google Slides deck to normalise.
 * @param {Object} [layout] Optional { left, top, width, height } in points.
 */
function normaliseImages(deckId, layout = {}) {
  // 1. Merge any caller overrides onto the default layout.
  const { left, top, width, height } = { ...DEFAULT_LAYOUT, ...layout };

  // 2. Open the deck and grab every slide.
  const deck = SlidesApp.openById(deckId);
  const slides = deck.getSlides();

  if (!slides.length) {
    Logger.log('Deck has no slides — nothing to normalise.');
    return;
  }

  // 3. Walk each slide, snapping every image to the target layout.
  let count = 0;
  for (const slide of slides) {
    for (const image of slide.getImages()) {
      image.setLeft(left).setTop(top).setWidth(width).setHeight(height);
      count++;
    }
  }
  Logger.log('Normalised ' + count + ' image(s) across ' + slides.length + ' slide(s).');
}

How it works

  1. normaliseImages starts by merging any options the caller passed over DEFAULT_LAYOUT. Pass nothing and every image takes the defaults; pass { width: 480 } and only the width changes.
  2. It opens the deck by ID and reads every slide into an array. If the deck is empty it logs a message and stops.
  3. It loops over the slides, and within each slide loops over slide.getImages() — the picture elements on that slide.
  4. For each image it chains setLeft, setTop, setWidth, and setHeight, moving and resizing it to the exact target layout. All four values are in points, the same unit Slides uses internally.
  5. A counter tracks how many images were touched, logged at the end so you can confirm the run did what you expected.

Example run

Take a six-slide deck where the team has dropped one photo on each slide, all at slightly different sizes and positions:

SlideImage beforeImage after
1left 62, 580×340left 50, 600×350
2left 48, 610×355left 50, 600×350
3left 70, 590×330left 50, 600×350

After normaliseImages('1abcDeckId'), every image sits at left 50, top 100, sized 600×350. Flick through the deck and the photos no longer jump around between slides.

Run it

This is an on-demand cleanup, run when a deck needs tidying:

  1. Add a wrapper that passes your deck ID, since the editor cannot call a function with arguments directly:
function runNormalise() {
  normaliseImages('1abcDeckId');
}
  1. Select runNormalise and click Run.
  2. Approve the Slides authorisation prompt the first time.
  3. Open the deck to check the result.

To use a custom layout, pass an options object: normaliseImages('1abcDeckId', { left: 80, top: 120, width: 480, height: 270 }).

Watch out for

  • This is destructive. It overwrites position and size for every image — there is no undo from the script side. Run it on a copy first if the deck matters.
  • It treats all images alike. A full-bleed background photo and a small inline logo both get forced to the same box, which is rarely what you want. If your deck mixes image roles, filter by current size before resizing.
  • The script does not preserve aspect ratio. Forcing every image to 600×350 will stretch any photo that is not already that ratio. Crop or pre-size your images, or compute a height from each image’s own ratio.
  • Images inside groups are not returned by slide.getImages(). Ungroup them first if they also need aligning.
  • Logos placed on the slide master or layout, rather than on the slide itself, are not touched — that is usually correct, but worth knowing.

Related