Merging Data into Slides

Conceptual diagram of a mail merge

One very useful application of the Slides API is to merge information from one or more data sources into a templated slide deck. There are a number of reasons why this approach is useful, including:

  • It's easy for designers to fine-tune a presentation's design using the Google Slides editor. This is much easier than adjusting parameters in your app to adjust the rendered slide design.

  • Separating content from presentation is a well-known design principle with many benefits.

This page outlines how you can take data from an external source and insert it into an existing "template" presentation. The concept is similar to that of a mail merge using a word processor and spreadsheet.

A basic recipe

Here's an example of how you might merge data into a presentation with the Slides API. The overall steps are:

  1. Create your presentation exactly as you want it to appear using dummy content to help you with the design.

  2. For each content element that you'll be inserting, replace the dummy content with a tag. Tags are just text boxes or shapes with a unique string.

  3. In your code, use the Google Drive API to make a fresh copy of the presentation.

  4. In your code, use the Slides API's batchUpdate method, with a set of replaceAllText requests, to perform all the text substitutions throughout the presentation. Use replaceAllShapesWithImage requests to perform image substitutions throughout the presentation.

When setting tags, make sure to use strings that are unlikely to occur normally. For example, {{account-holder-name}} might be a good tag.

Once you've created a deck with tags in it, be sure to make a copy and use the Slides API to manipulate the copy. Don't use the Slides API to manipulate your master "template" copy!

The following sections include code snippets that illustrate some of this process. You can also view the above video to see a complete example (Python) combining several of the concepts from the individual sections below.

Text merging

You can use a replaceAllText request to replace all instances of a given text string in a presentation with new text. For merges, this is usually far simpler than finding and replacing each instance of text individually. One reason this is the most robust approach is that the IDs of page elements is difficult to predict, especially as collaborators work to refine and maintain the template presentation.

Example

This example uses the Google Drive API to copy a template presentation, making a new instance of the presentation. Then it uses the Sheets API to read data from a Google Sheets spreadsheet, and finally uses the Slides API to update the new presentation.

The example takes data from three cells in one row of a named range in the spreadsheet; it then substitutes that data into the presentation wherever the strings {{customer-name}}, {{case-description}}, and {{total-portfolio}}occur.

Apps Script

slides/api/Snippets.gs
// Use the Sheets API to load data, one record per row.
var dataRangeNotation = 'Customers!A2:M6';
var values = SpreadsheetApp.openById(dataSpreadsheetId).getRange(dataRangeNotation).getValues();

// For each record, create a new merged presentation.
for (var i = 0; i < values.length; ++i) {
  var row = values[i];
  var customerName = row[2]; // name in column 3
  var caseDescription = row[5]; // case description in column 6
  var totalPortfolio = row[11]; // total portfolio in column 12

  // Duplicate the template presentation using the Drive API.
  var copyTitle = customerName + ' presentation';
  var copyFile = {
    title: copyTitle,
    parents: [{id: 'root'}]
  };
  copyFile = Drive.Files.copy(copyFile, templatePresentationId);
  var presentationCopyId = copyFile.id;

  // Create the text merge (replaceAllText) requests for this presentation.
  requests = [{
    replaceAllText: {
      containsText: {
        text: '{{customer-name}}',
        matchCase: true
      },
      replaceText: customerName
    }
  }, {
    replaceAllText: {
      containsText: {
        text: '{{case-description}}',
        matchCase: true
      },
      replaceText: caseDescription
    }
  }, {
    replaceAllText: {
      containsText: {
        text: '{{total-portfolio}}',
        matchCase: true
      },
      replaceText: totalPortfolio + ''
    }
  }];

  // Execute the requests for this presentation.
  var result = Slides.Presentations.batchUpdate({
    requests: requests
  }, presentationCopyId);
  // Count the total number of replacements made.
  var numReplacements = 0;
  result.replies.forEach(function(reply) {
    numReplacements += reply.replaceAllText.occurrencesChanged;
  });
  console.log('Created presentation for %s with ID: %s', customerName, presentationCopyId);
  console.log('Replaced %s text instances', numReplacements);
}

Go

