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 bản trình bày mẫu hiện có. Khái niệm này tương tự như tính năng hợp nhất thư sử dụ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 cách sử dụ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 để thiết lập thiết kế trang trình bày được kết xuất.

  • Việc tách nội dung khỏi bản trình bày là một nguyên tắc thiết kế phổ biến với nhiều lợi ích.

Sơ đồ khái niệm về quá trình hợp nhất.

Công thức cơ bản

Dưới đâ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 bản trình bày:

  1. Tạo bản trình bày theo cách bạn muốn bằng cách sử dụng nội dung phần giữ chỗ để giúp bạn thiết kế.

  2. Đối với mỗi phần tử nội dung mà bạn sẽ chèn, hãy thay thế nội dung phần giữ chỗ bằng một thẻ. Thẻ là các 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ó có khả năng xảy ra bình thường. Ví dụ: {{account-holder-name}} có thể là một thẻ tốt.

  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 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 hoạt động thay thế văn bản trong toàn bộ bản trình bày. Sử dụng các yêu cầu replaceAllShapesWithImage để thực hiện việc thay thế hình ảnh trong toàn bộ bản trình bày.

Sau khi tạo 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 để xử lý bản sao. Đừng sử dụng API Trang trình bày để thao túng bản sao "mẫu" chính của bạn!

Các phần sau 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ẻ dưới đây.

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

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

Ví dụ:

Ví dụ này sử dụng API Drive để sao chép bản trình bày mẫu, tạo thành phiên bản mới của bản trình bày. Sau đó, công cụ này sử dụng API Google Trang tính để đọc dữ liệu trên một bảng tính rồi mới 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 đó, phương thức này sẽ thay thế dữ liệu đó vào bản trình bày ở bất cứ nơi nào các chuỗi {{customer-name}}, {{case-description}} hoặc {{total-portfolio}} xảy ra.

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

trang trình bày/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

trang trình bày/snippets/slide_text_merge.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

trang trình bày/snippets/slide_text_merge.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;
  }
}

1.199

slides/snippets/src/SlidesTextMerging.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

trang trình bày/snippets/slide_text_merge.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 các 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 replaceAllShapesWithImage. Yêu cầu này sẽ thay thế tất cả các bản sao 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 sẽ tự động đặt và điều chỉnh tỷ lệ hình ảnh cho vừa với giới hạn của hình dạng thẻ mà vẫn duy trì 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 mẫu, tạo thành phiên bản mới của bản trình bày. Sau đó, thư viện 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 biểu trưng của công ty. Yêu cầu này cũng thay thế mọi hình dạng bằng 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.
    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

trang trình bày/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

trang trình bày/snippets/slide_image_merge.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

trang trình bày/snippets/slide_image_merge.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;
  }
}

1.199

slides/snippets/src/SlidesImageMerging.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

trang trình bày/snippets/slide_image_merge.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 phiên bản 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 cho việc thay thế thẻ trong toàn bộ bản trình bày, nhưng đôi khi bạn chỉ cần thay thế các phần tử theo tiêu chí khác, chẳng hạn như được đặt 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 hình dạng thẻ mà bạn muốn thay thế. Để thay thế văn bản, bạn 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).

Việc thay thế hình ảnh phức tạp hơn. Để hợp nhất trong mộ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 kích thước và chuyển đổi thông tin từ thẻ.
  3. Thêm hình ảnh của bạn vào trang, sử dụng thông tin kích thước và biến đổi.
  4. Xoá hình dạng thẻ.

Bạn có thể phải cẩn trọng khi duy trì tỷ lệ khung hình của hình ảnh trong khi điều chỉnh tỷ lệ theo kích thước mong muốn, như mô tả trong phần sau đây. Ngoài ra, hãy 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, chế độ vừa vặn theo khung hình chỉ dựa trên kích thước hình ảnh chứ không dựa trên kích thước và dữ liệu biến đổi. Dữ liệu kích thước mà bạn cung cấp trong yêu cầu createImage đượ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 với kích thước mong muốn, sau đó áp dụng phép biến đổi được cung cấp.

Khi thay thế thẻ bằng một hình ảnh, bạn giữ nguyên tỷ lệ khung hình của hình ảnh bằng cách đặt kích thước và 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 khớp với hình ảnh theo kích thước hình ảnh của thẻ, thay vì kích thước không được điều chỉnh theo tỷ lệ (xem phần Thay thế thẻ hình dạng bằng hình ảnh). Việc đặt các tham số tỷ lệ thành 1 sẽ ngăn hình ảnh được điều chỉnh theo tỷ lệ hai lần.

Sự sắp xếp này đảm bảo tỷ lệ khung hình của hình ảnh được giữ nguyên 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 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 đề với các chính sách của Google Workspace hạn chế việc chia sẻ.

Khi bạn tạo các bản sao của bản trình bày từ mẫu, hãy luôn sử dụng thông tin đăng nhập của người dùng cuối. Điều này mang lại cho người dùng toàn quyền kiểm soát quá trình trình bày kết quả và ngăn ngừa các vấn đề về việc mở rộng quy mô liên quan đến giới hạn trên 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 đây với thông tin đăng nhập của ứng dụng:

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

Để tạo một bản sao của bản trình bày, hãy thực hiện các bước sau đây với thông tin đăng nhập của người dùng:

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