# Android PdfDocumentで複雑絵文字を白黒Bitmapとして描画する
Android の PdfDocument で、複雑な絵文字を1つの見た目として白黒表示する方法を整理します。
# 方針
- 通常文字は
Canvas.drawText()で描画します。 - 単純な絵文字は、白黒絵文字フォントの
getTextPath()を使用できます。 - ZWJ、国旗、keycap などの複雑な絵文字は、
EmojiCompatのEmojiSpanを一度Bitmapに描画します。 Bitmapは黒のアルファマスクに変換してから PDF へ描画します。
PdfDocument の Canvas.drawText() だけでは、複雑な絵文字が複数の glyph に分離することがあります。EmojiSpan を利用すると、EmojiCompat が解決した1つの見た目を使用できます。
# 最小サンプル
このコードは、EmojiCompat の初期化完了後に呼び出します。androidx.emoji2:emoji2 と androidx.emoji2:emoji2-bundled が必要です。
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.pdf.PdfDocument;
import android.text.Spanned;
import androidx.emoji2.text.EmojiCompat;
import androidx.emoji2.text.EmojiSpan;
import java.io.IOException;
import java.io.OutputStream;
public final class EmojiBitmapPdf {
public static void write(OutputStream output) throws IOException {
if (EmojiCompat.get().getLoadState() != EmojiCompat.LOAD_STATE_SUCCEEDED) {
throw new IllegalStateException("EmojiCompat の初期化完了後に実行してください");
}
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setTextSize(72);
Bitmap emoji = toMonochromeBitmap("😶🌫️", paint);
PdfDocument document = new PdfDocument();
PdfDocument.Page page = document.startPage(
new PdfDocument.PageInfo.Builder(300, 200, 1).create());
page.getCanvas().drawBitmap(emoji, 32, 32, paint);
document.finishPage(page);
document.writeTo(output);
document.close();
emoji.recycle();
}
private static Bitmap toMonochromeBitmap(String text, Paint paint) {
Spanned spanned = (Spanned) EmojiCompat.get().process(text);
EmojiSpan span = spanned.getSpans(0, spanned.length(), EmojiSpan.class)[0];
int start = spanned.getSpanStart(span);
int end = spanned.getSpanEnd(span);
Paint.FontMetricsInt metrics = paint.getFontMetricsInt();
int width = span.getSize(paint, spanned, start, end, metrics);
Bitmap bitmap = Bitmap.createBitmap(width, metrics.descent - metrics.ascent,
Bitmap.Config.ARGB_8888);
span.draw(new Canvas(bitmap), spanned, start, end, 0, 0,
-metrics.ascent, bitmap.getHeight(), paint);
for (int y = 0; y < bitmap.getHeight(); y++) {
for (int x = 0; x < bitmap.getWidth(); x++) {
int color = bitmap.getPixel(x, y);
int alpha = Color.alpha(color);
int darkness = 255 - (Color.red(color) * 299
+ Color.green(color) * 587 + Color.blue(color) * 114) / 1000;
bitmap.setPixel(x, y, Color.argb(alpha * darkness / 255, 0, 0, 0));
}
}
return bitmap;
}
}
# 注意点
- この方法では、絵文字は PDF 上で画像として扱われます。選択やコピーは維持されません。
- 変換後の
Bitmapは必要に応じて透明余白をトリミングします。 - 同じ絵文字を繰り返し描画する場合は、文字列と文字サイズをキーにして
Bitmapをキャッシュします。 EmojiSpanを得られない場合だけ、白黒絵文字フォントやシステム絵文字へフォールバックします。
この方法は、複雑な絵文字を1つの見た目として PDF に出力したい場合の実用的な選択肢です。