# 从相册中选择图片添加到PDF页面中

#### 问题现象

从相册选择的图片怎么转换成PDF文档，或者说新建一个PDF文档，怎么插入在相册选择的图片。

#### 背景知识

*   使用PhotoPicker组件访问图片/视频：当应用需要读取用户图片时，开发者可以在应用界面中嵌入PhotoPicker组件，在用户选择所需要的图片资源后，直接返回该图片资源，而不需要授予应用读取图片文件的权限，即可完成图片或视频文件的访问和读取。
*   PDF Kit（PDF服务）支持编辑PDF页面内容，包括：添加、删除文本、添加、删除图片、添加、修改、删除批注、通过索引指定PDF页面添加批注。

#### 解决方案

*   aboutToAppear回调中，确保rawfile目录下有PDF文件如input.pdf文档，拷贝到沙箱内。
*   selectPhoto()通过PhotoPicker组件直接返回该图片资源，而不需要授予应用读取图片文件的权限。PhotoViewPicker选择图片保存到uri。
*   getFilePath()使用基础文件fs.openSync接口，通过uri打开这个文件得到fd，复制到沙箱中，获取沙箱路径。
*   确保沙箱目录已有如input.pdf文档调用loadDocument方法，加载PDF文档。在【addImage】按钮中调用addImageObject的方法添加沙箱路径中上述步骤选择的相册图片。
*   添加图片后保存PDF到沙箱路径中。可在IDE中查看通过View -> Tool Windows -> Device File Browser打开，Device File Browser对应沙箱目录如下：“/data/app/el2/100/base/com.example.myapplication/haps/entry/files/testAddImage.pdf”。

```
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { fileIo } from '@kit.CoreFileKit';
import { pdfService } from '@kit.PDFKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { promptAction } from '@kit.ArkUI';
import { common } from '@kit.AbilityKit';

@Entry
@Component
struct PhotoPickerComponentDemo {
  // 缓存选择的图片uri
  uri: Array<string> = [];
  private pdfDocument: pdfService.PdfDocument = new pdfService.PdfDocument();
  private context = this.getUIContext().getHostContext() as Context;

  async aboutToAppear(): Promise<void> {
    try {
      //确保rawfile目录下有pdf文件
      await this.copyRawFileToSdcard(this.context, 'input.pdf');
      promptAction.openToast({ message: '全部拷贝完成' });
    } catch (error) {
      promptAction.openToast({ message: '文件拷贝失败' });
    }
  }

  private copyRawFileToSdcard(context: common.Context, pdfName: string): Promise<void> {
    return new Promise((resolve) => {
      let destRoot = context.filesDir;
      // rawfile下的文件名
      let srcFileName = pdfName;
      let destFilePath = `${destRoot}/${srcFileName}`;
      context.resourceManager.getRawFileContent(srcFileName, (error: BusinessError, data: Uint8Array) => {
        if (error) {
          promptAction.openToast({ message: '拷贝失败' });
          console.error(`error.code is ${error.code},error.message is ${error.message},`);
          return;
        }
        let fileStream = fileIo.createStreamSync(destFilePath, 'w+');
        fileStream.writeSync(data.buffer);
        fileStream.close();
        promptAction.openToast({ message: '拷贝成功' });
        resolve();
      });
    });
  }

  selectPhoto() {
    try {
      let photoSelectOptions = new photoAccessHelper.PhotoSelectOptions();
      photoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;
      photoSelectOptions.maxSelectNumber = 5;
      let photoPicker = new photoAccessHelper.PhotoViewPicker();
      photoPicker.select(photoSelectOptions).then((PhotoSelectResult: photoAccessHelper.PhotoSelectResult) => {
        // select方法：在选择图片点击完成之后，PhotoSelectResult.photoUris返回选中的uri
        this.uri = PhotoSelectResult.photoUris;
        console.info(`PhotoViewPicker.select successfully, PhotoSelectResult uri: ${JSON.stringify(PhotoSelectResult)}`);
      }).catch((err: BusinessError) => {
        console.error(`PhotoViewPicker.select failed with err: ${err.code}, ${err.message}`);
      });
    } catch (error) {
      let err: BusinessError = error as BusinessError;
      console.error(`PhotoViewPicker failed with err: ${err.code}, ${err.message}`);
    }
  }

  // 使用fs.openSync接口，通过uri打开这个文件得到fd，拷贝到新路径
  getFilePath(uri: string): string {
    let file = fileIo.openSync(uri, fileIo.OpenMode.READ_ONLY);
    const dateStr = (new Date().getTime()).toString();
    // 临时文件目录
    let newPath = this.context.filesDir + `/${dateStr + file.name}`;
    // 转化路径
    fileIo.copyFileSync(file.fd, newPath);
    // 沙箱路径
    let realUri = newPath;
    console.info(`newPath is : ${realUri}`);
    return realUri;
  }

  build() {
    Column() {
      Button('select').onClick(() => {
        this.selectPhoto();
      })
      // 添加图片
      Button('addImage').onClick(async () => {
        // 确保沙箱目录有input.pdf文档
        let filePath = this.context.filesDir + '/input.pdf';
        let loadResult = this.pdfDocument.loadDocument(filePath, '');
        if (pdfService.ParseResult.PARSE_SUCCESS === loadResult) {
          let page: pdfService.PdfPage = this.pdfDocument.getPage(0);
          console.info(`click info>>`);
          console.info(`file path info>> ${this.getFilePath(this.uri[0])}`);
          // 插入图片，沙箱目录已有选择后的图片
          page.addImageObject(this.getFilePath(this.uri[0]), 100, 100, 100, 120);
          let outPdfPath = this.context.filesDir + '/testAddImage.pdf';
          console.info(`outPdfPath info>>${outPdfPath}`);
          let result = this.pdfDocument.saveDocument(outPdfPath);
          hilog.info(0x0000, 'PdfPage', 'addImage %{public}s!', result ? 'success' : 'fail');
        }
      })
    }

  }
}
```