Hợp nhất dữ liệu vào một bản trình bày

Một ứng dụng hữu ích của API Google Trang trình bày là hợp nhất thông tin từ một hoặc nhiều nguồn dữ liệu vào một bản trình bày theo mẫu.

Trang này trình bày cách bạn có thể lấy dữ liệu từ một nguồn bên ngoài và chèn dữ liệu đó vào một bản trình bày theo mẫu hiện có. Khái niệm này tương tự như khái niệm hợp nhất thư bằng trình xử lý văn bản và bảng tính.

Có một số lý do khiến phương pháp này hữu ích:

  • Nhà thiết kế có thể dễ dàng tinh chỉnh thiết kế của bản trình bày bằng trình chỉnh sửa Google Trang trình bày. Việc này dễ dàng hơn nhiều so với việc điều chỉnh các tham số trong ứng dụng để đặt thiết kế trang trình bày được kết xuất.

  • Tách nội dung khỏi bản trình bày là một nguyên tắc thiết kế nổi tiếng mang lại nhiều lợi ích.

Sơ đồ khái niệm về một thao tác hợp nhất.

Công thức cơ bản

Sau đây là ví dụ về cách bạn có thể sử dụng API Trang trình bày để hợp nhất dữ liệu vào một bản trình bày:

  1. Tạo bản trình bày theo cách bạn muốn hiển thị bằng nội dung giữ chỗ để giúp bạn thiết kế.

  2. Đối với mỗi thành phần nội dung mà bạn sẽ chèn, hãy thay thế phần giữ chỗ nội dung bằng một thẻ. Thẻ là hộp văn bản hoặc hình dạng có một chuỗi duy nhất. Hãy nhớ sử dụng các chuỗi khó xuất hiện một cách bình thường. Ví dụ: {{account-holder-name}} có thể là một thẻ phù hợp.

  3. Trong mã của bạn, hãy sử dụng API Google Drive để tạo bản sao của bản trình bày.

  4. Trong mã của bạn, hãy sử dụng phương thức batchUpdate của API Trang trình bày với một tập hợp các yêu cầu replaceAllText để thực hiện tất cả các thao tác thay thế văn bản trong bản trình bày. Sử dụng replaceAllShapesWithImage yêu cầu để thực hiện các thao tác thay thế hình ảnh trong bản trình bày.

Sau khi tạo một bản trình bày có thẻ, hãy nhớ tạo bản sao và sử dụng API Trang trình bày để thao tác với bản sao đó. Không sử dụng API Trang trình bày để thao tác với bản sao "mẫu" chính của bạn!

Các phần sau đây bao gồm các đoạn mã minh hoạ một số quy trình này. Bạn cũng có thể xem video ở trên để xem một ví dụ hoàn chỉnh (Python) kết hợp một số khái niệm trong các phần riêng lẻ bên dưới.

Hợp nhất văn bản

Bạn có thể sử dụng replaceAllText yêu cầu để thay thế tất cả các thực thể của một chuỗi văn bản nhất định trong bản trình bày bằng văn bản mới. Đối với thao tác hợp nhất, thao tác này đơn giản hơn so với việc tìm và thay thế từng thực thể văn bản riêng lẻ. Một lý do khiến đây là phương pháp phức tạp nhất là vì khó dự đoán được mã nhận dạng của phần tử trang, đặc biệt là khi cộng tác viên tinh chỉnh và duy trì bản trình bày theo mẫu.

Ví dụ:

Ví dụ này sử dụng API Drive để sao chép bản trình bày theo mẫu, tạo một thực thể mới của bản trình bày. Sau đó, ví dụ này sử dụng API Google Trang tính để đọc dữ liệu từ một bảng tính Trang tính và cuối cùng sử dụng API Trang trình bày để cập nhật bản trình bày mới.

