2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

PDFアップロード時のプレビューが白紙になる

Posted at

内容

プロダクトの中に、PDFをアップロードする部分があり、
そこで特定のPDFアップロードすると、下記のように枠線だけ残って、文字が消えるといった自体を発見。
このときの調査の履歴と対応を記しておく。
ライブラリにreact-pdf@3.0.5を利用していた。(pdfjs-dist)
諸事情で今はライブラリのアップデートとかはしたくない!なんてときに役立つはず。
同じような問題に直面している人に少しでも助けになりますように。

image.png

前提知識

react-pdfとは

React アプリケーション内で PDF ドキュメントを表示、操作、作成するためのライブラリ。
アプリを作成するときにこのライブラリをインストールして、importして使う。
このライブラリの中でpdfjs-distも使われている
https://react-pdf.org/

pdfjs-distとは

PDF.jsのビルド成果物。これをnpm installで自分のアプリにインストールしてPDF.jsが使えるようになる。

PDF.jsとは

Mozillaが開発した、オープンソースのJavaScriptライブラリ。
ウェブブラウザ内でPDFドキュメントを表示するためのもの

pdfの文字表示のために必要なこと

cmapsの理解。フォントが持つそれぞれの文字と、文字コードを結びつけるための対応表のこと。
PDF.jsなどのPDFレンダリングライブラリはPDF内の文字を実際のUnicode文字にマッピングさせることで、ブラウザでの表示を可能にしている。つまり、PDFが持っている文字の情報をブラウザで表示するためにマッピングの情報を予め持っておく必要がある。そのマッピングを行うものの1つがcmaps。
PDF.jsはそれをライブラリ内部にこんな感じで持っている。
image.png

参考)
https://www.morisawa.co.jp/culture/dictionary/1921#:~:text=%E3%83%95%E3%82%A9%E3%83%B3%E3%83%88%E3%81%8C%E6%8C%81%E3%81%A4%E3%81%9D%E3%82%8C%E3%81%9E%E3%82%8C%E3%81%AE,CID%E3%81%8C%E4%BD%BF%E3%82%8F%E3%82%8C%E3%81%BE%E3%81%99%E3%80%82

今回の事象

上記スクショのように、アプリ内でcmapsを持っていて、そこを参照してレンダリングされるようになっている場合、ユーザーによってアップロードされたPDFの文字コードが、今、システムに取り込まれている、このライブラリ内のcmapsにマッピングがない場合、このマッピングがうまくいかず、ブラウザでレンダリングできないというような状況になってしまう!!(ここに至るまでかなりの時間を溶かした)

参考)

対応

じゃあ、Web上に転がっている最新のやつを参照するようにすればよくね?
おそらくこのマッピングの参照元を定義している場所があって、そこをどうにかすればなんとかなるのでは
という発想。

それが下記の部分。
react-pdfはデフォルトではライブラリ内を読み込もうとする。

const options = {
  cMapUrl: 'cmaps/',
  cMapPacked: true,
};

ここを変更する。なんとオプションをつけることができて、読み込むソースを指定できる。
setOptionsをimportする(setOptionsはreact-pdfの3.0.5専用)

import { Document, Page, setOptions } from 'react-pdf';

利用前にsetOptionsを定義しておく
このcMapUrlというところを自分のプロダクトに適するものをチョイスする。

setOptions({
    cMapUrl: 'https://cdn.jsdelivr.net/npm/pdfjs-dist@2.0.305/cmaps/',
    cMapPacked: true,
});

利用する部分でoptionをもたせる

<Document
    file={file}
    onLoadSuccess={this.onDocumentLoadSuccess}
    options={options}
>

これで表示されるようになった!!

参考)
https://github.com/wojtekmaj/react-pdf/commit/6cc17ca63d5742f23293e8379202a37787941f8f

書簡

自分が作った部分じゃなかった(ほとんどそう)ので、pdfをブラウザにどうやって出しているかというところからの調査。
後任エンジニアあるあるの、問い合わせを投げてきている人よりこの周辺を知らないところからのよーいどん。
前提知識すらいろんなドキュメントを漁って、githubに載っているライブラリの中のソースコードを読んで漸くたどり着けた。
この記事を書くために自分の作業ログを見ていたら、誕生日にこの調査やっていた。エンジニア冥利に尽きるぜ(涙)
同じような問題に直面している人に少しでも助けになりますように。と本当に心から思ってこの記事書こうと思いました。
もっといい解決は絶対あるとは思う。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?