詳細については、pdf-lib.js.org をご覧ください。
pdf-lib
、JavaScript エコシステムに PDF 操作 (特に PDF変更) に対する強力なサポートが不足していることに対処するために作成されました。
pdf-lib
の特徴的な機能は次の 2 つです。
他にも優れたオープンソース JavaScript PDF ライブラリが利用可能です。ただし、ほとんどの場合はドキュメントの作成のみが可能で、既存のドキュメントを変更することはできません。そして、それらの多くは特定の環境でのみ動作します。
この例では、次の PDF を作成します。
JSFiddle デモを試してみる
import { PDFDocument , StandardFonts , rgb } from 'pdf-lib'
// Create a new PDFDocument
const pdfDoc = await PDFDocument . create ( )
// Embed the Times Roman font
const timesRomanFont = await pdfDoc . embedFont ( StandardFonts . TimesRoman )
// Add a blank page to the document
const page = pdfDoc . addPage ( )
// Get the width and height of the page
const { width , height } = page . getSize ( )
// Draw a string of text toward the top of the page
const fontSize = 30
page . drawText ( 'Creating PDFs in JavaScript is awesome!' , {
x : 50 ,
y : height - 4 * fontSize ,
size : fontSize ,
font : timesRomanFont ,
color : rgb ( 0 , 0.53 , 0.71 ) ,
} )
// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc . save ( )
// For example, `pdfBytes` can be:
// • Written to a file in Node
// • Downloaded from the browser
// • Rendered in an <iframe>
この例では、この PDF を生成します(この PDF がexistingPdfBytes
変数に使用される場合)。
JSFiddle デモを試してみる
import { degrees , PDFDocument , rgb , StandardFonts } from 'pdf-lib' ;
// This should be a Uint8Array or ArrayBuffer
// This data can be obtained in a number of different ways
// If your running in a Node environment, you could use fs.readFile()
// In the browser, you could make a fetch() call and use res.arrayBuffer()
const existingPdfBytes = ...
// Load a PDFDocument from the existing PDF bytes
const pdfDoc = await PDFDocument . load ( existingPdfBytes )
// Embed the Helvetica font
const helveticaFont = await pdfDoc . embedFont ( StandardFonts . Helvetica )
// Get the first page of the document
const pages = pdfDoc . getPages ( )
const firstPage = pages [ 0 ]
// Get the width and height of the first page
const { width , height } = firstPage . getSize ( )
// Draw a string of text diagonally across the first page
firstPage . drawText ( 'This text was added with JavaScript!' , {
x : 5 ,
y : height / 2 + 300 ,
size : 50 ,
font : helveticaFont ,
color : rgb ( 0.95 , 0.1 , 0.1 ) ,
rotate : degrees ( - 45 ) ,
} )
// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc . save ( )
// For example, `pdfBytes` can be:
// • Written to a file in Node
// • Downloaded from the browser
// • Rendered in an <iframe>
この例では、次の PDF を作成します。
JSFiddle デモを試してみる
フォームの作成と入力も参照してください。
import { PDFDocument } from 'pdf-lib'
// Create a new PDFDocument
const pdfDoc = await PDFDocument . create ( )
// Add a blank page to the document
const page = pdfDoc . addPage ( [ 550 , 750 ] )
// Get the form so we can add fields to it
const form = pdfDoc . getForm ( )
// Add the superhero text field and description
page . drawText ( 'Enter your favorite superhero:' , { x : 50 , y : 700 , size : 20 } )
const superheroField = form . createTextField ( 'favorite.superhero' )
superheroField . setText ( 'One Punch Man' )
superheroField . addToPage ( page , { x : 55 , y : 640 } )
// Add the rocket radio group, labels, and description
page . drawText ( 'Select your favorite rocket:' , { x : 50 , y : 600 , size : 20 } )
page . drawText ( 'Falcon Heavy' , { x : 120 , y : 560 , size : 18 } )
page . drawText ( 'Saturn IV' , { x : 120 , y : 500 , size : 18 } )
page . drawText ( 'Delta IV Heavy' , { x : 340 , y : 560 , size : 18 } )
page . drawText ( 'Space Launch System' , { x : 340 , y : 500 , size : 18 } )
const rocketField = form . createRadioGroup ( 'favorite.rocket' )
rocketField . addOptionToPage ( 'Falcon Heavy' , page , { x : 55 , y : 540 } )
rocketField . addOptionToPage ( 'Saturn IV' , page , { x : 55 , y : 480 } )
rocketField . addOptionToPage ( 'Delta IV Heavy' , page , { x : 275 , y : 540 } )
rocketField . addOptionToPage ( 'Space Launch System' , page , { x : 275 , y : 480 } )
rocketField . select ( 'Saturn IV' )
// Add the gundam check boxes, labels, and description
page . drawText ( 'Select your favorite gundams:' , { x : 50 , y : 440 , size : 20 } )
page . drawText ( 'Exia' , { x : 120 , y : 400 , size : 18 } )
page . drawText ( 'Kyrios' , { x : 120 , y : 340 , size : 18 } )
page . drawText ( 'Virtue' , { x : 340 , y : 400 , size : 18 } )
page . drawText ( 'Dynames' , { x : 340 , y : 340 , size : 18 } )
const exiaField = form . createCheckBox ( 'gundam.exia' )
const kyriosField = form . createCheckBox ( 'gundam.kyrios' )
const virtueField = form . createCheckBox ( 'gundam.virtue' )
const dynamesField = form . createCheckBox ( 'gundam.dynames' )
exiaField . addToPage ( page , { x : 55 , y : 380 } )
kyriosField . addToPage ( page , { x : 55 , y : 320 } )
virtueField . addToPage ( page , { x : 275 , y : 380 } )
dynamesField . addToPage ( page , { x : 275 , y : 320 } )
exiaField . check ( )
dynamesField . check ( )
// Add the planet dropdown and description
page . drawText ( 'Select your favorite planet*:' , { x : 50 , y : 280 , size : 20 } )
const planetsField = form . createDropdown ( 'favorite.planet' )
planetsField . addOptions ( [ 'Venus' , 'Earth' , 'Mars' , 'Pluto' ] )
planetsField . select ( 'Pluto' )
planetsField . addToPage ( page , { x : 55 , y : 220 } )
// Add the person option list and description
page . drawText ( 'Select your favorite person:' , { x : 50 , y : 180 , size : 18 } )
const personField = form . createOptionList ( 'favorite.person' )
personField . addOptions ( [
'Julius Caesar' ,
'Ada Lovelace' ,
'Cleopatra' ,
'Aaron Burr' ,
'Mark Antony' ,
] )
personField . select ( 'Ada Lovelace' )
personField . addToPage ( page , { x : 55 , y : 70 } )
// Just saying...
page . drawText ( `* Pluto should be a planet too!` , { x : 15 , y : 15 , size : 15 } )
// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc . save ( )
// For example, `pdfBytes` can be:
// • Written to a file in Node
// • Downloaded from the browser
// • Rendered in an <iframe>
この例では、この PDF を生成します(この PDF がformPdfBytes
変数に使用される場合、この画像はmarioImageBytes
変数に使用され、この画像はemblemImageBytes
変数に使用されます)。
JSFiddle デモを試してみる
フォームの作成と入力も参照してください。
import { PDFDocument } from 'pdf-lib'
// These should be Uint8Arrays or ArrayBuffers
// This data can be obtained in a number of different ways
// If your running in a Node environment, you could use fs.readFile()
// In the browser, you could make a fetch() call and use res.arrayBuffer()
const formPdfBytes = ...
const marioImageBytes = ...
const emblemImageBytes = ...
// Load a PDF with form fields
const pdfDoc = await PDFDocument . load ( formPdfBytes )
// Embed the Mario and emblem images
const marioImage = await pdfDoc . embedPng ( marioImageBytes )
const emblemImage = await pdfDoc . embedPng ( emblemImageBytes )
// Get the form containing all the fields
const form = pdfDoc . getForm ( )
// Get all fields in the PDF by their names
const nameField = form . getTextField ( 'CharacterName 2' )
const ageField = form . getTextField ( 'Age' )
const heightField = form . getTextField ( 'Height' )
const weightField = form . getTextField ( 'Weight' )
const eyesField = form . getTextField ( 'Eyes' )
const skinField = form . getTextField ( 'Skin' )
const hairField = form . getTextField ( 'Hair' )
const alliesField = form . getTextField ( 'Allies' )
const factionField = form . getTextField ( 'FactionName' )
const backstoryField = form . getTextField ( 'Backstory' )
const traitsField = form . getTextField ( 'Feat+Traits' )
const treasureField = form . getTextField ( 'Treasure' )
const characterImageField = form . getButton ( 'CHARACTER IMAGE' )
const factionImageField = form . getTextField ( 'Faction Symbol Image' )
// Fill in the basic info fields
nameField . setText ( 'Mario' )
ageField . setText ( '24 years' )
heightField . setText ( `5' 1"` )
weightField . setText ( '196 lbs' )
eyesField . setText ( 'blue' )
skinField . setText ( 'white' )
hairField . setText ( 'brown' )
// Fill the character image field with our Mario image
characterImageField . setImage ( marioImage )
// Fill in the allies field
alliesField . setText (
[
`Allies:` ,
` • Princess Daisy` ,
` • Princess Peach` ,
` • Rosalina` ,
` • Geno` ,
` • Luigi` ,
` • Donkey Kong` ,
` • Yoshi` ,
` • Diddy Kong` ,
`` ,
`Organizations:` ,
` • Italian Plumbers Association` ,
] . join ( 'n' ) ,
)
// Fill in the faction name field
factionField . setText ( `Mario's Emblem` )
// Fill the faction image field with our emblem image
factionImageField . setImage ( emblemImage )
// Fill in the backstory field
backstoryField . setText (
`Mario is a fictional character in the Mario video game franchise, owned by Nintendo and created by Japanese video game designer Shigeru Miyamoto. Serving as the company's mascot and the eponymous protagonist of the series, Mario has appeared in over 200 video games since his creation. Depicted as a short, pudgy, Italian plumber who resides in the Mushroom Kingdom, his adventures generally center upon rescuing Princess Peach from the Koopa villain Bowser. His younger brother and sidekick is Luigi.` ,
)
// Fill in the traits field
traitsField . setText (
[
`Mario can use three basic three power-ups:` ,
` • the Super Mushroom, which causes Mario to grow larger` ,
` • the Fire Flower, which allows Mario to throw fireballs` ,
` • the Starman, which gives Mario temporary invincibility` ,
] . join ( 'n' ) ,
)
// Fill in the treasure field
treasureField . setText ( [ '• Gold coins' , '• Treasure chests' ] . join ( 'n' ) )
// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc . save ( )
// For example, `pdfBytes` can be:
// • Written to a file in Node
// • Downloaded from the browser
// • Rendered in an <iframe>
この例では、この PDF を生成します(この PDF がformPdfBytes
変数に使用される場合)。
JSFiddle デモを試してみる
import { PDFDocument } from 'pdf-lib'
// This should be a Uint8Array or ArrayBuffer
// This data can be obtained in a number of different ways
// If your running in a Node environment, you could use fs.readFile()
// In the browser, you could make a fetch() call and use res.arrayBuffer()
const formPdfBytes = ...
// Load a PDF with form fields
const pdfDoc = await PDFDocument . load ( formPdfBytes )
// Get the form containing all the fields
const form = pdfDoc . getForm ( )
// Fill the form's fields
form . getTextField ( 'Text1' ) . setText ( 'Some Text' ) ;
form . getRadioGroup ( 'Group2' ) . select ( 'Choice1' ) ;
form . getRadioGroup ( 'Group3' ) . select ( 'Choice3' ) ;
form . getRadioGroup ( 'Group4' ) . select ( 'Choice1' ) ;
form . getCheckBox ( 'Check Box3' ) . check ( ) ;
form . getCheckBox ( 'Check Box4' ) . uncheck ( ) ;
form . getDropdown ( 'Dropdown7' ) . select ( 'Infinity' ) ;
form . getOptionList ( 'List Box6' ) . select ( 'Honda' ) ;
// Flatten the form's fields
form . flatten ( ) ;
// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc . save ( )
// For example, `pdfBytes` can be:
// • Written to a file in Node
// • Downloaded from the browser
// • Rendered in an <iframe>
この例では、この PDF を生成します(この PDF がfirstDonorPdfBytes
変数に使用され、この PDF がsecondDonorPdfBytes
変数に使用される場合)。
JSFiddle デモを試してみる
import { PDFDocument } from 'pdf-lib'
// Create a new PDFDocument
const pdfDoc = await PDFDocument . create ( )
// These should be Uint8Arrays or ArrayBuffers
// This data can be obtained in a number of different ways
// If your running in a Node environment, you could use fs.readFile()
// In the browser, you could make a fetch() call and use res.arrayBuffer()
const firstDonorPdfBytes = ...
const secondDonorPdfBytes = ...
// Load a PDFDocument from each of the existing PDFs
const firstDonorPdfDoc = await PDFDocument . load ( firstDonorPdfBytes )
const secondDonorPdfDoc = await PDFDocument . load ( secondDonorPdfBytes )
// Copy the 1st page from the first donor document, and
// the 743rd page from the second donor document
const [ firstDonorPage ] = await pdfDoc . copyPages ( firstDonorPdfDoc , [ 0 ] )
const [ secondDonorPage ] = await pdfDoc . copyPages ( secondDonorPdfDoc , [ 742 ] )
// Add the first copied page
pdfDoc . addPage ( firstDonorPage )
// Insert the second copied page to index 0, so it will be the
// first page in `pdfDoc`
pdfDoc . insertPage ( 0 , secondDonorPage )
// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc . save ( )
// For example, `pdfBytes` can be:
// • Written to a file in Node
// • Downloaded from the browser
// • Rendered in an <iframe>
この例では、この PDF を生成します(この画像がjpgImageBytes
変数に使用され、この画像がpngImageBytes
変数に使用される場合)。
JSFiddle デモを試してみる
import { PDFDocument } from 'pdf-lib'
// These should be Uint8Arrays or ArrayBuffers
// This data can be obtained in a number of different ways
// If your running in a Node environment, you could use fs.readFile()
// In the browser, you could make a fetch() call and use res.arrayBuffer()
const jpgImageBytes = ...
const pngImageBytes = ...
// Create a new PDFDocument
const pdfDoc = await PDFDocument . create ( )
// Embed the JPG image bytes and PNG image bytes
const jpgImage = await pdfDoc . embedJpg ( jpgImageBytes )
const pngImage = await pdfDoc . embedPng ( pngImageBytes )
// Get the width/height of the JPG image scaled down to 25% of its original size
const jpgDims = jpgImage . scale ( 0.25 )
// Get the width/height of the PNG image scaled down to 50% of its original size
const pngDims = pngImage . scale ( 0.5 )
// Add a blank page to the document
const page = pdfDoc . addPage ( )
// Draw the JPG image in the center of the page
page . drawImage ( jpgImage , {
x : page . getWidth ( ) / 2 - jpgDims . width / 2 ,
y : page . getHeight ( ) / 2 - jpgDims . height / 2 ,
width : jpgDims . width ,
height : jpgDims . height ,
} )
// Draw the PNG image near the lower right corner of the JPG image
page . drawImage ( pngImage , {
x : page . getWidth ( ) / 2 - pngDims . width / 2 + 75 ,
y : page . getHeight ( ) / 2 - pngDims . height ,
width : pngDims . width ,
height : pngDims . height ,
} )
// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc . save ( )
// For example, `pdfBytes` can be:
// • Written to a file in Node
// • Downloaded from the browser
// • Rendered in an <iframe>
この例では、この PDF を生成します(この PDF がamericanFlagPdfBytes
変数に使用され、この PDF がusConstitutionPdfBytes
変数に使用される場合)。
JSFiddle デモを試してみる
import { PDFDocument } from 'pdf-lib'
// These should be Uint8Arrays or ArrayBuffers
// This data can be obtained in a number of different ways
// If your running in a Node environment, you could use fs.readFile()
// In the browser, you could make a fetch() call and use res.arrayBuffer()
const americanFlagPdfBytes = ...
const usConstitutionPdfBytes = ...
// Create a new PDFDocument
const pdfDoc = await PDFDocument . create ( )
// Embed the American flag PDF bytes
const [ americanFlag ] = await pdfDoc . embedPdf ( americanFlagPdfBytes )
// Load the U.S. constitution PDF bytes
const usConstitutionPdf = await PDFDocument . load ( usConstitutionPdfBytes )
// Embed the second page of the constitution and clip the preamble
const preamble = await pdfDoc . embedPage ( usConstitutionPdf . getPages ( ) [ 1 ] , {
left : 55 ,
bottom : 485 ,
right : 300 ,
top : 575 ,
} )
// Get the width/height of the American flag PDF scaled down to 30% of
// its original size
const americanFlagDims = americanFlag . scale ( 0.3 )
// Get the width/height of the preamble clipping scaled up to 225% of
// its original size
const preambleDims = preamble . scale ( 2.25 )
// Add a blank page to the document
const page = pdfDoc . addPage ( )
// Draw the American flag image in the center top of the page
page . drawPage ( americanFlag , {
... americanFlagDims ,
x : page . getWidth ( ) / 2 - americanFlagDims . width / 2 ,
y : page . getHeight ( ) - americanFlagDims . height - 150 ,
} )
// Draw the preamble clipping in the center bottom of the page
page . drawPage ( preamble , {
... preambleDims ,
x : page . getWidth ( ) / 2 - preambleDims . width / 2 ,
y : page . getHeight ( ) / 2 - preambleDims . height / 2 - 50 ,
} )
// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc . save ( )
// For example, `pdfBytes` can be:
// • Written to a file in Node
// • Downloaded from the browser
// • Rendered in an <iframe>
pdf-lib
カスタム フォントの埋め込みをサポートする姉妹モジュール@pdf-lib/fontkit
に依存しています。カスタム フォントを埋め込む前に、 @pdf-lib/fontkit
モジュールをプロジェクトに追加し、 pdfDoc.registerFontkit(...)
を使用して登録する必要があります。
@pdf-lib/fontkit
UMD または NPM モジュールとしてインストールする場合の詳細なインストール手順については、以下を参照してください。
この例では、この PDF が生成されます(このフォントがfontBytes
変数に使用されている場合)。
JSFiddle デモを試してみる
import { PDFDocument , rgb } from 'pdf-lib'
import fontkit from '@pdf-lib/fontkit'
// This should be a Uint8Array or ArrayBuffer
// This data can be obtained in a number of different ways
// If you're running in a Node environment, you could use fs.readFile()
// In the browser, you could make a fetch() call and use res.arrayBuffer()
const fontBytes = ...
// Create a new PDFDocument
const pdfDoc = await PDFDocument . create ( )
// Register the `fontkit` instance
pdfDoc . registerFontkit ( fontkit )
// Embed our custom font in the document
const customFont = await pdfDoc . embedFont ( fontBytes )
// Add a blank page to the document
const page = pdfDoc . addPage ( )
// Create a string of text and measure its width and height in our custom font
const text = 'This is text in an embedded font!'
const textSize = 35
const textWidth = customFont . widthOfTextAtSize ( text , textSize )
const textHeight = customFont . heightAtSize ( textSize )
// Draw the string of text on the page
page . drawText ( text , {
x : 40 ,
y : 450 ,
size : textSize ,
font : customFont ,
color : rgb ( 0 , 0.53 , 0.71 ) ,
} )
// Draw a box around the string of text
page . drawRectangle ( {
x : 40 ,
y : 450 ,
width : textWidth ,
height : textHeight ,
borderColor : rgb ( 1 , 0 , 0 ) ,
borderWidth : 1.5 ,
} )
// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc . save ( )
// For example, `pdfBytes` can be:
// • Written to a file in Node
// • Downloaded from the browser
// • Rendered in an <iframe>
この例では、この PDF を生成します(この画像がjpgAttachmentBytes
変数に使用され、この PDF がpdfAttachmentBytes
変数に使用される場合)。
JSFiddle デモを試してみる
import { PDFDocument } from 'pdf-lib'
// These should be Uint8Arrays or ArrayBuffers
// This data can be obtained in a number of different ways
// If your running in a Node environment, you could use fs.readFile()
// In the browser, you could make a fetch() call and use res.arrayBuffer()
const jpgAttachmentBytes = ...
const pdfAttachmentBytes = ...
// Create a new PDFDocument
const pdfDoc = await PDFDocument . create ( )
// Add the JPG attachment
await pdfDoc . attach ( jpgAttachmentBytes , 'cat_riding_unicorn.jpg' , {
mimeType : 'image/jpeg' ,
description : 'Cool cat riding a unicorn! ???️' ,
creationDate : new Date ( '2019/12/01' ) ,
modificationDate : new Date ( '2020/04/19' ) ,
} )
// Add the PDF attachment
await pdfDoc . attach ( pdfAttachmentBytes , 'us_constitution.pdf' , {
mimeType : 'application/pdf' ,
description : 'Constitution of the United States ???' ,
creationDate : new Date ( '1787/09/17' ) ,
modificationDate : new Date ( '1992/05/07' ) ,
} )
// Add a page with some text
const page = pdfDoc . addPage ( ) ;
page . drawText ( 'This PDF has two attachments' , { x : 135 , y : 415 } )
// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc . save ( )
// For example, `pdfBytes` can be:
// • Written to a file in Node
// • Downloaded from the browser
// • Rendered in an <iframe>
この例では、次の PDF を生成します。
JSFiddle デモを試してみる
import { PDFDocument , StandardFonts } from 'pdf-lib'
// Create a new PDFDocument
const pdfDoc = await PDFDocument . create ( )
// Embed the Times Roman font
const timesRomanFont = await pdfDoc . embedFont ( StandardFonts . TimesRoman )
// Add a page and draw some text on it
const page = pdfDoc . addPage ( [ 500 , 600 ] )
page . setFont ( timesRomanFont )
page . drawText ( 'The Life of an Egg' , { x : 60 , y : 500 , size : 50 } )
page . drawText ( 'An Epic Tale of Woe' , { x : 125 , y : 460 , size : 25 } )
// Set all available metadata fields on the PDFDocument. Note that these fields
// are visible in the "Document Properties" section of most PDF readers.
pdfDoc . setTitle ( '? The Life of an Egg ?' )
pdfDoc . setAuthor ( 'Humpty Dumpty' )
pdfDoc . setSubject ( ' An Epic Tale of Woe ' )
pdfDoc . setKeywords ( [ 'eggs' , 'wall' , 'fall' , 'king' , 'horses' , 'men' ] )
pdfDoc . setProducer ( 'PDF App 9000 ?' )
pdfDoc . setCreator ( 'pdf-lib (https://github.com/Hopding/pdf-lib)' )
pdfDoc . setCreationDate ( new Date ( '2018-06-24T01:58:37.228Z' ) )
pdfDoc . setModificationDate ( new Date ( '2019-12-21T07:00:11.000Z' ) )
// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc . save ( )
// For example, `pdfBytes` can be:
// • Written to a file in Node
// • Downloaded from the browser
// • Rendered in an <iframe>
JSFiddle デモを試してみる
import { PDFDocument } from 'pdf-lib'
// This should be a Uint8Array or ArrayBuffer
// This data can be obtained in a number of different ways
// If your running in a Node environment, you could use fs.readFile()
// In the browser, you could make a fetch() call and use res.arrayBuffer()
const existingPdfBytes = ...
// Load a PDFDocument without updating its existing metadata
const pdfDoc = await PDFDocument . load ( existingPdfBytes , {
updateMetadata : false
} )
// Print all available metadata fields
console . log ( 'Title:' , pdfDoc . getTitle ( ) )
console . log ( 'Author:' , pdfDoc . getAuthor ( ) )
console . log ( 'Subject:' , pdfDoc . getSubject ( ) )
console . log ( 'Creator:' , pdfDoc . getCreator ( ) )
console . log ( 'Keywords:' , pdfDoc . getKeywords ( ) )
console . log ( 'Producer:' , pdfDoc . getProducer ( ) )
console . log ( 'Creation Date:' , pdfDoc . getCreationDate ( ) )
console . log ( 'Modification Date:' , pdfDoc . getModificationDate ( ) )
このスクリプトは次を出力します (この PDF がexistingPdfBytes
変数に使用されている場合)。
Title: Microsoft Word - Basic Curriculum Vitae example.doc
Author: Administrator
Subject: undefined
Creator: PScript5.dll Version 5.2
Keywords: undefined
Producer: Acrobat Distiller 8.1.0 (Windows)
Creation Date: 2010-07-29T14:26:00.000Z
Modification Date: 2010-07-29T14:26:00.000Z
import {
PDFDocument ,
StandardFonts ,
NonFullScreenPageMode ,
ReadingDirection ,
PrintScaling ,
Duplex ,
PDFName ,
} from 'pdf-lib'
// Create a new PDFDocument
const pdfDoc = await PDFDocument . create ( )
// Embed the Times Roman font
const timesRomanFont = await pdfDoc . embedFont ( StandardFonts . TimesRoman )
// Add a page and draw some text on it
const page = pdfDoc . addPage ( [ 500 , 600 ] )
page . setFont ( timesRomanFont )
page . drawText ( 'The Life of an Egg' , { x : 60 , y : 500 , size : 50 } )
page . drawText ( 'An Epic Tale of Woe' , { x : 125 , y : 460 , size : 25 } )
// Set all available viewer preferences on the PDFDocument:
const viewerPrefs = pdfDoc . catalog . getOrCreateViewerPreferences ( )
viewerPrefs . setHideToolbar ( true )
viewerPrefs . setHideMenubar ( true )
viewerPrefs . setHideWindowUI ( true )
viewerPrefs . setFitWindow ( true )
viewerPrefs . setCenterWindow ( true )
viewerPrefs . setDisplayDocTitle ( true )
// Set the PageMode (otherwise setting NonFullScreenPageMode has no meaning)
pdfDoc . catalog . set ( PDFName . of ( 'PageMode' ) , PDFName . of ( 'FullScreen' ) )
// Set what happens when fullScreen is closed
viewerPrefs . setNonFullScreenPageMode ( NonFullScreenPageMode . UseOutlines )
viewerPrefs . setReadingDirection ( ReadingDirection . L2R )
viewerPrefs . setPrintScaling ( PrintScaling . None )
viewerPrefs . setDuplex ( Duplex . DuplexFlipLongEdge )
viewerPrefs . setPickTrayByPDFSize ( true )
// We can set the default print range to only the first page
viewerPrefs . setPrintPageRange ( { start : 0 , end : 0 } )
// Or we can supply noncontiguous ranges (e.g. pages 1, 3, and 5-7)
viewerPrefs . setPrintPageRange ( [
{ start : 0 , end : 0 } ,
{ start : 2 , end : 2 } ,
{ start : 4 , end : 6 } ,
] )
viewerPrefs . setNumCopies ( 2 )
// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc . save ( )
// For example, `pdfBytes` can be:
// • Written to a file in Node
// • Downloaded from the browser
// • Rendered in an <iframe>
import { PDFDocument } from 'pdf-lib'
// This should be a Uint8Array or ArrayBuffer
// This data can be obtained in a number of different ways
// If your running in a Node environment, you could use fs.readFile()
// In the browser, you could make a fetch() call and use res.arrayBuffer()
const existingPdfBytes = ...
// Load a PDFDocument without updating its existing metadata
const pdfDoc = await PDFDocument . load ( existingPdfBytes )
const viewerPrefs = pdfDoc . catalog . getOrCreateViewerPreferences ( )
// Print all available viewer preference fields
console . log ( 'HideToolbar:' , viewerPrefs . getHideToolbar ( ) )
console . log ( 'HideMenubar:' , viewerPrefs . getHideMenubar ( ) )
console . log ( 'HideWindowUI:' , viewerPrefs . getHideWindowUI ( ) )
console . log ( 'FitWindow:' , viewerPrefs . getFitWindow ( ) )
console . log ( 'CenterWindow:' , viewerPrefs . getCenterWindow ( ) )
console . log ( 'DisplayDocTitle:' , viewerPrefs . getDisplayDocTitle ( ) )
console . log ( 'NonFullScreenPageMode:' , viewerPrefs . getNonFullScreenPageMode ( ) )
console . log ( 'ReadingDirection:' , viewerPrefs . getReadingDirection ( ) )
console . log ( 'PrintScaling:' , viewerPrefs . getPrintScaling ( ) )
console . log ( 'Duplex:' , viewerPrefs . getDuplex ( ) )
console . log ( 'PickTrayByPDFSize:' , viewerPrefs . getPickTrayByPDFSize ( ) )
console . log ( 'PrintPageRange:' , viewerPrefs . getPrintPageRange ( ) )
console . log ( 'NumCopies:' , viewerPrefs . getNumCopies ( ) )
このスクリプトは次を出力します (この PDF がexistingPdfBytes
変数に使用されている場合)。
HideToolbar: true
HideMenubar: true
HideWindowUI: false
FitWindow: true
CenterWindow: true
DisplayDocTitle: true
NonFullScreenPageMode: UseNone
ReadingDirection: R2L
PrintScaling: None
Duplex: DuplexFlipLongEdge
PickTrayByPDFSize: true
PrintPageRange: [ { start: 1, end: 1 }, { start: 3, end: 4 } ]
NumCopies: 2
この例では、次の PDF を生成します。
JSFiddle デモを試してみる
import { PDFDocument , rgb } from 'pdf-lib'
// SVG path for a wavy line
const svgPath =
'M 0,20 L 100,160 Q 130,200 150,120 C 190,-40 200,200 300,150 L 400,90'
// Create a new PDFDocument
const pdfDoc = await PDFDocument . create ( )
// Add a blank page to the document
const page = pdfDoc . addPage ( )
page . moveTo ( 100 , page . getHeight ( ) - 5 )
// Draw the SVG path as a black line
page . moveDown ( 25 )
page . drawSvgPath ( svgPath )
// Draw the SVG path as a thick green line
page . moveDown ( 200 )
page . drawSvgPath ( svgPath , { borderColor : rgb ( 0 , 1 , 0 ) , borderWidth : 5 } )
// Draw the SVG path and fill it with red
page . moveDown ( 200 )
page . drawSvgPath ( svgPath , { color : rgb ( 1 , 0 , 0 ) } )
// Draw the SVG path at 50% of its original size
page . moveDown ( 200 )
page . drawSvgPath ( svgPath , { scale : 0.5 } )
// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc . save ( )
// For example, `pdfBytes` can be:
// • Written to a file in Node
// • Downloaded from the browser
// • Rendered in an <iframe>
pdf-lib
エキサイティングな新しい Deno ランタイムを完全にサポートしています。すべての使用例は Deno で動作します。 Deno ではすべてのモジュールが URL 経由で参照される必要があるため、Skypack CDN を使用するようにpdf-lib
と@pdf-lib/fontkit
のインポートを変更する必要があるだけです。
pdf-lib を使用して Deno で PDF ファイルを作成および変更する方法も参照してください。
以下は、Deno 用に変更されたドキュメント作成の例です。
import {
PDFDocument ,
StandardFonts ,
rgb ,
} from 'https://cdn.skypack.dev/pdf-lib@^1.11.1?dts' ;
const pdfDoc = await PDFDocument . create ( ) ;
const timesRomanFont = await pdfDoc . embedFont ( StandardFonts . TimesRoman ) ;
const page = pdfDoc . addPage ( ) ;
const { width , height } = page . getSize ( ) ;
const fontSize = 30 ;
page . drawText ( 'Creating PDFs in JavaScript is awesome!' , {
x : 50 ,
y : height - 4 * fontSize ,
size : fontSize ,
font : timesRomanFont ,
color : rgb ( 0 , 0.53 , 0.71 ) ,
} ) ;
const pdfBytes = await pdfDoc . save ( ) ;
await Deno . writeFile ( 'out.pdf' , pdfBytes ) ;
このスクリプトをcreate-document.ts
として保存すると、Deno を使用して次のコマンドを実行できます。
deno run --allow-write create-document.ts
結果のout.pdf
ファイルは次の PDF のようになります。
以下は、Deno にフォントを埋め込んでテキストを測定する方法を示す、少し複雑な例です。
import {
degrees ,
PDFDocument ,
rgb ,
StandardFonts ,
} from 'https://cdn.skypack.dev/pdf-lib@^1.11.1?dts' ;
import fontkit from 'https://cdn.skypack.dev/@pdf-lib/fontkit@^1.0.0?dts' ;
const url = 'https://pdf-lib.js.org/assets/ubuntu/Ubuntu-R.ttf' ;
const fontBytes = await fetch ( url ) . then ( ( res ) => res . arrayBuffer ( ) ) ;
const pdfDoc = await PDFDocument . create ( ) ;
pdfDoc . registerFontkit ( fontkit ) ;
const customFont = await pdfDoc . embedFont ( fontBytes ) ;
const page = pdfDoc . addPage ( ) ;
const text = 'This is text in an embedded font!' ;
const textSize = 35 ;
const textWidth = customFont . widthOfTextAtSize ( text , textSize ) ;
const textHeight = customFont . heightAtSize ( textSize ) ;
page . drawText ( text , {
x : 40 ,
y : 450 ,
size : textSize ,
font : customFont ,
color : rgb ( 0 , 0.53 , 0.71 ) ,
} ) ;
page . drawRectangle ( {
x : 40 ,
y : 450 ,
width : textWidth ,
height : textHeight ,
borderColor : rgb ( 1 , 0 , 0 ) ,
borderWidth : 1.5 ,
} ) ;
const pdfBytes = await pdfDoc . save ( ) ;
await Deno . writeFile ( 'out.pdf' , pdfBytes ) ;
このスクリプトをcustom-font.ts
として保存すると、次のコマンドで実行できます。
deno run --allow-write --allow-net custom-font.ts
結果のout.pdf
ファイルは次の PDF のようになります。
使用例では、 pdf-lib
のさまざまな機能を示す、簡潔かつ要点を絞ったコードが提供されています。完全な動作例はapps/
ディレクトリにあります。これらのアプリは、(自動テストに加えて) 各リリース前にpdf-lib
の手動テストを行うために使用されます。
現在、次の 4 つのアプリがあります。
node
- ノード環境でのpdf-lib
のテストが含まれています。これらのテストは、ファイルシステムからpdf-lib
を使用して PDF、フォント、または画像を保存/ロードしようとするときに便利なリファレンスです。また、互換性を確保するために、PDF をさまざまなビューア (Acrobat、Preview、Foxit、Chrome、Firefox など) ですばやく開くこともできます。web
- ブラウザ環境でのpdf-lib
のテストが含まれています。これらのテストは、ブラウザ環境でpdf-lib
を使用して PDF、フォント、または画像を保存/ロードしようとするときに便利なリファレンスです。rn
- React Native 環境でのpdf-lib
のテストが含まれています。これらのテストは、React Native 環境でpdf-lib
を使用して PDF、フォント、または画像を保存/ロードしようとするときに便利なリファレンスです。deno
- Deno 環境でのpdf-lib
のテストが含まれています。これらのテストは、ファイルシステムからpdf-lib
を使用して PDF、フォント、または画像を保存/ロードしようとするときに便利なリファレンスです。 最新の安定バージョンをインストールするには:
# With npm
npm install --save pdf-lib
# With yarn
yarn add pdf-lib
これは、パッケージ マネージャーとして npm または Yarn を使用していることを前提としています。
unpkg または jsDelivr からpdf-lib
UMD モジュールとしてダウンロードすることもできます。 UMD ビルドは ES5 にコンパイルされているため、最新のブラウザーで動作するはずです。 UMD ビルドは、パッケージ マネージャーやモジュール バンドラーを使用していない場合に便利です。たとえば、HTML ページの<script>
タグ内で直接使用できます。
次のビルドが利用可能です。
注:運用環境で CDN スクリプトを使用している場合は、URL に特定のバージョン番号を含める必要があります。次に例を示します。
- https://unpkg.com/[email protected]/dist/pdf-lib.min.js
- https://cdn.jsdelivr.net/npm/[email protected]/dist/pdf-lib.min.js
UMD ビルドを使用する場合、グローバルwindow.PDFLib
変数にアクセスできます。この変数には、 pdf-lib
によってエクスポートされたすべてのクラスと関数が含まれています。例えば:
// NPM module
import { PDFDocument , rgb } from 'pdf-lib' ;
// UMD module
var PDFDocument = PDFLib . PDFDocument ;
var rgb = PDFLib . rgb ;
pdf-lib
カスタム フォントの埋め込みをサポートする姉妹モジュール@pdf-lib/fontkit
に依存しています。カスタム フォントを埋め込む前に、 @pdf-lib/fontkit
モジュールをプロジェクトに追加し、 pdfDoc.registerFontkit(...)
を使用して登録する必要があります (フォントの埋め込み例を参照)。このモジュールは、すべてのユーザーが必要とするわけではなく、バンドル サイズが増加するため、デフォルトでは含まれていません。
このモジュールのインストールは簡単です。 pdf-lib
自体と同様に、 @pdf-lib/fontkit
npm
/ yarn
を使用して、または UMD モジュールとしてインストールできます。
# With npm
npm install --save @pdf-lib/fontkit
# With yarn
yarn add @pdf-lib/fontkit
fontkit
インスタンスを登録するには:
import { PDFDocument } from 'pdf-lib'
import fontkit from '@pdf-lib/fontkit'
const pdfDoc = await PDFDocument . create ( )
pdfDoc . registerFontkit ( fontkit )
次のビルドが利用可能です。
注:運用環境で CDN スクリプトを使用している場合は、URL に特定のバージョン番号を含める必要があります。次に例を示します。
- https://unpkg.com/@pdf-lib/[email protected]/dist/fontkit.umd.min.js
- https://cdn.jsdelivr.net/npm/@pdf-lib/[email protected]/dist/fontkit.umd.min.js
UMD ビルドを使用する場合、グローバルwindow.fontkit
変数にアクセスできます。 fontkit
インスタンスを登録するには:
var pdfDoc = await PDFLib . PDFDocument . create ( )
pdfDoc . registerFontkit ( fontkit )
API ドキュメントは、プロジェクト サイト (https://pdf-lib.js.org/docs/api/) で入手できます。
プロジェクト サイト (および生成されたドキュメント ファイル) のリポジトリは、https://github.com/Hopding/pdf-lib-docs にあります。
PDF を扱うとき、「文字エンコーディング」と「フォント」という用語に頻繁に遭遇します。 Web 開発の経験がある方は、なぜこれらがこれほど普及しているのか不思議に思うかもしれません。気にする必要のない、煩わしい詳細だけではありませんか? Web ブラウザと同じように、PDF ライブラリとリーダーがこれらすべてを処理できるようにすべきではないでしょうか?残念ながらそうではありません。 PDF ファイル形式の性質上、PDF を操作する際に文字エンコーディングとフォントについて考えないようにすることは非常に困難です。
pdf-lib
作業を簡素化するために最善を尽くします。ただし魔法は発動できない。これは、次のことに注意する必要があることを意味します。
import { PDFDocument , StandardFonts } from 'pdf-lib'
const pdfDoc = await PDFDocument . create ( )
const courierFont = await pdfDoc . embedFont ( StandardFonts . Courier )
const page = pdfDoc . addPage ( )
page . drawText ( 'Some boring latin text in the Courier font' , {
font : courierFont ,
} )
embedFont
メソッドに渡す必要があります。独自のフォントを埋め込む場合、そのフォントがサポートする任意の Unicode 文字を使用できます。この機能により、標準フォントによる制限から解放されます。ほとんどの PDF ファイルは埋め込みフォントを使用します。次のようにカスタム フォントを埋め込んで使用できます (こちらも参照)。 import { PDFDocument } from 'pdf-lib'
import fontkit from '@pdf-lib/fontkit'
const url = 'https://pdf-lib.js.org/assets/ubuntu/Ubuntu-R.ttf'
const fontBytes = await fetch ( url ) . then ( ( res ) => res . arrayBuffer ( ) )
const pdfDoc = await PDFDocument . create ( )
pdfDoc . registerFontkit ( fontkit )
const ubuntuFont = await pdfDoc . embedFont ( fontBytes )
const page = pdfDoc . addPage ( )
page . drawText ( 'Some fancy Unicode text in the ŪЬȕǹƚü font' , {
font : ubuntuFont ,
} )
サポートされていないフォントの文字を使用しようとすると、エンコード エラーがスローされることに注意してください。たとえば、 Ω
WinAnsi 文字セットに含まれていません。したがって、標準の Helvetica フォントを使用してページ上に描画しようとすると、次のエラーがスローされます。
Error: WinAnsi cannot encode "Ω" (0x03a9)
at Encoding.encodeUnicodeCodePoint
PDF ドキュメントにフォントを埋め込むと、通常、ファイルのサイズが増加します。必要な文字のみが埋め込まれるようにフォントをサブセット化することで、ファイル サイズの増加量を減らすことができます。 subset
オプションをtrue
に設定すると、フォントをサブセット化できます。例えば:
const font = await pdfDoc . embedFont ( fontBytes , { subset : true } ) ;
サブセット化はすべてのフォントで機能するわけではないことに注意してください。詳細については、#207 (コメント) を参照してください。
pdf-lib
PDF フォームフィールドを作成、入力、および読み取ることができます。次のフィールド タイプがサポートされています。
コードサンプルについては、フォームの作成とフォーム入力の使用例を参照してください。完全な例のテスト 1、14、15、16、および 17 には、フォームの作成およびさまざまな異なる JS 環境への入力のための実際のコード例が含まれています。
重要:ボタン、ドロップダウン、オプション リスト、およびテキスト フィールドにテキストを表示するために使用されるデフォルトのフォントは、標準の Helvetica フォントです。このフォントは、ラテンアルファベットの文字のみをサポートします (詳細については、「フォントと Unicode」を参照してください)。つまり、これらのフィールド タイプのいずれかがラテン文字以外のテキストを含むように作成または変更された場合 (よくあることですが)、フィールドの外観を更新するにはカスタム フォントを埋め込んで使用する必要があります。そうしないと、エラーがスローされます (おそらくPDFDocument
保存するとき)。
次のように、フォームフィールドに入力するときに埋め込みフォントを使用できます。
import { PDFDocument } from 'pdf-lib' ;
import fontkit from '@pdf-lib/fontkit' ;
// Fetch the PDF with form fields
const formUrl = 'https://pdf-lib.js.org/assets/dod_character.pdf' ;
const formBytes = await fetch ( formUrl ) . then ( ( res ) => res . arrayBuffer ( ) ) ;
// Fetch the Ubuntu font
const fontUrl = 'https://pdf-lib.js.org/assets/ubuntu/Ubuntu-R.ttf' ;
const fontBytes = await fetch ( fontUrl ) . then ( ( res ) => res . arrayBuffer ( ) ) ;
// Load the PDF with form fields
const pdfDoc = await PDFDocument . load ( formBytes ) ;
// Embed the Ubuntu font
pdfDoc . registerFontkit ( fontkit ) ;
const ubuntuFont = await pdfDoc . embedFont ( fontBytes ) ;
// Get two text fields from the form
const form = pdfDoc . getForm ( ) ;
const nameField = form . getTextField ( 'CharacterName 2' ) ;
const ageField = form . getTextField ( 'Age' ) ;
// Fill the text fields with some fancy Unicode characters (outside
// the WinAnsi latin character set)
nameField . setText ( 'Ӎӑȑїõ' ) ;
ageField . setText ( '24 ŷȇȁŗš' ) ;
// **Key Step:** Update the field appearances with the Ubuntu font
form . updateFieldAppearances ( ubuntuFont ) ;
// Save the PDF with filled form fields
const pdfBytes = await pdfDoc . save ( ) ;
既存のフォーム フィールドには、 PDFForm
の次のメソッドを使用してアクセスできます。
PDFForm.getButton
PDFForm.getCheckBox
PDFForm.getDropdown
PDFForm.getOptionList
PDFForm.getRadioGroup
PDFForm.getTextField
新しいフォームフィールドは、 PDFForm
の次のメソッドを使用して作成できます。
PDFForm.createButton
PDFForm.createCheckBox
PDFForm.createDropdown
PDFForm.createOptionList
PDFForm.createRadioGroup
PDFForm.createTextField
以下は、前述のPDFField
のサブクラスの読み取りと入力に最も一般的に使用されるメソッドの一部です。
PDFCheckBox.check
PDFCheckBox.uncheck
PDFCheckBox.isChecked
PDFDropdown.select
PDFDropdown.clear
PDFDropdown.getSelected
PDFDropdown.getOptions
PDFDropdown.addOptions
PDFOptionList.select
PDFOptionList.clear
PDFOptionList.getSelected
PDFOptionList.getOptions
PDFOptionList.addOptions
PDFRadioGroup.select
PDFRadioGroup.clear
PDFRadioGroup.getSelected
PDFRadioGroup.getOptions
PDFRadioGroup.addOptionToPage
PDFTextField.setText
PDFTextField.getText
PDFTextField.setMaxLength
PDFTextField.getMaxLength
PDFTextField.removeMaxLength
pdf-lib
テキスト フィールドの内容を抽出できます( PDFTextField.getText
を参照) が、フォーム フィールドの外側のページ上のプレーン テキストを抽出することはできません。これは実装が難しい機能ですが、このライブラリの範囲内であり、将来pdf-lib
に追加される可能性があります。 #93、#137、#177、#329、および #380 を参照してください。pdf-lib
テキスト フィールドの内容を削除および編集できます( PDFTextField.setText
を参照) が、フォーム フィールドの外側のページ上のテキストを削除または編集するための API は提供しません。これも実装が難しい機能ですが、 pdf-lib
の範囲内であり、将来追加される可能性があります。 #93、#137、#177、#329、および #380 を参照してください。pdf-lib
PDF にコンテンツを追加する際の HTML または CSS の使用をサポートしていません。同様に、 pdf-lib
HTML/CSS コンテンツを PDF に埋め込むことができません。このような機能は便利かもしれませんが、実装するのは非常に難しく、このライブラリの範囲をはるかに超えています。この機能が必要な場合は、Puppeteer の使用を検討してください。 ディスカッションは、私たちとチャットしたり、質問したり、pdf-lib についてさらに学ぶのに最適な場所です。
MAINTAINERSHIP.md#communication および MAINTAINERSHIP.md#discord も参照してください。
pdf-lib
現在、暗号化されたドキュメントをサポートしていません。暗号化されたドキュメントではpdf-lib
使用しないでください。ただし、これはpdf-lib
に追加できる機能です。この機能が役立つと思われる場合は、問題を作成してください。
暗号化されたドキュメントがPDFDocument.load(...)
に渡されると、エラーがスローされます。
import { PDFDocument , EncryptedPDFError } from 'pdf-lib'
const encryptedPdfBytes = ...
// Assignment fails. Throws an `EncryptedPDFError`.
const pdfDoc = PDFDocument . load ( encryptedPdfBytes )
通常は、このデフォルトの動作が望ましいものになります。これにより、特定のドキュメントが暗号化されているかどうかを簡単に検出でき、ドキュメントを変更しようとするのを防ぐことができます。ただし、本当にドキュメントをロードしたい場合は、 { ignoreEncryption: true }
オプションを使用できます。
import { PDFDocument } from 'pdf-lib'
const encryptedPdfBytes = ...
// Assignment succeeds. Does not throw an error.
const pdfDoc = PDFDocument . load ( encryptedPdfBytes , { ignoreEncryption : true } )
このオプションを使用してもドキュメントは復号化されないことに注意してください。これは、返されたPDFDocument
に変更を加えようとすると失敗するか、予期しない結果が生じる可能性があることを意味します。
このオプションは使用しないでください。これは下位互換性の理由からのみ存在します。
オープンソース コミュニティからの貢献を歓迎します。 pdf-lib
への貢献に興味がある場合は、CONTRIBUTING.md ファイルをご覧ください。これには、マシン上でpdf-lib
セットアップして実行するのに役立つ情報が含まれています。 (私たちはこれをできるだけ簡単かつ迅速に行うよう努めています!)
このリポジトリがどのように維持されているか、また問題、PR、ディスカッションがどのように使用されているかについて詳しくは、MAINTAINERSHIP.md をご覧ください。
pdfkit
、ノードおよびブラウザ用の PDF 生成ライブラリです。このライブラリはpdf-lib
作成する際の参照および存在証明として非常に役立ちました。 pdfkit
のフォント埋め込み、PNG 埋め込み、JPG 埋め込み用のコードは特に役に立ちました。pdf.js
、ブラウザ用の PDF レンダリング ライブラリです。このライブラリは、 pdf-lib
のパーサーを作成する際の参考として役に立ちました。ストリーム デコード用のコードの一部は、 pdf-lib
で使用するために TypeScript に直接移植されました。pdfbox
、Java で書かれた PDF の生成および変更ライブラリです。このライブラリはpdf-lib
のフォーム作成と入力 API を実装する際に貴重なリファレンスでした。jspdf
ブラウザ用の PDF 生成ライブラリです。pdfmake
ブラウザ用の PDF 生成ライブラリです。hummus
、Node 環境用の PDF 生成および変更ライブラリです。 hummus
は C++ ライブラリの Node ラッパーであるため、ブラウザや React Native などの多くの JavaScript 環境では動作しません。react-native-pdf-lib
React Native 環境用の PDF 生成および変更ライブラリです。 react-native-pdf-lib
C++ および Java ライブラリのラッパーです。pdfassembler
、Node およびブラウザ用の PDF 生成および変更ライブラリです。使用するには、PDF ドキュメントの論理構造に関するある程度の知識が必要です。 このリポジトリには、ルート ディレクトリにpdf_specification.pdf
というファイルが含まれていました。これは、Adobe によって無料で入手できる PDF 1.7 仕様のコピーでした。 2021 年 8 月 30 日に、このリポジトリからファイルを削除するよう求める DMCA の苦情を受け取りました。 master
への新しいコミットを介してファイルを削除するだけでは、苦情を満たすには不十分でした。ファイルはリポジトリの git 履歴から完全に削除する必要がありました。残念ながら、このファイルは 2 年以上前に追加されたものであるため、リポジトリの git 履歴を書き換えてmaster
? に強制的にプッシュする必要がありました。
ここで説明するように、ファイルを削除し、BFG Repo-Cleaner を使用してリポジトリの履歴を書き直しました。完全な透明性を確保するために、実行した正確なコマンドを次に示します。
$ git clone [email protected]:Hopding/pdf-lib.git
$ cd pdf-lib
$ rm pdf_specification.pdf
$ git commit -am 'Remove pdf_specification.pdf'
$ bfg --delete-files pdf_specification.pdf
$ git reflog expire --expire=now --all && git gc --prune=now --aggressive
$ git push --force
pdf-lib
のユーザーであれば、気にする必要はありません。通常どおりpdf-lib
使い続けてください。 !
あなたがpdf-lib
開発者である場合 ( pdf-lib
をフォークしたことがある、またはオープン PR を持っていることを意味します)、これは影響します。 2021 年 8 月 30 日より前にリポジトリをフォークまたはクローンした場合、フォークの git 履歴はこのリポジトリのmaster
ブランチと同期していません。残念ながら、これに対処するのは頭の痛い問題になるでしょう。ごめん!私たちは歴史を書き換えたくはありませんでしたが、実際には他に選択肢はありませんでした。
pdf-lib のソース コードはまったく変更されていないことに注意することが重要です。 git 履歴を書き換える前とまったく同じです。リポジトリには、まったく同じ数のコミットがまだ含まれています (さらに、 pdf_specification.pdf
を追加したコミットを除いて、同じコミット内容も含まれています)。変更されたのは、それらのコミットの SHA です。
この事実に対処する最も簡単な方法は次のとおりです。
git 履歴の書き換えに伴う内容についての優れた詳細な説明については、この StackOverflow の回答を参照してください。
マサチューセッツ工科大学