Ví dụ này lấy dữ liệu từ 3 ô trong một hàng của một dải ô được đặt tên trong bảng tính. Sau đó, ví dụ này thay thế dữ liệu đó vào bản trình bày ở bất cứ nơi nào xuất hiện các chuỗi {{customer-name}}, {{case-description}}, hoặc {{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) {
  const responses = [];
  const dataRangeNotation = "Customers!A2:M6";
  try {
    const 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;
      for (const reply of result.replies) {
        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
import {GoogleAuth} from 'google-auth-library';
import {google} from 'googleapis';

/**
 * Merges text from a spreadsheet into a template presentation.
 * @param {string} templatePresentationId The ID of the template presentation.
 * @param {string} dataSpreadsheetId The ID of the spreadsheet containing the data.
 */
async function textMerging(templatePresentationId, dataSpreadsheetId) {
  // Authenticate with Google and get an authorized client.
  const auth = new GoogleAuth({
    scopes: [
      'https://www.googleapis.com/auth/presentations',
      'https://www.googleapis.com/auth/drive',
      'https://www.googleapis.com/auth/spreadsheets',
    ],
  });

  // Create new clients for Slides, Sheets, and Drive APIs.
  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 from the spreadsheet.
  const dataRangeNotation = 'A2:M6';
  const sheetsResponse = await sheetsService.spreadsheets.values.get({
    spreadsheetId: dataSpreadsheetId,
    range: dataRangeNotation,
  });
  const values = sheetsResponse.data.values;

  // For each row of data, create a new presentation by copying the template
  // and replacing the placeholder text with the data.
  for (let i = 0; i < values.length; ++i) {
    const row = values[i];
    const customerName = row[2]; // Column 3
    const caseDescription = row[5]; // Column 6
    const totalPortfolio = row[11]; // Column 12

    // Duplicate the template presentation.
    const title = `${customerName} presentation`;
    const driveResponse = await driveService.files.copy({
      fileId: templatePresentationId,
      requestBody: {
        title,
      },
    });
    const presentationCopyId = driveResponse.data.id;

    // Create the text merge 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 to replace the placeholder text.
    const batchUpdateResponse = await slidesService.presentations.batchUpdate({
      presentationId: presentationCopyId,
      requestBody: {
        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.`);
  }
}

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
  )

Hợp nhất hình ảnh

Bạn cũng có thể hợp nhất hình ảnh vào bản trình bày bằng yêu cầu a replaceAllShapesWithImage. Yêu cầu này thay thế tất cả các thực thể của hình dạng chứa chuỗi văn bản được cung cấp bằng hình ảnh được cung cấp. Yêu cầu này tự động định vị và điều chỉnh tỷ lệ hình ảnh cho phù hợp với ranh giới của hình dạng thẻ trong khi vẫn giữ nguyên tỷ lệ khung hình của hình ảnh.

Ví dụ:

Ví dụ này sử dụng API Google Drive để sao chép bản trình bày theo mẫu, tạo một thực thể mới của bản trình bày. Sau đó, ví dụ này sử dụng API Trang trình bày để tìm bất kỳ hình dạng nào có văn bản {{company-logo}} và thay thế bằng hình ảnh logo công ty. Yêu cầu này cũng thay thế bất kỳ hình dạng nào có văn bản {{customer-graphic}} bằng một hình ảnh khác.

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.
    const batchUpdateResponse = Slides.Presentations.batchUpdate(
      {
        requests: requests,
      },
      presentationCopyId,
    );
    let numReplacements = 0;
    for (const reply of batchUpdateResponse.replies) {
      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
import {GoogleAuth} from 'google-auth-library';
import {google} from 'googleapis';

/**
 * Replaces shapes in a presentation with images.
 * @param {string} templatePresentationId The ID of the template presentation.
 * @param {string} imageUrl The URL of the image to use.
 * @param {string} customerName The name of the customer for the new presentation title.
 * @return {Promise<object>} The response from the batch update.
 */
async function imageMerging(templatePresentationId, imageUrl, customerName) {
  // Authenticate with Google and get an authorized client.
  const auth = new GoogleAuth({
    scopes: [
      'https://www.googleapis.com/auth/presentations',
      'https://www.googleapis.com/auth/drive',
    ],
  });

  // Create new clients for Slides and Drive APIs.
  const slidesService = google.slides({version: 'v1', auth});
  const driveService = google.drive({version: 'v2', auth});

  const logoUrl = imageUrl;
  const customerGraphicUrl = imageUrl;

  // Duplicate the template presentation.
  const copyTitle = `${customerName} presentation`;
  const driveResponse = await driveService.files.copy({
    fileId: templatePresentationId,
    requestBody: {
      name: copyTitle,
    },
  });
  const presentationCopyId = driveResponse.data.id;

  // Create the image merge 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 to replace the shapes with images.
  const batchUpdateResponse = await slidesService.presentations.batchUpdate({
    presentationId: presentationCopyId,
    requestBody: {
      requests,
    },
  });

  // Count the total number of replacements made.
  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;
}

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"

Thay thế các thực thể hộp văn bản hoặc hình ảnh cụ thể

Các yêu cầu replaceAllTextreplaceAllShapesWithImage rất hữu ích để thay thế các thẻ trong bản trình bày, nhưng đôi khi bạn chỉ cần thay thế các thành phần theo một tiêu chí khác, chẳng hạn như nằm trên một trang trình bày cụ thể.

Trong những trường hợp này, bạn phải truy xuất mã nhận dạng của các hình dạng thẻ mà bạn muốn thay thế. Đối với thao tác thay thế văn bản, bạn sẽ xoá văn bản hiện có trong các hình dạng đó rồi chèn văn bản mới (xem mẫu Chỉnh sửa văn bản trong một hình dạng được chỉ định).

Thao tác thay thế hình ảnh phức tạp hơn. Để hợp nhất hình ảnh, bạn cần:

  1. Lấy mã nhận dạng của hình dạng thẻ.
  2. Sao chép thông tin về kích thước và chuyển đổi từ thẻ.
  3. Thêm hình ảnh của bạn vào trang, sử dụng thông tin về kích thước và biến đổi.
  4. Xoá hình dạng thẻ.

Việc giữ nguyên tỷ lệ khung hình của hình ảnh trong khi điều chỉnh tỷ lệ hình ảnh theo kích thước mong muốn có thể đòi hỏi bạn phải cẩn thận, như mô tả trong phần sau. Bạn cũng có thể xem mẫu này: Thay thế thẻ hình dạng bằng hình ảnh.

Giữ nguyên tỷ lệ khung hình

Khi bạn tạo hình ảnh bằng API Trang trình bày, các tỷ lệ khung hình chỉ dựa trên kích thước hình ảnh chứ không dựa trên dữ liệu về kích thước và chuyển đổi. Dữ liệu về kích thước mà bạn cung cấp trong createImage yêu cầu được coi là kích thước mong muốn của hình ảnh. API này điều chỉnh tỷ lệ khung hình của hình ảnh theo kích thước mong muốn này, sau đó áp dụng phép chuyển đổi được cung cấp.

Khi thay thế thẻ bằng hình ảnh, bạn sẽ giữ nguyên tỷ lệ khung hình của hình ảnh bằng cách đặt kích thước và điều chỉnh tỷ lệ hình ảnh như sau:

  • width: đặt thành tích của widthscaleX của thẻ
  • height: đặt thành tích của heightscaleY của thẻ
  • scale_x: đặt thành 1
  • scale_y: đặt thành 1

Điều này khiến API Trang trình bày điều chỉnh tỷ lệ khung hình của hình ảnh theo kích thước trực quan của thẻ, thay vì kích thước không được điều chỉnh tỷ lệ (xem phần Thay thế thẻ hình dạng bằng hình ảnh). Việc đặt các tham số điều chỉnh tỷ lệ thành 1 sẽ ngăn hình ảnh bị điều chỉnh tỷ lệ hai lần.

Cách sắp xếp này đảm bảo giữ nguyên tỷ lệ khung hình của hình ảnh và ngăn hình ảnh vượt quá kích thước của hình dạng thẻ. Hình ảnh có cùng điểm giữa với hình dạng thẻ.

Quản lý mẫu

Đối với các bản trình bày theo mẫu mà ứng dụng xác định và sở hữu, hãy tạo mẫu bằng một tài khoản riêng đại diện cho ứng dụng. Tài khoản dịch vụ là một lựa chọn phù hợp và tránh các vấn đề phức tạp với các chính sách của Google Workspace hạn chế việc chia sẻ.

Khi tạo thực thể của bản trình bày từ mẫu, hãy luôn sử dụng thông tin xác thực của người dùng cuối. Điều này giúp người dùng kiểm soát hoàn toàn bản trình bày kết quả và ngăn các vấn đề về điều chỉnh tỷ lệ liên quan đến giới hạn cho mỗi người dùng trong Google Drive.

Để tạo mẫu bằng tài khoản dịch vụ, hãy thực hiện các bước sau bằng thông tin xác thực của ứng dụng:

  1. Tạo bản trình bày bằng presentations.create trong API Trang trình bày.
  2. Cập nhật quyền để cho phép người nhận bản trình bày đọc bản trình bày đó bằng permissions.create trong Drive API.
  3. Cập nhật quyền để cho phép tác giả mẫu ghi vào bản trình bày đó bằng permissions.create trong Drive API.
  4. Chỉnh sửa mẫu theo yêu cầu.

Để tạo thực thể của bản trình bày, hãy thực hiện các bước sau bằng thông tin xác thực của người dùng:

  1. Tạo bản sao của mẫu bằng files.copy trong API Drive.
  2. Thay thế các giá trị bằng presentation.batchUpdate trong API Trang trình bày.