PDFファイルにフィールドの文字を差し込みたい

コパイロットに以下で、作成をお願いしましたが、まったく動きません。お助けください。kintoneの「配水管図面」フィールドに添付されたPDFファイルに、「図面付番用」フィールドの値を右下に差し込み、編集後のPDFを再度「配水管図面」フィールドに保存する完全なJavaScriptコード「配水管図面」フィールドは添付ファイルフィールド(フィールドコード: pdf_file

  • 「図面付番用」フィールドは文字列フィールド(フィールドコード: drawing_number

  • PDF編集には PDF-lib ライブラリを使用

(function () {
  'use strict';

  kintone.events.on('app.record.edit.show', async function (event) {
    const record = event.record;
    const fileObj = record.pdf_file.value[0];
    const drawingNumber = record.drawing_number.value;

    if (!fileObj || !drawingNumber) {
      console.warn('PDFファイルまたは図面付番用の値がありません。');
      return event;
    }

    try {
      // 添付ファイルの取得
      const fileKey = fileObj.fileKey;
      const fileResponse = await kintone.api(kintone.api.url('/k/v1/file', true), 'GET', { fileKey }, true);
      const arrayBuffer = await fileResponse.arrayBuffer();

      // PDF-libで編集
      const pdfDoc = await PDFLib.PDFDocument.load(arrayBuffer);
      const pages = pdfDoc.getPages();
      const lastPage = pages[pages.length - 1];

      const { width, height } = lastPage.getSize();
      const font = await pdfDoc.embedFont(PDFLib.StandardFonts.HelveticaBold);

      lastPage.drawText(drawingNumber, {
        x: width - 150,
        y: 30,
        size: 12,
        font: font,
        color: PDFLib.rgb(0, 0, 0),
      });

      const modifiedPdfBytes = await pdfDoc.save();

      // PDFを再アップロード
      const blob = new Blob([modifiedPdfBytes], { type: 'application/pdf' });
      const formData = new FormData();
      formData.append('file', blob, fileObj.name);

      const uploadResponse = await fetch(kintone.api.url('/k/v1/file', true), {
        method: 'POST',
        body: formData,
      });
      const uploadResult = await uploadResponse.json();

      // フィールドに新しいファイルを設定
      record.pdf_file.value = [{
        fileKey: uploadResult.fileKey,
        name: fileObj.name,
        size: blob.size,
      }];

      return event;

    } catch (error) {
      console.error('PDF編集エラー:', error);
      return event;
    }
  });
})();
コードをここに入力または貼り付け

「まったく動きません。」では状況があまり伝わらず回答者も困ってしまうと思うので、 ガイドライン にあるように、

  • 発生した問題やエラーメッセージを具体的に書きましょう

の段落があると良いと思います。


まずはなぜ動いていないのかを判断する必要があると思います。

cybozu developer network にもデバッグツールの使い方が載っているので、こちらを参考にどういう挙動をしているかを確認されるのが良いと思います。

あと、 Copilot には既に GPT-5 モードが追加されていると思うので、もしまだ使っていないのであれば有効にすると良いと思います。 4o と比べて精度が上がってる気がします。気だけですが。

「いいね!」 3

住田さん投稿のように、コンソールに出力されたコードの実行結果が欲しいところですが…。現時点で2点ほど気になったので投稿します。

  • 差し込むタイミングはレコード編集画面を開いたときですか?
    kintone.events.on('app.record.edit.show', ... );という記述ですが、app.record.edit.show レコード編集画面を表示した後のイベントを指します。
    レコードを追加して保存し、その後に編集画面を表示したタイミングでスクリプトが動作するかと思いますが、これは意図したものでしょうか。
    必要に応じてほかのイベントを指定したり、ボタンクリックによって動作させる方法など、適切なタイミングで実行できるように調整してみましょう。

  • PDF-libは適切に読み込まれていますか?
    「PDF-libライブラリを使用」と記載されていますが、投稿のJavaScriptコードには該当ライブラリを読み込む記述がないようです。
    JavaScriptコードに記述せず外部ライブラリを利用する場合は、 JavaScriptファイルやCSSファイルを適用する必要があります。
    おそらくPDF-LIBに記載のJSファイルについて、URL指定またはアップロードする必要があると思いますが、アプリ設定は済んでいますか。
    また、JavaScript・CSSでのカスタマイズは、より上に配置したものから適用されるため、Copilotに生成させたJSスクリプトよりも、PDF-libのJSファイルを上位に配置する必要があります。

ざっと記載しましたが、解決しない場合はコンソールに出力された容が重要となります。コンソールに出力された情報も投稿いただくと、より的確な回答も得られるかと存じます。

「いいね!」 2

ご回答ありがとうございます。質問の仕方がわるくて大変申し訳ございませんでした。

GPT5モードで試してみたいと思います。

「いいね!」 1

copilotでここまでできるのはすごいですね。

ChatGPTに以下のURLを読み込んで回答してもらったら、動くようになりました。

ファイルダウンロードで必須となる2つの手順 - cybozu developer network

ファイルアップロードで必須となる3つの手順 - cybozu developer network

デバッガーとかコードを書きたくない場合のやり方としては、

  • まず、単体でファイルをダウンロードできるボタンのコードを作成してもらう。ダウンロード方法の解説ページを参照させる。
  • PDFに文字を入れるコードでダウンロードだけする。PDF編集が完了しているか?
  • 最後にアップロードするコードも継ぎ足す。アップロードの解説ページを参照させる。

一部、変更しています。

(function () {
  'use strict';

  const BUTTON_ID = 'pdf-stamp-upload';

  kintone.events.on('app.record.detail.show', (event) => {
    const record = event.record;
    const header = kintone.app.record.getHeaderMenuSpaceElement();
    if (!header || document.getElementById(BUTTON_ID)) return event;

    const btn = document.createElement('button');
    btn.id = BUTTON_ID;
    btn.textContent = 'PDFに図番追記→添付置換';
    btn.className = 'kintoneplugin-button-normal';
    header.appendChild(btn);

    btn.addEventListener('click', async () => {
      btn.disabled = true;

      try {
        // 入力チェック
        const fileValue = record.pdf_file?.value;
        const drawingNumber = record.drawing_number?.value;
        if (!Array.isArray(fileValue) || fileValue.length === 0 || !drawingNumber) {
          alert('PDFファイルまたは図番が未設定です。');
          return;
        }
        const { fileKey, name } = fileValue[0];

        // 1) 添付PDFのダウンロード(公式チップス準拠)
        const dlUrl = `${kintone.api.url('/k/v1/file', true)}?fileKey=${encodeURIComponent(fileKey)}`;
        const dlRes = await fetch(dlUrl, {
          method: 'GET',
          headers: { 'X-Requested-With': 'XMLHttpRequest', 'Cache-Control': 'no-cache' },
        });
        if (!dlRes.ok) throw new Error(`Download failed: ${dlRes.status} ${dlRes.statusText}`);
        const arrayBuffer = await dlRes.arrayBuffer();

        // 2) PDF-lib で最後のページに図番を描画
        const pdfDoc = await PDFLib.PDFDocument.load(arrayBuffer);
        const pages = pdfDoc.getPages();
        if (pages.length === 0) throw new Error('PDFにページがありません。');
        const lastPage = pages[pages.length - 1];
        const { width } = lastPage.getSize();
        const font = await pdfDoc.embedFont(PDFLib.StandardFonts.HelveticaBold);

        lastPage.drawText(String(drawingNumber), {
          x: Math.max(0, width - 220),
          y: 30,
          size: 30,
          font,
          color: PDFLib.rgb(0, 0, 0)
        });

        const modified = await pdfDoc.save();

        // 3) アップロード(公式チップス準拠:FormData に __REQUEST_TOKEN__ を入れる)
        const upUrl = kintone.api.url('/k/v1/file', true); // /k/v1/file.json
        const formData = new FormData();
        formData.append('__REQUEST_TOKEN__', kintone.getRequestToken());
        formData.append('file', new Blob([modified], { type: 'application/pdf' }), name);

        const upRes = await fetch(upUrl, {
          method: 'POST',
          body: formData,
          headers: { 'X-Requested-With': 'XMLHttpRequest' }, // Content-Type は指定しない
          credentials: 'same-origin'
        });

        const upText = await upRes.text();
        if (!upRes.ok) {
          // CB_CS01 等のコードを表示
          try {
            const j = JSON.parse(upText);
            throw new Error(`${upRes.status} ${upRes.statusText} :: ${j.code ?? ''} ${j.message ?? upText}`);
          } catch {
            throw new Error(`Upload failed: ${upRes.status} ${upRes.statusText} :: ${upText}`);
          }
        }
        const { fileKey: newFileKey } = JSON.parse(upText);
        if (!newFileKey) throw new Error('Upload response does not contain fileKey.');

        // 4) レコードの添付置換(JSON API)
        await kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', {
          app: kintone.app.getId(),
          id: kintone.app.record.getId(),
          record: { pdf_file: { value: [{ fileKey: newFileKey }] } }
        });

        alert('PDFを更新し、添付ファイルを置換しました。画面を再読み込みします。');
        location.reload();
      } catch (e) {
        console.error('PDF編集/置換エラー:', e);
        alert(`処理に失敗しました。\n${e instanceof Error ? e.message : String(e)}`);
      } finally {
        btn.disabled = false;
      }
    });

    return event;
  });
})();
「いいね!」 2

ご回答ありがとうございます。

・差し込みタイミングは、レコードを追加ボタンで追加して、添付ファイルにアップしたあと、保存ボタンを押したら、実行したいです。

・ボタンを作成するのもAI (ジェミニ)の場合は提案されたまして、そのパターンもコードを作成してもらいましたが、動きませんでした。

https://unpkg.com/pdf-lib/dist/pdf-lib.min.jsをJavascriptファイルで先頭で登録をしております。

・F12を押して、コンソールを見ると、以下が表示されてます。

Uncaught (in promise) Error: Failed to parse PDF document (line:72 col:0 offset=1732): No PDF header found

「いいね!」 1

aaa様

ご回答ありがとうございました。

最後にページに、文字がきれてましたが、文字が挿入されました。ありがとうございます。

できれば、複数枚あるPDFのすべてのページに記載されるようにしたいのですが、そのようなコードを大変恐縮ですが、教えていただけると幸いです。

動くコードが出てるので、今更ではありますが……

コードをよく読んでたら

この部分の kintone.api() の使い方がまずかったみたいですね

「いいね!」 1

このトピックはベストアンサーに選ばれた返信から 3 日が経過したので自動的にクローズされました。新たに返信することはできません。