Узнайте больше на pdf-lib.js.org.
pdf-lib
был создан для решения проблемы отсутствия в экосистеме JavaScript надежной поддержки манипуляций с PDF-файлами (особенно для модификации PDF-файлов).
Две отличительные особенности pdf-lib
:
Существуют и другие хорошие библиотеки 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
переменной PdfBytes).
Попробуйте демо-версию 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
переменной DonorPdfBytes).
Попробуйте демо-версию 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. Единственное, что вам нужно сделать, это изменить импорт pdf-lib
и @pdf-lib/fontkit
для использования Skypack CDN, поскольку Deno требует, чтобы на все модули ссылались через URL-адреса.
См. также «Как создавать и изменять PDF-файлы в Deno с помощью pdf-lib».
Ниже приведен пример создания документа, модифицированный для 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
перед каждым выпуском (в дополнение к автоматическим тестам).
На данный момент существует четыре приложения:
node
— содержит тесты для pdf-lib
в средах Node. Эти тесты являются удобным справочником при попытке сохранить/загрузить PDF-файлы, шрифты или изображения с помощью pdf-lib
из файловой системы. Они также позволяют быстро открывать PDF-файлы в различных программах просмотра (Acrobat, Preview, Foxit, Chrome, Firefox и т. д.), чтобы обеспечить совместимость.web
— содержит тесты для pdf-lib
в среде браузера. Эти тесты являются удобным справочником при попытке сохранить/загрузить PDF-файлы, шрифты или изображения с помощью pdf-lib
в среде браузера.rn
— содержит тесты для pdf-lib
в средах React Native. Эти тесты являются удобным справочником при попытке сохранить/загрузить PDF-файлы, шрифты или изображения с помощью pdf-lib
в среде React Native.deno
— содержит тесты для pdf-lib
в средах Deno. Эти тесты являются удобным справочником при попытке сохранить/загрузить PDF-файлы, шрифты или изображения с помощью pdf-lib
из файловой системы. Чтобы установить последнюю стабильную версию:
# With npm
npm install --save pdf-lib
# With yarn
yarn add pdf-lib
Предполагается, что вы используете npm или Yarn в качестве менеджера пакетов.
Вы также можете скачать pdf-lib
как модуль UMD из unpkg или jsDelivr. Сборки UMD скомпилированы в ES5, поэтому они должны работать в любом современном браузере. Сборки UMD полезны, если вы не используете менеджер пакетов или сборщик модулей. Например, вы можете использовать их непосредственно в теге <script>
HTML-страницы.
Доступны следующие сборки:
ПРИМЕЧАНИЕ. Если вы используете сценарии 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-файлами вы часто будете сталкиваться с терминами «кодировка символов» и «шрифт». Если у вас есть опыт веб-разработки, вы можете задаться вопросом, почему они так распространены. Разве это не просто раздражающие детали, о которых не стоит беспокоиться? Разве 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
. Встраивая собственный шрифт, вы можете использовать любые символы Юникода, которые он поддерживает. Эта возможность освобождает вас от ограничений, налагаемых стандартными шрифтами. В большинстве 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. Этот шрифт поддерживает только символы латинского алфавита (подробнее см. в разделе «Шрифты и Юникод»). Это означает, что если какой-либо из этих типов полей создается или изменяется так, чтобы содержать текст за пределами латинского алфавита (как это часто бывает), вам потребуется встроить и использовать собственный шрифт для обновления внешнего вида поля. В противном случае будет выдана ошибка (вероятно, при сохранении 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
не поддерживает использование HTML или CSS при добавлении содержимого в PDF-файл. Аналогично, 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
на вашем компьютере. (Мы стараемся сделать это максимально просто и быстро!)
Посетите MAINTAINERSHIP.md, чтобы узнать подробнее о том, как поддерживается этот репозиторий и как мы используем задачи, PR и обсуждения.
pdfkit
— это библиотека создания PDF-файлов для Node и браузера. Эта библиотека оказалась чрезвычайно полезной в качестве справочного материала и доказательства существования при создании pdf-lib
. Код pdfkit
для встраивания шрифтов, встраивания PNG и встраивания JPG был особенно полезен.pdf.js
— это библиотека рендеринга PDF для браузера. Эта библиотека была полезна в качестве справочного материала при написании парсера pdf-lib
. Часть кода декодирования потока была перенесена непосредственно в TypeScript для использования в pdf-lib
.pdfbox
— это библиотека создания и изменения PDF-файлов, написанная на Java. Эта библиотека стала неоценимым справочником при реализации создания и заполнения форм API для pdf-lib
.jspdf
— это библиотека создания PDF-файлов для браузера.pdfmake
— это библиотека создания PDF-файлов для браузера.hummus
— это библиотека создания и модификации PDF-файлов для сред Node. hummus
— это Node-оболочка библиотеки C++, поэтому он не работает во многих средах JavaScript, таких как браузер или React Native.react-native-pdf-lib
— это библиотека создания и модификации PDF-файлов для сред React Native. react-native-pdf-lib
— это оболочка библиотек C++ и Java.pdfassembler
— это библиотека создания и модификации PDF-файлов для Node и браузера. Для использования требуются некоторые знания о логической структуре PDF-документов. Раньше этот репозиторий содержал файл с именем pdf_specification.pdf
в корневом каталоге. Это была копия спецификации PDF 1.7, которую Adobe предоставила в свободном доступе. 30 августа 2021 г. мы получили жалобу DMCA с требованием удалить файл из этого репозитория. Простого удаления файла посредством новой фиксации в master
было недостаточно для удовлетворения жалобы. Файл необходимо было полностью удалить из истории git репозитория. К сожалению, файл был добавлен более двух лет назад, а это означало, что нам пришлось переписать историю 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), то это действительно на вас повлияет. Если вы разветвили или клонировали репозиторий до 30 августа 2021 г., то история git вашего форка не синхронизирована с master
веткой этого репозитория. К сожалению, это, скорее всего, станет для вас головной болью. Извини! Мы не хотели переписывать историю, но альтернативы действительно не было.
Важно отметить, что исходный код pdf-lib вообще не изменился. Это точно так же, как и до переписывания истории git. Репозиторий по-прежнему имеет точно такое же количество коммитов (и даже то же содержимое коммитов, за исключением коммита, в который добавлен pdf_specification.pdf
). Что изменилось, так это SHA этих коммитов.
Самый простой способ справиться с этим фактом:
См. этот ответ StackOverflow, где вы найдете отличное и подробное объяснение того, что влечет за собой перезапись истории git.
Массачусетский технологический институт