slides/snippets/presentations.go
// Use the Sheets API to load data, one record per row.
dataRangeNotation := "Customers!A2:M6"
sheetsResponse, _ := sheetsService.Spreadsheets.Values.Get(dataSpreadsheetId, dataRangeNotation).Do()
values := sheetsResponse.Values

// For each record, create a new merged presentation.
for _, row := range values {
	customerName := row[2].(string)
	caseDescription := row[5].(string)
	totalPortfolio := row[11].(string)

	// Duplicate the template presentation using the Drive API.
	copyTitle := customerName + " presentation"
	file := drive.File{
		Title: copyTitle,
	}
	presentationFile, _ := driveService.Files.Copy(templatePresentationId, &file).Do()
	presentationId := presentationFile.Id

	// Create the text merge (replaceAllText) requests for this presentation.
	requests := []*slides.Request{{
		ReplaceAllText: &slides.ReplaceAllTextRequest{
			ContainsText: &slides.SubstringMatchCriteria{
				Text:      "{{customer-name}}",
				MatchCase: true,
			},
			ReplaceText: customerName,
		},
	}, {
		ReplaceAllText: &slides.ReplaceAllTextRequest{
			ContainsText: &slides.SubstringMatchCriteria{
				Text:      "{{case-description}}",
				MatchCase: true,
			},
			ReplaceText: caseDescription,
		},
	}, {
		ReplaceAllText: &slides.ReplaceAllTextRequest{
			ContainsText: &slides.SubstringMatchCriteria{
				Text:      "{{total-portfolio}}",
				MatchCase: true,
			},
			ReplaceText: totalPortfolio,
		},
	}}

	// Execute the requests for this presentation.
	body := &slides.BatchUpdatePresentationRequest{
		Requests: requests,
	}
	response, _ := slidesService.Presentations.BatchUpdate(presentationId, body).Do()

Java

slides/snippets/src/main/java/Snippets.java
// Use the Sheets API to load data, one record per row.
String dataRangeNotation = "Customers!A2:M6";
ValueRange sheetsResponse = sheetsService.spreadsheets().values()
        .get(dataSpreadsheetId, dataRangeNotation).execute();
List<List<Object>> values = sheetsResponse.getValues();

// For each record, create a new merged presentation.
for (List<Object> row: values) {
    String customerName = row.get(2).toString();     // name in column 3
    String caseDescription = row.get(5).toString();  // case description in column 6
    String totalPortfolio = row.get(11).toString();  // total portfolio in column 12

    // Duplicate the template presentation using the Drive API.
    String copyTitle = customerName + " presentation";
    File content = new File().setName(copyTitle);
    File presentationFile =
            driveService.files().copy(templatePresentationId, content).execute();
    String presentationId = presentationFile.getId();

    // Create the text merge (replaceAllText) requests for this presentation.
    List<Request> requests = new ArrayList<>();
    requests.add(new Request()
            .setReplaceAllText(new ReplaceAllTextRequest()
                    .setContainsText(new SubstringMatchCriteria()
                            .setText("{{customer-name}}")
                            .setMatchCase(true))
                    .setReplaceText(customerName)));
    requests.add(new Request()
            .setReplaceAllText(new ReplaceAllTextRequest()
                    .setContainsText(new SubstringMatchCriteria()
                            .setText("{{case-description}}")
                            .setMatchCase(true))
                    .setReplaceText(caseDescription)));
    requests.add(new Request()
            .setReplaceAllText(new ReplaceAllTextRequest()
                    .setContainsText(new SubstringMatchCriteria()
                            .setText("{{total-portfolio}}")
                            .setMatchCase(true))
                    .setReplaceText(totalPortfolio)));

    // Execute the requests for this presentation.
    BatchUpdatePresentationRequest body =
            new BatchUpdatePresentationRequest().setRequests(requests);
    BatchUpdatePresentationResponse response =
            slidesService.presentations().batchUpdate(presentationId, body).execute();
    // Count total number of replacements made.
    int numReplacements = 0;
    for (Response resp : response.getReplies()) {
        numReplacements += resp.getReplaceAllText().getOccurrencesChanged();
    }

    System.out.println("Created merged presentation for " +
            customerName + " with ID: " + presentationId);
    System.out.println("Replaced " + numReplacements + " text instances.");
}

JavaScript

slides/snippets/snippets.js
// Use the Sheets API to load data, one record per row.
var responses = [];
var dataRangeNotation = 'Customers!A2:M6';
gapi.client.sheets.spreadsheets.values.get({
  spreadsheetId: dataSpreadsheetId,
  range: dataRangeNotation
}).then((sheetsResponse) => {
  var values = sheetsResponse.result.values;

  // For each record, create a new merged presentation.
  for (var i = 0; i < values.length; ++i) {
    var row = values[i];
    var customerName = row[2]; // name in column 3
    var caseDescription = row[5]; // case description in column 6
    var totalPortfolio = row[11]; // total portfolio in column 12

    // Duplicate the template presentation using the Drive API.
    var copyTitle = customerName + ' presentation';
    var request = {
      name: copyTitle
    };
    gapi.client.drive.files.copy({
      fileId: templatePresentationId,
      requests: request
    }).then((driveResponse) => {
      var presentationCopyId = driveResponse.result.id;

      // Create the text merge (replaceAllText) requests for this presentation.
      var requests = [{
        replaceAllText: {
          containsText: {
            text: '{{customer-name}}',
            matchCase: true
          },
          replaceText: customerName
        }
      }, {
        replaceAllText: {
          containsText: {
            text: '{{case-description}}',
            matchCase: true
          },
          replaceText: caseDescription
        }
      }, {
        replaceAllText: {
          containsText: {
            text: '{{total-portfolio}}',
            matchCase: true
          },
          replaceText: totalPortfolio
        }
      }];

      // Execute the requests for this presentation.
      gapi.client.slides.presentations.batchUpdate({
        presentationId: presentationCopyId,
        requests: requests
      }).then((batchUpdateResponse) => {
        var result = batchUpdateResponse.result;
        // Count the total number of replacements made.
        var numReplacements = 0;
        for (var i = 0; i < result.replies.length; ++i) {
          numReplacements += result.replies[i].replaceAllText.occurrencesChanged;
        }
        console.log(`Created presentation for ${customerName} with ID: ${presentationCopyId}`);
        console.log(`Replaced ${numReplacements} text instances`);
      });
    });
  }
});

Node.js

slides/snippets/snippets.js
// Use the Sheets API to load data, one record per row.
let responses = [];
let dataRangeNotation = 'Customers!A2:M6';

this.sheetsService.spreadsheets.values.get({
  spreadsheetId: dataSpreadsheetId,
  range: dataRangeNotation,
}, (err, sheetsResponse) => {
  let values = sheetsResponse.values;

  // For each record, create a new merged presentation.
  for (let i = 0; i < values.length; ++i) {
    let row = values[i];
    let customerName = row[2]; // name in column 3
    let caseDescription = row[5]; // case description in column 6
    let totalPortfolio = row[11]; // total portfolio in column 12

    // Duplicate the template presentation using the Drive API.
    let copyTitle = customerName + ' presentation';
    let requests = {
      name: copyTitle,
    };

    this.driveService.files.copy({
      fileId: templatePresentationId,
      requests,
    }, (err, driveResponse) => {
      let presentationCopyId = driveResponse.id;
      // Create the text merge (replaceAllText) requests for this presentation.
      let requests = [{
        replaceAllText: {
          containsText: {
            text: '{{customer-name}}',
            matchCase: true,
          },
          replaceText: customerName,
        },
      }, {
        replaceAllText: {
          containsText: {
            text: '{{case-description}}',
            matchCase: true,
          },
          replaceText: caseDescription,
        },
      }, {
        replaceAllText: {
          containsText: {
            text: '{{total-portfolio}}',
            matchCase: true,
          },
          replaceText: totalPortfolio,
        },
      }];
      // Execute the requests for this presentation.
      this.slidesService.presentations.batchUpdate({
        presentationId: presentationCopyId,
        resource: {
          requests,
        },
      }, (err, batchUpdateResponse) => {
        let result = batchUpdateResponse;
        // Count the total number of replacements made.
        let numReplacements = 0;
        for (let i = 0; i < result.replies.length; ++i) {
          numReplacements += result.replies[i].replaceAllText.occurrencesChanged;
        }
        console.log(`Created presentation for ${customerName} with ID: ` +
            presentationCopyId);
        console.log(`Replaced ${numReplacements} text instances`);
      });
    });
  }
});

PHP

slides/snippets/src/SlidesSnippets.php
<?php
// Use the Sheets API to load data, one record per row.
$dataRangeNotation = 'Customers!A2:M6';
$sheetsResponse =
    $sheetsService->spreadsheets_values->get($dataSpreadsheetId, $dataRangeNotation);
$values = $sheetsResponse['values'];

// For each record, create a new merged presentation.
foreach ($values as $row) {
    $customerName = $row[2];     // name in column 3
    $caseDescription = $row[5];  // case description in column 6
    $totalPortfolio = $row[11];  // total portfolio in column 12

    // Duplicate the template presentation using the Drive API.
    $copy = new Google_Service_Drive_DriveFile(array(
        'name' => $customerName . ' presentation'
    ));
    $driveResponse = $driveService->files->copy($templatePresentationId, $copy);
    $presentationCopyId = $driveResponse->id;

    // Create the text merge (replaceAllText) requests for this presentation.
    $requests = array();
    $requests[] = new Google_Service_Slides_Request(array(
        'replaceAllText' => array(
            'containsText' => array(
                'text' => '{{customer-name}}',
                'matchCase' => true
            ),
            'replaceText' => $customerName
        )
    ));
    $requests[] = new Google_Service_Slides_Request(array(
        'replaceAllText' => array(
            'containsText' => array(
                'text' => '{{case-description}}',
                'matchCase' => true
            ),
            'replaceText' => $caseDescription
        )
    ));
    $requests[] = new Google_Service_Slides_Request(array(
        'replaceAllText' => array(
            'containsText' => array(
                'text' => '{{total-portfolio}}',
                'matchCase' => true
            ),
            'replaceText' => $totalPortfolio
        )
    ));

    // Execute the requests for this presentation.
    $batchUpdateRequest = new Google_Service_Slides_BatchUpdatePresentationRequest(array(
        'requests' => $requests
    ));
    $response =
        $slidesService->presentations->batchUpdate($presentationCopyId, $batchUpdateRequest);
    // Count the total number of replacements made.
    $numReplacements = 0;
    foreach ($response->getReplies() as $reply) {
        $numReplacements += $reply->getReplaceAllText()->getOccurrencesChanged();
    }
    printf("Created presentation for %s with ID: %s\n", $customerName, $presentationCopyId);
    printf("Replaced %d text instances.\n", $numReplacements);
}

Python

slides/snippets/slides_snippets.py
# Use the Sheets API to load data, one record per row.
data_range_notation = 'Customers!A2:M6'
sheets_response = sheets_service.spreadsheets().values().get(
    spreadsheetId=data_spreadsheet_id,
    range=data_range_notation).execute()
values = sheets_response.get('values')

# For each record, create a new merged presentation.
for row in values:
    customer_name = row[2]       # name in column 3
    case_description = row[5]    # case description in column 6
    total_portfolio = row[11]    # total portfolio in column 12

    # Duplicate the template presentation using the Drive API.
    copy_title = customer_name + ' presentation'
    body = {
        'name': copy_title
    }
    drive_response = drive_service.files().copy(
        fileId=template_presentation_id, body=body).execute()
    presentation_copy_id = drive_response.get('id')

    # Create the text merge (replaceAllText) requests
    # for this presentation.
    requests = [
        {
            'replaceAllText': {
                'containsText': {
                    'text': '{{customer-name}}',
                    'matchCase': True
                },
                'replaceText': customer_name
            }
        },
        {
            'replaceAllText': {
                'containsText': {
                    'text': '{{case-description}}',
                    'matchCase': True
                },
                'replaceText': case_description
            }
        },
        {
            'replaceAllText': {
                'containsText': {
                    'text': '{{total-portfolio}}',
                    'matchCase': True
                },
                'replaceText': total_portfolio
            }
        }
    ]

    # Execute the requests for this presentation.
    body = {
        'requests': requests
    }
    response = slides_service.presentations().batchUpdate(
        presentationId=presentation_copy_id, body=body).execute()
    # Count the total number of replacements made.
    num_replacements = 0
    for reply in response.get('replies'):
        num_replacements += reply.get('replaceAllText') \
            .get('occurrencesChanged')
    print('Created presentation for %s with ID: %s' %
        (customer_name, presentation_copy_id))
    print('Replaced %d text instances' % num_replacements)

Ruby

slides/snippets/lib/file_snippets.rb
# Use the Sheets API to load data, one record per row.
data_range_notation = 'Customers!A2:M6'
sheets_response = sheets_service.get_spreadsheet_values(
  data_spreadsheet_id,
  data_range_notation)
values = sheets_response.values

# For each record, create a new merged presentation.
values.each do |row|
  customer_name = row[2]       # name in column 3
  case_description = row[5]    # case description in column 6
  total_portfolio = row[11]    # total portfolio in column 12

  # Duplicate the template presentation using the Drive API.
  copy_title = customer_name + ' presentation'
  body = Google::Apis::SlidesV1::Presentation.new
  body.title = copy_title
  drive_response = drive_service.copy_file(template_presentation_id, body)
  presentation_copy_id = drive_response.id

  # Create the text merge (replace_all_text) requests for this presentation.
  requests = [] << {
    replace_all_text: {
      contains_text: {
        text: '{{customer-name}}',
        match_case: true
      },
      replace_text: customer_name
    }
  } << {
    replace_all_text: {
      contains_text: {
        text: '{{case-description}}',
        match_case: true
      },
      replace_text: case_description
    }
  } << {
    replace_all_text: {
      contains_text: {
        text: '{{total-portfolio}}',
        match_case: true
      },
      replace_text: total_portfolio
    }
  }

  # Execute the requests for this presentation.
  req = Google::Apis::SlidesV1::BatchUpdatePresentationRequest.new(requests: requests)
  response = slides_service.batch_update_presentation(
    presentation_copy_id,
    req)

Image merging

You can also merge images into your presentation using a replaceAllShapesWithImage request. This request replaces all instances of shapes containing the provided text string with the provided image. The request automatically positions and scales the image to fit within the tag shape's bounds while preserving the image's aspect ratio.

Example

This example uses the Google Drive API to copy a template presentation, making a new instance of the presentation. Then it uses the Slides API to find any shape with the text {{company-logo}} and replace it with a company logo image. The request will also replace any shape with the text {{customer-graphic}} with a different image.

Apps Script

slides/api/Snippets.gs
// Duplicate the template presentation using the Drive API.
var copyTitle = customerName + ' presentation';
var copyFile = {
  title: copyTitle,
  parents: [{id: 'root'}]
};
copyFile = Drive.Files.copy(copyFile, templatePresentationId);
var presentationCopyId = copyFile.id;

// Create the image merge (replaceAllShapesWithImage) requests.
var requests = [{
  replaceAllShapesWithImage: {
    imageUrl: logoUrl,
    replaceMethod: 'CENTER_INSIDE',
    containsText: {
      text: '{{company-logo}}',
      matchCase: true
    }
  }
}, {
  replaceAllShapesWithImage: {
    imageUrl: customerGraphicUrl,
    replaceMethod: 'CENTER_INSIDE',
    containsText: {
      text: '{{customer-graphic}}',
      matchCase: true
    }
  }
}];

// Execute the requests for this presentation.
var batchUpdateResponse = Slides.Presentations.batchUpdate({
  requests: requests
}, presentationCopyId);
var numReplacements = 0;
batchUpdateResponse.replies.forEach(function(reply) {
  numReplacements += reply.replaceAllShapesWithImage.occurrencesChanged;
});
console.log('Created merged presentation with ID: %s', presentationCopyId);
console.log('Replaced %s shapes with images.', numReplacements);

Go

slides/snippets/presentations.go
// Duplicate the template presentation using the Drive API.
copyTitle := customerName + " presentation"
file := drive.File{
	Title: copyTitle,
}
presentationFile, _ := driveService.Files.Copy(templatePresentationId, &file).Do()
presentationId := presentationFile.Id

// Create the image merge (replaceAllShapesWithImage) requests.
requests := []*slides.Request{{
	ReplaceAllShapesWithImage: &slides.ReplaceAllShapesWithImageRequest{
		ImageUrl:      logoURL,
		ReplaceMethod: "CENTER_INSIDE",
		ContainsText: &slides.SubstringMatchCriteria{
			Text:      "{{company-logo}}",
			MatchCase: true,
		},
	},
}, {
	ReplaceAllShapesWithImage: &slides.ReplaceAllShapesWithImageRequest{
		ImageUrl:      customerGraphicURL,
		ReplaceMethod: "CENTER_INSIDE",
		ContainsText: &slides.SubstringMatchCriteria{
			Text:      "{{customer-graphic}}",
			MatchCase: true,
		},
	},
}}

// Execute the requests for this presentation.
body := &slides.BatchUpdatePresentationRequest{Requests: requests}
response, _ := slidesService.Presentations.BatchUpdate(presentationId, body).Do()

// Count total number of replacements made.
numReplacements := 0
for _, resp := range response.Replies {
	numReplacements += resp.ReplaceAllShapesWithImage.OccurrencesChanged
}
fmt.Printf("Created merged presentation with ID %s\n", presentationId)
fmt.Printf("Replaced %d shapes instances with images.\n", numReplacements)

Java

slides/snippets/src/main/java/Snippets.java
// Duplicate the template presentation using the Drive API.
String copyTitle = customerName + " presentation";
File content = new File().setName(copyTitle);
File presentationFile =
        driveService.files().copy(templatePresentationId, content).execute();
String presentationId = presentationFile.getId();

// Create the image merge (replaceAllShapesWithImage) requests.
List<Request> requests = new ArrayList<>();
requests.add(new Request()
        .setReplaceAllShapesWithImage(new ReplaceAllShapesWithImageRequest()
                .setImageUrl(logoUrl)
                .setReplaceMethod("CENTER_INSIDE")
                .setContainsText(new SubstringMatchCriteria()
                        .setText("{{company-logo}}")
                        .setMatchCase(true))));
requests.add(new Request()
        .setReplaceAllShapesWithImage(new ReplaceAllShapesWithImageRequest()
                .setImageUrl(customerGraphicUrl)
                .setReplaceMethod("CENTER_INSIDE")
                .setContainsText(new SubstringMatchCriteria()
                        .setText("{{customer-graphic}}")
                        .setMatchCase(true))));

// Execute the requests.
BatchUpdatePresentationRequest body =
        new BatchUpdatePresentationRequest().setRequests(requests);
BatchUpdatePresentationResponse response =
        slidesService.presentations().batchUpdate(presentationId, body).execute();

// Count total number of replacements made.
int numReplacements = 0;
for(Response resp: response.getReplies()) {
    numReplacements += resp.getReplaceAllShapesWithImage().getOccurrencesChanged();
}

System.out.println("Created merged presentation with ID: " + presentationId);
System.out.println("Replaced " + numReplacements + " shapes instances with images.");

JavaScript

slides/snippets/snippets.js
// Duplicate the template presentation using the Drive API.
var copyTitle = customerName + ' presentation';
gapi.client.drive.files.copy({
  fileId: templatePresentationId,
  resource: {
    name: copyTitle
  }
}).then((driveResponse) => {
  var presentationCopyId = driveResponse.result.id;

  // Create the image merge (replaceAllShapesWithImage) requests.
  var requests = [{
    replaceAllShapesWithImage: {
      imageUrl: logoUrl,
      replaceMethod: 'CENTER_INSIDE',
      containsText: {
        text: '{{company-logo}}',
        matchCase: true
      }
    }
  }, {
    replaceAllShapesWithImage: {
      imageUrl: customerGraphicUrl,
      replaceMethod: 'CENTER_INSIDE',
      containsText: {
        text: '{{customer-graphic}}',
        matchCase: true
      }
    }
  }];

  // Execute the requests for this presentation.
  gapi.client.slides.presentations.batchUpdate({
    presentationId: presentationCopyId,
    requests: requests
  }).then((batchUpdateResponse) => {
    var numReplacements = 0;
    for (var i = 0; i < batchUpdateResponse.result.replies.length; ++i) {
      numReplacements += batchUpdateResponse.result.replies[i].replaceAllShapesWithImage.occurrencesChanged;
    }
    console.log(`Created merged presentation with ID: ${presentationCopyId}`);
    console.log(`Replaced ${numReplacements} shapes with images.`);
  });
});

Node.js

slides/snippets/snippets.js
// Duplicate the template presentation using the Drive API.
let copyTitle = customerName + ' presentation';
this.driveService.files.copy({
  fileId: templatePresentationId,
  resource: {
    name: copyTitle,
  },
}, (err, driveResponse) => {
  let presentationCopyId = driveResponse.id;

  // Create the image merge (replaceAllShapesWithImage) requests.
  let requests = [{
    replaceAllShapesWithImage: {
      imageUrl: logoUrl,
      replaceMethod: 'CENTER_INSIDE',
      containsText: {
        text: '{{company-logo}}',
        matchCase: true,
      },
    },
  }, {
    replaceAllShapesWithImage: {
      imageUrl: customerGraphicUrl,
      replaceMethod: 'CENTER_INSIDE',
      containsText: {
        text: '{{customer-graphic}}',
        matchCase: true,
      },
    },
  }];

  // Execute the requests for this presentation.
  this.slidesService.presentations.batchUpdate({
    presentationId: presentationCopyId,
    resource: {
      requests,
    },
  }, (err, batchUpdateResponse) => {
    let numReplacements = 0;
    for (let i = 0; i < batchUpdateResponse.replies.length; ++i) {
      numReplacements += batchUpdateResponse.replies[i]
          .replaceAllShapesWithImage.occurrencesChanged;
    }
    console.log(`Created merged presentation with ID: ${presentationCopyId}`);
    console.log(`Replaced ${numReplacements} shapes with images.`);
  });
});

PHP

slides/snippets/src/SlidesSnippets.php
<?php
// Duplicate the template presentation using the Drive API.
$copy = new Google_Service_Drive_DriveFile(array(
    'name' => $customerName . ' presentation'
));
$driveResponse = $driveService->files->copy($templatePresentationId, $copy);
$presentationCopyId = $driveResponse->id;

// Create the image merge (replaceAllShapesWithImage) requests.
$requests = array();
$requests[] = new Google_Service_Slides_Request(array(
    'replaceAllShapesWithImage' => array(
        'imageUrl' => $logoUrl,
        'replaceMethod' => 'CENTER_INSIDE',
        'containsText' => array(
            'text' => '{{company-logo}}',
            'matchCase' => true
        )
    )
));
$requests[] = new Google_Service_Slides_Request(array(
    'replaceAllShapesWithImage' => array(
        'imageUrl' => $customerGraphicUrl,
        'replaceMethod' => 'CENTER_INSIDE',
        'containsText' => array(
            'text' => '{{customer-graphic}}',
            'matchCase' => true
        )
    )
));

// Execute the requests.
$batchUpdateRequest = new Google_Service_Slides_BatchUpdatePresentationRequest(array(
    'requests' => $requests
));
$response =
    $slidesService->presentations->batchUpdate($presentationCopyId, $batchUpdateRequest);

// Count the total number of replacements made.
$numReplacements = 0;
foreach ($response->getReplies() as $reply) {
    $numReplacements += $reply->getReplaceAllShapesWithImage()->getOccurrencesChanged();
}
printf("Created presentation for %s with ID: %s\n", $customerName, $presentationCopyId);
printf("Replaced %d shapes with images.\n", $numReplacements);

Python

slides/snippets/slides_snippets.py
# Duplicate the template presentation using the Drive API.
copy_title = customer_name + ' presentation'
drive_response = drive_service.files().copy(
    fileId=template_presentation_id,
    body={'name': copy_title}).execute()
presentation_copy_id = drive_response.get('id')

# Create the image merge (replaceAllShapesWithImage) requests.
requests = []
requests.append({
    'replaceAllShapesWithImage': {
        'imageUrl': logo_url,
        'replaceMethod': 'CENTER_INSIDE',
        'containsText': {
            'text': '{{company-logo}}',
            'matchCase': True
        }
    }
})
requests.append({
    'replaceAllShapesWithImage': {
        'imageUrl': customer_graphic_url,
        'replaceMethod': 'CENTER_INSIDE',
        'containsText': {
            'text': '{{customer-graphic}}',
            'matchCase': True
        }
    }
})

# Execute the requests.
body = {
    'requests': requests
}
response = slides_service.presentations().batchUpdate(
    presentationId=presentation_copy_id, body=body).execute()

# Count the number of replacements made.
num_replacements = 0
for reply in response.get('replies'):
    num_replacements += reply.get('replaceAllShapesWithImage') \
        .get('occurrencesChanged')
print('Created merged presentation with ID: {0}' \
    .format(presentation_copy_id))
print('Replaced %d shapes with images.' % num_replacements)

Ruby

slides/snippets/lib/file_snippets.rb
# Duplicate the template presentation using the Drive API.
copy_title = customer_name + ' presentation'
body = Google::Apis::SlidesV1::Presentation.new
body.title = copy_title
drive_response = drive_service.copy_file(template_presentation_id, body)
presentation_copy_id = drive_response.id

# Create the image merge (replace_all_shapes_with_image) requests.
requests = [] << {
  replace_all_shapes_with_image: {
    image_url: logo_url,
    replace_method: 'CENTER_INSIDE',
    contains_text: {
      text: '{{company-logo}}',
      match_case: true
    }
  }
} << {
  replace_all_shapes_with_image: {
    image_url: customer_graphic_url,
    replace_method: 'CENTER_INSIDE',
    contains_text: {
      text: '{{customer-graphic}}',
      match_case: true
    }
  }
}

# Execute the requests.
req = Google::Apis::SlidesV1::BatchUpdatePresentationRequest.new(requests: requests)
response = slides_service.batch_update_presentation(
  presentation_copy_id,
  req)

# Count the number of replacements made.
num_replacements = 0
response.replies.each do |reply|
  num_replacements += reply.replace_all_shapes_with_image.occurrences_changed
end
puts "Created presentation for #{customer_name} with ID: #{presentation_copy_id}"
puts "Replaced #{num_replacements} shapes with images"

Replacing specific text box or image instances

The replaceAllText and replaceAllShapesWithImage requests are useful for replacing tags throughout a presentation, but sometimes you only need to replace elements according to some criteria, such as being located on a specific slide.

In these cases, you must retrieve the IDs of the tag shapes you want to replace. For text replacements, you delete the existing text in those shapes and then insert the new text (see the Edit text in a specified shape example).

Image replacements are more complex. To merge in an image, you need to:

  1. Get the tag shape's ID.
  2. Copy the size and transform information from the tag.
  3. Add your image to the page, using the size and transform information.
  4. Delete the tag shape.

Preserving the image's aspect ratio while scaling it to the desired size may require some care, as described in the following paragraphs. See also the Replace a shape tag with an image example.

Preserving aspect ratio

When you create images using the Slides API, aspect fits are based only on the image size, not on the size and transform data. The size data that you provide in the createImage request is considered to be the desired size of the image. The API fits the image's aspect ratio to this desired size, then applies the provided transform.

When replacing a tag with an image, you preserve the image's aspect ratio by setting the image's size and scaling as follows:

  • width: set to the product of the tag's width and scaleX
  • height: set to the product of the tag's height and scaleY
  • scale_x: set to 1
  • scale_y: set to 1

This causes the Slides API to aspect fit the image according to the tag's visual size, rather than its non-scaled size (see the Replace a shape tag with an image). Setting the scaling parameters to 1 prevents the image from being scaled twice.

This arrangement ensures the image's aspect ratio is preserved, and prevents the image from exceeding the size of the tag shape. The image will have the same center point as the tag shape.

Managing templates

For template presentations defined and owned by the application, create the template using a dedicated account representing the application. Service accounts are a good choice and avoid complications with GSuite policies that restrict sharing.

When you create instances of presentations from templates, always use end-user credentials. This gives users full control over the resulting presentation and prevents scaling issues related to per-user limits in Google Drive.

To create a template using a service account, perform the following steps using the application credentials:

  1. Create a new presentation using presentation.create in the Slides API
  2. Update the permissions to allow anyone to read using files.permissions.insert in the Drive API
  3. Update the permissions to allow template authors to write using files.permissions.insert in the Drive API
  4. Edit the template as required

To create a new instance of the presentation, perform the following steps using the user credentials:

  1. Create a copy of the template using files.copy in the Drive API
  2. Replace values using presentation.batchUpdate in the Slides API.

Оставить отзыв о...

Текущей странице
Нужна помощь? Обратитесь в службу поддержки.