データをプレゼンテーションに統合する

Google Slides API の便利な用途の 1 つは、1 つ以上のデータソースの情報をテンプレート化されたスライドデッキに統合することです。

このページでは、外部ソースからデータを取得して既存のテンプレート プレゼンテーションに挿入する方法について説明します。このコンセプトは、ワープロとスプレッドシートを使用した差し込み印刷のコンセプトと似ています。

このアプローチが有用な理由は次のとおりです。

  • デザイナーは、Google スライド エディタを使用して、プレゼンテーションのデザインを簡単に調整できます。これは、アプリでパラメータを調整してレンダリングされたスライドのデザインを設定するよりもはるかに簡単です。

  • コンテンツとプレゼンテーションを分離することは、多くのメリットがあるよく知られた設計原則です。

マージの概念図。

基本的なレシピ

Slides API を使用してデータをプレゼンテーションに統合する方法の例を次に示します。

  1. プレースホルダ コンテンツを使用して、デザインを参考にしながら、プレゼンテーションを作成します。

  2. 挿入するコンテンツ要素ごとに、プレースホルダ コンテンツをタグに置き換えます。タグは、一意の文字列を含むテキスト ボックスまたは図形です。通常は発生しない文字列を使用してください。たとえば、{{account-holder-name}} は適切なタグです。

  3. コードで Google Drive API を使用して、プレゼンテーションのコピーを作成します。

  4. コードで、Slides API の batchUpdate メソッドと replaceAllText リクエストのセットを使用して、プレゼンテーション全体でテキストの置換を実行します。replaceAllShapesWithImage リクエストを使用して、プレゼンテーション全体で画像の置換を行います。

タグを含むスライドを作成したら、必ずコピーを作成し、Slides API を使用してコピーを操作してください。Slides API を使用して、メインの「テンプレート」コピーを操作しないでください。

以降のセクションでは、このプロセスの一部を示すコード スニペットを紹介します。上記の動画では、以下の各セクションのコンセプトを組み合わせた完全な例(Python)をご覧いただけます。

テキストを結合する

replaceAllText リクエストを使用すると、プレゼンテーション内の特定の文字列のすべてのインスタンスを新しいテキストに置き換えることができます。差し込み印刷の場合、テキストの各インスタンスを個別に検索して置換するよりも簡単です。これが最も高度なアプローチである理由の一つは、ページ要素の ID を予測することが難しいからです。特に、共同編集者がテンプレート プレゼンテーションを改良して維持している場合は、予測が難しくなります。

この例では、Drive API を使用してテンプレート プレゼンテーションをコピーし、プレゼンテーションの新しいインスタンスを作成します。次に、Google Sheets API を使用してスプレッドシートからデータを読み取り、最後に Slides API を使用して新しいプレゼンテーションを更新します。

この例では、スプレッドシートの指定範囲の 1 つの行にある 3 つのセルからデータを取得します。次に、文字列 {{customer-name}}{{case-description}}{{total-portfolio}} が出現するたびに、そのデータをプレゼンテーションに代入します。

Apps Script

