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

#### 问题现象

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

#### 背景知识

*   [使用PhotoPicker组件访问图片/视频](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/component-guidelines-photoviewpicker)：当应用需要读取用户图片时，开发者可以在应用界面中嵌入PhotoPicker组件，在用户选择所需要的图片资源后，直接返回该图片资源，而不需要授予应用读取图片文件的权限，即可完成图片或视频文件的访问和读取。
*   [PDF Kit（PDF服务）](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/pdf-kit-guide)支持编辑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');
        }
      })
    }

  }
}