slides/api/Snippets.gs
/**  * Use the Sheets API to load data, one record per row.  * @param {string} templatePresentationId  * @param {string} dataSpreadsheetId  * @returns {*[]}  */ function textMerging(templatePresentationId, dataSpreadsheetId) {   let responses = [];   const dataRangeNotation = 'Customers!A2:M6';   try {     let values = SpreadsheetApp.openById(dataSpreadsheetId).getRange(dataRangeNotation).getValues();      // For each record, create a new merged presentation.     for (let i = 0; i < values.length; ++i) {       const row = values[i];       const customerName = row[2]; // name in column 3       const caseDescription = row[5]; // case description in column 6       const totalPortfolio = row[11]; // total portfolio in column 12        // Duplicate the template presentation using the Drive API.       const copyTitle = customerName + ' presentation';       let copyFile = {         title: copyTitle,         parents: [{id: 'root'}]       };       copyFile = Drive.Files.copy(copyFile, templatePresentationId);       const presentationCopyId = copyFile.id;        // Create the text merge (replaceAllText) requests for this presentation.       const 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.       const result = Slides.Presentations.batchUpdate({         requests: requests       }, presentationCopyId);       // Count the total number of replacements made.       let 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);     }   } catch (err) {     // TODO (Developer) - Handle exception     console.log('Failed with error: %s', err.error);   } };

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/TextMerging.java
import com.google.api.client.googleapis.json.GoogleJsonError; import com.google.api.client.googleapis.json.GoogleJsonResponseException; import com.google.api.client.http.HttpRequestInitializer; import com.google.api.client.http.javanet.NetHttpTransport; import com.google.api.client.json.gson.GsonFactory; import com.google.api.services.drive.Drive; import com.google.api.services.drive.model.File; import com.google.api.services.sheets.v4.Sheets; import com.google.api.services.sheets.v4.model.ValueRange; import com.google.api.services.slides.v1.Slides; import com.google.api.services.slides.v1.SlidesScopes; import com.google.api.services.slides.v1.model.BatchUpdatePresentationRequest; import com.google.api.services.slides.v1.model.BatchUpdatePresentationResponse; import com.google.api.services.slides.v1.model.ReplaceAllTextRequest; import com.google.api.services.slides.v1.model.Request; import com.google.api.services.slides.v1.model.Response; import com.google.api.services.slides.v1.model.SubstringMatchCriteria; import com.google.auth.http.HttpCredentialsAdapter; import com.google.auth.oauth2.GoogleCredentials;  import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List;  /* Class to demonstrate the use of Slides Text Merging API */ public class TextMerging {   /**    * Changes specified texts with data from spreadsheet.    *    * @param templatePresentationId - id of the presentation.    * @param dataSpreadsheetId      - id of the spreadsheet containing data.    * @return merged presentation id    * @throws IOException - if credentials file not found.    */   public static List<BatchUpdatePresentationResponse> textMerging(       String templatePresentationId, String dataSpreadsheetId) throws IOException {         /* Load pre-authorized user credentials from the environment.            TODO(developer) - See https://developers.google.com/identity for             guides on implementing OAuth2 for your application. */     GoogleCredentials credentials = GoogleCredentials.getApplicationDefault()         .createScoped(Arrays.asList(SlidesScopes.PRESENTATIONS,             SlidesScopes.DRIVE, SlidesScopes.SPREADSHEETS));     HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(         credentials);      // Create the slides API client     Slides service = new Slides.Builder(new NetHttpTransport(),         GsonFactory.getDefaultInstance(),         requestInitializer)         .setApplicationName("Slides samples")         .build();      // Create the drive API client     Drive driveService = new Drive.Builder(new NetHttpTransport(),         GsonFactory.getDefaultInstance(),         requestInitializer)         .setApplicationName("Slides samples")         .build();      // Create the sheets API client     Sheets sheetsService = new Sheets.Builder(new NetHttpTransport(),         GsonFactory.getDefaultInstance(),         requestInitializer)         .setApplicationName("Slides samples")         .build();      List<BatchUpdatePresentationResponse> responses = new ArrayList<>(5);     // 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();      try {       // 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 =             service.presentations().batchUpdate(presentationId, body).execute();          // Count total number of replacements made.         int numReplacements = 0;         for (Response resp : response.getReplies()) {           numReplacements += resp.getReplaceAllText().getOccurrencesChanged();         }         // Prints the merged presentation id and count of replacements.         System.out.println("Created merged presentation for " +             customerName + " with ID: " + presentationId);         System.out.println("Replaced " + numReplacements + " text instances.");       }     } catch (NullPointerException ne) {       System.out.println("Text not found to replace with image.");     } catch (GoogleJsonResponseException e) {       // TODO(developer) - handle error appropriately       GoogleJsonError error = e.getDetails();       if (error.getCode() == 404) {         System.out.printf("Presentation not found with id '%s'.\n", templatePresentationId);       } else {         throw e;       }     }     return responses;   } }

JavaScript

slides/snippets/slides_text_merging.js
function textMerging(templatePresentationId, dataSpreadsheetId, callback) {   // Use the Sheets API to load data, one record per row.   const responses = [];   const dataRangeNotation = 'Customers!A2:M6';   try {     gapi.client.sheets.spreadsheets.values.get({       spreadsheetId: dataSpreadsheetId,       range: dataRangeNotation,     }).then((sheetsResponse) => {       const values = sheetsResponse.result.values;       // For each record, create a new merged presentation.       for (let i = 0; i < values.length; ++i) {         const row = values[i];         const customerName = row[2]; // name in column 3         const caseDescription = row[5]; // case description in column 6         const totalPortfolio = row[11]; // total portfolio in column 12          // Duplicate the template presentation using the Drive API.         const copyTitle = customerName + ' presentation';         const request = {           name: copyTitle,         };         gapi.client.drive.files.copy({           fileId: templatePresentationId,           requests: request,         }).then((driveResponse) => {           const presentationCopyId = driveResponse.result.id;            // Create the text merge (replaceAllText) requests for this presentation.           const 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) => {             const result = batchUpdateResponse.result;             responses.push(result.replies);             // 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`);             if (responses.length === values.length) { // callback for the last value               if (callback) callback(responses);             }           });         });       }     });   } catch (err) {     document.getElementById('content').innerText = err.message;     return;   } }

Node.js

slides/snippets/slides_text_merging.js
/**  * Adds data from a spreadsheet to a template presentation.  * @param {string} templatePresentationId The template presentation ID.  * @param {string} dataSpreadsheetId  The data spreadsheet ID.  */ async function textMerging(templatePresentationId, dataSpreadsheetId) {   const {GoogleAuth} = require('google-auth-library');   const {google} = require('googleapis');    const auth = new GoogleAuth({     scopes: [       'https://www.googleapis.com/auth/presentations',       'https://www.googleapis.com/auth/drive',       'https://www.googleapis.com/auth/spreadsheets',     ],   });    const slidesService = google.slides({version: 'v1', auth});   const sheetsService = google.sheets({version: 'v4', auth});   const driveService = google.drive({version: 'v2', auth});    // Use the Sheets API to load data, one record per row.   const responses = [];   const dataRangeNotation = 'A2:M6';    try {     const sheetsResponse = await sheetsService.spreadsheets.values.get({       spreadsheetId: dataSpreadsheetId,       range: dataRangeNotation,     });     const values = sheetsResponse.data.values;      // For each record, create a new merged presentation.     for (let i = 0; i < values.length; ++i) {       const row = values[i];       const customerName = row[2]; // name in column 3       const caseDescription = row[5]; // case description in column 6       const totalPortfolio = row[11]; // total portfolio in column 12        // Duplicate the template presentation using the Drive API.       const copyTitle = customerName + ' presentation';       let requests = {         name: copyTitle,       };        const driveResponse = await driveService.files.copy({         fileId: templatePresentationId,         requests,       });        const presentationCopyId = driveResponse.data.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.       const batchUpdateResponse = await slidesService.presentations.batchUpdate(           {             presentationId: presentationCopyId,             resource: {               requests,             },           },       );       const result = batchUpdateResponse.data;       // 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`);       return result;     }   } catch (err) {     // TODO (developer) - Handle exception     throw err;   } }

PHP

slides/snippets/src/SlidesTextMerging.php
<?php use Google\Client; use Google\Service\Drive; use Google\Service\Slides; use Google\Service\Slides\Request;  function textMerging($templatePresentationId, $dataSpreadsheetId) {      /* Load pre-authorized user credentials from the environment.        TODO(developer) - See https://developers.google.com/identity for         guides on implementing OAuth2 for your application. */     $client = new Google\Client();     $client->useApplicationDefaultCredentials();     $client->addScope(Google\Service\Drive::DRIVE);     $slidesService = new Google_Service_Slides($client);     $driveService = new Google_Service_Drive($client);     $sheetsService = new Google_Service_Sheets($client);     try {         $responses = array();         // 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);             $responses[] = $response;             // 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);         }         return $responses;     } catch (Exception $e) {         echo 'Message: ' . $e->getMessage();     } }

Python

slides/snippets/slides_text_merging.py
import google.auth from googleapiclient.discovery import build from googleapiclient.errors import HttpError   def text_merging(template_presentation_id, data_spreadsheet_id):   """   Run Text merging the user has access to.   Load pre-authorized user credentials from the environment.   TODO(developer) - See https://developers.google.com/identity   for guides on implementing OAuth2 for the application.   """   creds, _ = google.auth.default()   # pylint: disable=maybe-no-member    try:     service = build("slides", "v1", credentials=creds)     sheets_service = build("sheets", "v4", credentials=creds)     drive_service = build("drive", "v3", credentials=creds)     # 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 = (           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"):         if reply.get("occurrencesChanged") is not None:           num_replacements += reply.get("replaceAllText").get(               "occurrencesChanged"           )       print(           "Created presentation for "           f"{customer_name} with ID: {presentation_copy_id}"       )       print(f"Replaced {num_replacements} text instances")    except HttpError as error:     print(f"An error occurred: {error}")     return error   if __name__ == "__main__":   # Put the template_presentation_id, data_spreadsheet_id   # of slides    text_merging(       "10QnVUx1X2qHsL17WUidGpPh_SQhXYx40CgIxaKk8jU4",       "17eqFZl_WK4WVixX8PjvjfLD77DraoFwMDXeiHB3dvuM",   )

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   )

画像を統合する

replaceAllShapesWithImage リクエストを使用して、画像をプレゼンテーションに統合することもできます。このリクエストは、指定されたテキスト文字列を含む図形のすべてのインスタンスを指定された画像に置き換えます。リクエストは、画像の縦横比を維持しながら、タグの形状の境界内に収まるように画像を自動的に配置してスケーリングします。

この例では、Google Drive API を使用してテンプレート プレゼンテーションをコピーし、プレゼンテーションの新しいインスタンスを作成します。次に、Slides API を使用してテキスト {{company-logo}} を含む図形を見つけ、会社のロゴ画像に置き換えます。また、リクエストでは、図形をテキスト {{customer-graphic}} に置き換えて、別の画像に置き換えます。

Apps Script

slides/api/Snippets.gs
/**  * Duplicate the template presentation using the Drive API.  * @param {string} templatePresentationId  * @param {string} imageUrl  * @param {string} customerName  * @returns {*}  */ function imageMerging(templatePresentationId, imageUrl, customerName) {   const logoUrl = imageUrl;   const customerGraphicUrl = imageUrl;    const copyTitle = customerName + ' presentation';   let copyFile = {     title: copyTitle,     parents: [{id: 'root'}]   };    try {     copyFile = Drive.Files.copy(copyFile, templatePresentationId);     const presentationCopyId = copyFile.id;      // Create the image merge (replaceAllShapesWithImage) requests.     const requests = [{       replaceAllShapesWithImage: {         imageUrl: logoUrl,         imageReplaceMethod: 'CENTER_INSIDE',         containsText: {           text: '{{company-logo}}',           matchCase: true         }       }     }, {       replaceAllShapesWithImage: {         imageUrl: customerGraphicUrl,         imageReplaceMethod: 'CENTER_INSIDE',         containsText: {           text: '{{customer-graphic}}',           matchCase: true         }       }     }];      // Execute the requests for this presentation.     let batchUpdateResponse = Slides.Presentations.batchUpdate({       requests: requests     }, presentationCopyId);     let 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);      return batchUpdateResponse;   } catch (err) {     // TODO (Developer) - Handle exception     console.log('Failed with error: %s', err.error);   } };

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. var numReplacements int64 = 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/ImageMerging.java
import com.google.api.client.http.HttpRequestInitializer; import com.google.api.client.http.javanet.NetHttpTransport; import com.google.api.client.json.gson.GsonFactory; import com.google.api.services.drive.Drive; import com.google.api.services.drive.model.File; import com.google.api.services.slides.v1.Slides; import com.google.api.services.slides.v1.SlidesScopes; import com.google.api.services.slides.v1.model.BatchUpdatePresentationRequest; import com.google.api.services.slides.v1.model.BatchUpdatePresentationResponse; import com.google.api.services.slides.v1.model.Request; import com.google.api.services.slides.v1.model.Response; import com.google.api.services.slides.v1.model.ReplaceAllShapesWithImageRequest; import com.google.api.services.slides.v1.model.SubstringMatchCriteria; import com.google.auth.http.HttpCredentialsAdapter; import com.google.auth.oauth2.GoogleCredentials;  import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List;  /* Class to demonstrate the use of Slides Image Merging API */ public class ImageMerging {   /**    * Changes specified texts into images.    *    * @param templatePresentationId - id of the presentation.    * @param imageUrl               - Url of the image.    * @param customerName           - Name of the customer.    * @return merged presentation id    * @throws IOException - if credentials file not found.    */   public static BatchUpdatePresentationResponse imageMerging(String templatePresentationId,                                                              String imageUrl,                                                              String customerName)       throws IOException {         /* Load pre-authorized user credentials from the environment.            TODO(developer) - See https://developers.google.com/identity for             guides on implementing OAuth2 for your application. */     GoogleCredentials credentials = GoogleCredentials.getApplicationDefault()         .createScoped(Arrays.asList(SlidesScopes.PRESENTATIONS,             SlidesScopes.DRIVE));     HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(         credentials);      // Create the slides API client     Slides service = new Slides.Builder(new NetHttpTransport(),         GsonFactory.getDefaultInstance(),         requestInitializer)         .setApplicationName("Slides samples")         .build();      // Create the drive API client     Drive driveService = new Drive.Builder(new NetHttpTransport(),         GsonFactory.getDefaultInstance(),         requestInitializer)         .setApplicationName("Slides samples")         .build();      // 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(imageUrl)             .setImageReplaceMethod("CENTER_INSIDE")             .setContainsText(new SubstringMatchCriteria()                 .setText("{{company-logo}}")                 .setMatchCase(true))));      // Execute the requests.     BatchUpdatePresentationRequest body =         new BatchUpdatePresentationRequest().setRequests(requests);     BatchUpdatePresentationResponse response =         service.presentations().batchUpdate(presentationId, body).execute();      int numReplacements = 0;     try {       // Count total number of replacements made.       for (Response resp : response.getReplies()) {         numReplacements += resp.getReplaceAllShapesWithImage().getOccurrencesChanged();       }        // Prints the merged presentation id and count of replacements.       System.out.println("Created merged presentation with ID: " + presentationId);       System.out.println("Replaced " + numReplacements + " shapes instances with images.");     } catch (NullPointerException ne) {       System.out.println("Text not found to replace with image.");     }     return response;   } }

JavaScript

slides/snippets/slides_image_merging.js
function imageMerging(     templatePresentationId,     imageUrl,     customerName,     callback, ) {   const logoUrl = imageUrl;   const customerGraphicUrl = imageUrl;    // Duplicate the template presentation using the Drive API.   const copyTitle = customerName + ' presentation';   try {     gapi.client.drive.files         .copy({           fileId: templatePresentationId,           resource: {             name: copyTitle,           },         })         .then((driveResponse) => {           const presentationCopyId = driveResponse.result.id;            // Create the image merge (replaceAllShapesWithImage) requests.           const 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) => {                 let numReplacements = 0;                 for (                   let 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.`);                 if (callback) callback(batchUpdateResponse.result);               });         });   } catch (err) {     document.getElementById('content').innerText = err.message;     return;   } }

Node.js

slides/snippets/slides_image_merging.js
/**  * Add an image to a template presentation.  * @param {string} templatePresentationId The template presentation ID.  * @param {string} imageUrl The image URL  * @param {string} customerName A customer name used for the title  */ async function imageMerging(templatePresentationId, imageUrl, customerName) {   const {GoogleAuth} = require('google-auth-library');   const {google} = require('googleapis');    const auth = new GoogleAuth({     scopes: [       'https://www.googleapis.com/auth/presentations',       'https://www.googleapis.com/auth/drive',     ],   });    const slidesService = google.slides({version: 'v1', auth});   const driveService = google.drive({version: 'v2', auth});   const logoUrl = imageUrl;   const customerGraphicUrl = imageUrl;    // Duplicate the template presentation using the Drive API.   const copyTitle = customerName + ' presentation';   try {     const driveResponse = await driveService.files.copy({       fileId: templatePresentationId,       resource: {         name: copyTitle,       },     });     const presentationCopyId = driveResponse.data.id;      // Create the image merge (replaceAllShapesWithImage) requests.     const 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.     const batchUpdateResponse = await slidesService.presentations.batchUpdate({       presentationId: presentationCopyId,       resource: {         requests,       },     });     let numReplacements = 0;     for (let i = 0; i < batchUpdateResponse.data.replies.length; ++i) {       numReplacements +=         batchUpdateResponse.data.replies[i].replaceAllShapesWithImage             .occurrencesChanged;     }     console.log(`Created merged presentation with ID: ${presentationCopyId}`);     console.log(`Replaced ${numReplacements} shapes with images.`);     return batchUpdateResponse.data;   } catch (err) {     // TODO (developer) - Handle exception     throw err;   } }

PHP

slides/snippets/src/SlidesImageMerging.php
<?php use Google\Client; use Google\Service\Drive; use Google\Service\Slides; use Google\Service\DriveFile; use Google\Service\Slides\Request;   function imageMerging($templatePresentationId, $imageUrl, $customerName) {     /* Load pre-authorized user credentials from the environment.        TODO(developer) - See https://developers.google.com/identity for         guides on implementing OAuth2 for your application. */     $client = new Google\Client();     $client->useApplicationDefaultCredentials();     $client->addScope(Google\Service\Drive::DRIVE);     $slidesService = new Google_Service_Slides($client);     $driveService = new Google_Service_Drive($client);     // Duplicate the template presentation using the Drive API.     $copy = new Google_Service_Drive_DriveFile([         'name' => $customerName . ' presentation'     ]);      $driveResponse = $driveService->files->copy($templatePresentationId, $copy);     $presentationCopyId = $driveResponse->id;      // Create the image merge (replaceAllShapesWithImage) requests.      $requests[] = new Google_Service_Slides_Request([         'replaceAllShapesWithImage' => [             'imageUrl' => $imageUrl,             'replaceMethod' => 'CENTER_INSIDE',             'containsText' => [                 'text' => '{{company-logo}}',                 'matchCase' => true             ]         ]     ]);     $requests[] = new Google_Service_Slides_Request([         'replaceAllShapesWithImage' => [             'imageUrl' => $imageUrl,             'replaceMethod' => 'CENTER_INSIDE',             'containsText' => [                 'text' => '{{customer-graphic}}',                 'matchCase' => true             ]         ]     ]);      // Execute the requests.     $batchUpdateRequest = new Google_Service_Slides_BatchUpdatePresentationRequest([         '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);     return $response; }

Python

slides/snippets/slides_image_merging.py
import google.auth from googleapiclient.discovery import build from googleapiclient.errors import HttpError   def image_merging(template_presentation_id, image_url, customer_name):   """image_merging require template_presentation_id,   image_url and customer_name   Load pre-authorized user credentials from the environment.   TODO(developer) - See https://developers.google.com/identity   for guides on implementing OAuth2 for the application.   """   creds, _ = google.auth.default()   # pylint: disable=maybe-no-member   try:     slides_service = build("slides", "v1", credentials=creds)     drive_service = build("drive", "v3", credentials=creds)     logo_url = image_url      customer_graphic_url = image_url      # 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"):       # add below line        if reply.get("occurrencesChanged") is not None:         # end tag         num_replacements += reply.get("replaceAllShapesWithImage").get(             "occurrencesChanged"         )      print(f"Created merged presentation with ID:{presentation_copy_id}")     print(f"Replaced {num_replacements} shapes with images")   except HttpError as error:     print(f"An error occurred: {error}")     print("Images is not merged")     return error    return response   if __name__ == "__main__":   # Put the template_presentation_id, image_url and customer_name    image_merging(       "10QnVUx1X2qHsL17WUidGpPh_SQhXYx40CgIxaKk8jU4",       "https://www.google.com/images/branding/"       "googlelogo/2x/googlelogo_color_272x92dp.png",       "Fake Customer",   )

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"

特定のテキスト ボックスまたは画像インスタンスを置き換える

replaceAllText リクエストと replaceAllShapesWithImage リクエストは、プレゼンテーション全体でタグを置き換える場合に便利ですが、特定のスライドにあるなど、別の条件に基づいて要素を置き換える必要がある場合もあります。

このような場合は、置き換えるタグシェイプの ID を取得する必要があります。テキストの置換では、これらの図形内の既存のテキストを削除してから、新しいテキストを挿入します(指定した図形のテキストを編集するのサンプルを参照)。

画像の置き換えはより複雑です。画像を統合するには、次の操作を行います。

  1. タグシェイプの ID を取得します。
  2. タグからサイズと変換の情報をコピーします。
  3. サイズと変換の情報を使用して、画像をページに追加します。
  4. タグのシェイプを削除します。

次のセクションで説明するように、画像を目的のサイズに拡大縮小しながらアスペクト比を維持するには、注意が必要です。図形タグを画像に置き換えるのサンプルもご覧ください。

アスペクト比を保持

Slides API を使用して画像を作成する場合、アスペクト比の調整は、サイズと変換データではなく、画像サイズのみに基づいて行われます。createImage リクエストで指定したサイズデータは、画像の目的のサイズと見なされます。API は、画像の縦横比をこの目的のサイズに合わせ、指定された変換を適用します。

タグを画像に置き換える場合、画像のアスペクト比を維持するには、画像のサイズとスケーリングを次のように設定します。

  • width: タグの widthscaleX の積に設定します。
  • height: タグの heightscaleY の積に設定します。
  • scale_x: 1 に設定
  • scale_y: 1 に設定

これにより、Slides API は、スケーリングされていないサイズではなく、タグの視覚的なサイズに合わせて画像をアスペクト比を維持したままフィットさせます(シェイプタグを画像に置き換えるをご覧ください)。スケーリング パラメータを 1 に設定すると、画像が 2 回スケーリングされるのを防ぐことができます。

この配置により、画像のアスペクト比が維持され、画像のサイズがタグの形状を超えないようになります。画像はタグの形状と同じ中心点を持ちます。

テンプレートの管理

アプリケーションが定義して所有するテンプレート プレゼンテーションの場合は、アプリケーションを表す専用のアカウントを使用してテンプレートを作成します。サービス アカウントは、共有を制限する Google Workspace ポリシーによる複雑な問題を回避できるため、適切な選択肢です。

テンプレートからプレゼンテーションのインスタンスを作成する場合は、常にエンドユーザーの認証情報を使用します。これにより、ユーザーは作成されたプレゼンテーションを完全に制御でき、Google ドライブのユーザーごとの上限に関連するスケーリングの問題を防ぐことができます。

サービス アカウントを使用してテンプレートを作成するには、アプリケーションの認証情報を使用して次の操作を行います。

  1. Slides API の presentations.create を使用してプレゼンテーションを作成します。
  2. Drive API の permissions.create を使用して、プレゼンテーションの受信者が読み取れるように権限を更新します。
  3. Drive API の permissions.create を使用して、テンプレート作成者が書き込めるように権限を更新します。
  4. 必要に応じてテンプレートを編集します。

プレゼンテーションのインスタンスを作成するには、ユーザー認証情報を使用して次の手順を行います。

  1. Drive API の files.copy を使用して、テンプレートのコピーを作成します。
  2. Slides API の presentation.batchUpdate を使用して値を置き換えます。