Saiba mais em pdf-lib.js.org
pdf-lib
foi criado para resolver a falta de suporte robusto do ecossistema JavaScript para manipulação de PDF (especialmente para modificação de PDF).
Duas das características distintivas do pdf-lib
são:
Existem outras boas bibliotecas JavaScript PDF de código aberto disponíveis. No entanto, a maioria deles só pode criar documentos, não podem modificar os existentes. E muitos deles só funcionam em ambientes específicos.
Este exemplo produz este PDF.
Experimente a demonstração 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>
Este exemplo produz este PDF (quando este PDF é usado para a variável existingPdfBytes
).
Experimente a demonstração 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>
Este exemplo produz este PDF.
Experimente a demonstração JSFiddle
Veja também Criando e Preenchendo Formulários
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>
Este exemplo produz este PDF (quando este PDF é usado para a variável formPdfBytes
, esta imagem é usada para a variável marioImageBytes
e esta imagem é usada para a variável emblemImageBytes
).
Experimente a demonstração JSFiddle
Veja também Criando e Preenchendo Formulários
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>
Este exemplo produz este PDF (quando este PDF é usado para a variável formPdfBytes
).
Experimente a demonstração 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>
Este exemplo produz este PDF (quando este PDF é usado para a variável firstDonorPdfBytes
e este PDF é usado para a variável secondDonorPdfBytes
).
Experimente a demonstração 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>
Este exemplo produz este PDF (quando esta imagem é usada para a variável jpgImageBytes
e esta imagem é usada para a variável pngImageBytes
).
Experimente a demonstração 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>
Este exemplo produz este PDF (quando este PDF é usado para a variável americanFlagPdfBytes
e este PDF é usado para a variável usConstitutionPdfBytes
).
Experimente a demonstração 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
depende de um módulo irmão para suportar a incorporação de fontes personalizadas: @pdf-lib/fontkit
. Você deve adicionar o módulo @pdf-lib/fontkit
ao seu projeto e registrá-lo usando pdfDoc.registerFontkit(...)
antes de incorporar fontes personalizadas.
Veja abaixo instruções detalhadas de instalação sobre como instalar
@pdf-lib/fontkit
como um módulo UMD ou NPM.
Este exemplo produz este PDF (quando esta fonte é usada para a variável fontBytes
).
Experimente a demonstração 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>
Este exemplo produz este PDF (quando esta imagem é usada para a variável jpgAttachmentBytes
e este PDF é usado para a variável pdfAttachmentBytes
).
Experimente a demonstração 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>
Este exemplo produz este PDF .
Experimente a demonstração 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>
Experimente a demonstração 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 ( ) )
Este script gera o seguinte ( quando este PDF é usado para a variável 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 ( ) )
Este script gera o seguinte ( quando este PDF é usado para a variável 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
Este exemplo produz este PDF .
Experimente a demonstração 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
suporta totalmente o novo e emocionante tempo de execução Deno! Todos os exemplos de uso funcionam no Deno. A única coisa que você precisa fazer é alterar as importações de pdf-lib
e @pdf-lib/fontkit
para usar o Skypack CDN, porque o Deno exige que todos os módulos sejam referenciados via URLs.
Veja também Como criar e modificar arquivos PDF no Deno com pdf-lib
Abaixo está o exemplo de criação de documento modificado para 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 ) ;
Se você salvar este script como create-document.ts
, poderá executá-lo usando Deno com o seguinte comando:
deno run --allow-write create-document.ts
O arquivo out.pdf
resultante será semelhante a este PDF.
Aqui está um exemplo um pouco mais complicado que demonstra como incorporar uma fonte e medir texto no 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 ) ;
Se você salvar este script como custom-font.ts
, poderá executá-lo com o seguinte comando:
deno run --allow-write --allow-net custom-font.ts
O arquivo out.pdf
resultante será semelhante a este PDF.
Os exemplos de uso fornecem um código breve e direto, demonstrando os diferentes recursos do pdf-lib
. Você pode encontrar exemplos de trabalho completos no diretório apps/
. Esses aplicativos são usados para fazer testes manuais do pdf-lib
antes de cada lançamento (além dos testes automatizados).
Existem atualmente quatro aplicativos:
node
- contém testes para pdf-lib
em ambientes Node. Esses testes são uma referência útil ao tentar salvar/carregar PDFs, fontes ou imagens com pdf-lib
do sistema de arquivos. Eles também permitem que você abra rapidamente seus PDFs em diferentes visualizadores (Acrobat, Preview, Foxit, Chrome, Firefox, etc...) para garantir a compatibilidade.web
- contém testes para pdf-lib
em ambientes de navegador. Esses testes são uma referência útil ao tentar salvar/carregar PDFs, fontes ou imagens com pdf-lib
em um ambiente de navegador.rn
- contém testes para pdf-lib
em ambientes React Native. Esses testes são uma referência útil ao tentar salvar/carregar PDFs, fontes ou imagens com pdf-lib
em um ambiente React Native.deno
- contém testes para pdf-lib
em ambientes Deno. Esses testes são uma referência útil ao tentar salvar/carregar PDFs, fontes ou imagens com pdf-lib
do sistema de arquivos. Para instalar a versão estável mais recente:
# With npm
npm install --save pdf-lib
# With yarn
yarn add pdf-lib
Isso pressupõe que você esteja usando npm ou yarn como gerenciador de pacotes.
Você também pode baixar pdf-lib
como um módulo UMD em unpkg ou jsDelivr. As compilações UMD foram compiladas para ES5, portanto devem funcionar em qualquer navegador moderno. As compilações UMD são úteis se você não estiver usando um gerenciador de pacotes ou empacotador de módulos. Por exemplo, você pode usá-los diretamente na tag <script>
de uma página HTML.
As seguintes compilações estão disponíveis:
NOTA: se você estiver usando scripts CDN em produção, deverá incluir um número de versão específico na URL, por exemplo:
- https://unpkg.com/[email protected]/dist/pdf-lib.min.js
- https://cdn.jsdelivr.net/npm/[email protected]/dist/pdf-lib.min.js
Ao usar uma compilação UMD, você terá acesso a uma variável global window.PDFLib
. Esta variável contém todas as classes e funções exportadas por pdf-lib
. Por exemplo:
// NPM module
import { PDFDocument , rgb } from 'pdf-lib' ;
// UMD module
var PDFDocument = PDFLib . PDFDocument ;
var rgb = PDFLib . rgb ;
pdf-lib
depende de um módulo irmão para suportar a incorporação de fontes personalizadas: @pdf-lib/fontkit
. Você deve adicionar o módulo @pdf-lib/fontkit
ao seu projeto e registrá-lo usando pdfDoc.registerFontkit(...)
antes de incorporar fontes personalizadas (veja o exemplo de incorporação de fontes). Este módulo não está incluído por padrão porque nem todos os usuários precisam dele e aumenta o tamanho do pacote.
Instalar este módulo é fácil. Assim como o próprio pdf-lib
, @pdf-lib/fontkit
pode ser instalado com npm
/ yarn
ou como um módulo UMD.
# With npm
npm install --save @pdf-lib/fontkit
# With yarn
yarn add @pdf-lib/fontkit
Para registrar a instância fontkit
:
import { PDFDocument } from 'pdf-lib'
import fontkit from '@pdf-lib/fontkit'
const pdfDoc = await PDFDocument . create ( )
pdfDoc . registerFontkit ( fontkit )
As seguintes compilações estão disponíveis:
NOTA: se você estiver usando scripts CDN em produção, deverá incluir um número de versão específico na URL, por exemplo:
- 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
Ao usar uma compilação UMD, você terá acesso a uma variável global window.fontkit
. Para registrar a instância fontkit
:
var pdfDoc = await PDFLib . PDFDocument . create ( )
pdfDoc . registerFontkit ( fontkit )
A documentação da API está disponível no site do projeto em https://pdf-lib.js.org/docs/api/.
O repositório do site do projeto (e os arquivos de documentação gerados) está localizado aqui: https://github.com/Hopding/pdf-lib-docs.
Ao trabalhar com PDFs, você frequentemente encontrará os termos “codificação de caracteres” e “fonte”. Se você tem experiência em desenvolvimento web, pode estar se perguntando por que eles são tão comuns. Não são apenas detalhes irritantes com os quais você não deveria se preocupar? As bibliotecas e leitores de PDF não deveriam ser capazes de lidar com tudo isso para você como os navegadores da web podem? Infelizmente, este não é o caso. A natureza do formato de arquivo PDF torna muito difícil evitar pensar em codificações de caracteres e fontes ao trabalhar com PDFs.
pdf-lib
faz o possível para simplificar as coisas para você. Mas não pode realizar magia. Isso significa que você deve estar ciente do seguinte:
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
. Ao incorporar sua própria fonte, você pode usar qualquer caractere Unicode compatível. Esse recurso libera você das limitações impostas pelas fontes padrão. A maioria dos arquivos PDF usa fontes incorporadas. Você pode incorporar e usar uma fonte personalizada como esta (veja também): 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 ,
} )
Observe que erros de codificação serão gerados se você tentar usar um caractere com uma fonte que não seja compatível. Por exemplo, Ω
não está no conjunto de caracteres WinAnsi. Portanto, tentar desenhá-lo em uma página com a fonte Helvetica padrão gerará o seguinte erro:
Error: WinAnsi cannot encode "Ω" (0x03a9)
at Encoding.encodeUnicodeCodePoint
Incorporar uma fonte em um documento PDF normalmente aumenta o tamanho do arquivo. Você pode reduzir o aumento do tamanho de um arquivo subdividindo a fonte para que apenas os caracteres necessários sejam incorporados. Você pode criar subconjuntos de uma fonte definindo a opção de subset
como true
. Por exemplo:
const font = await pdfDoc . embedFont ( fontBytes , { subset : true } ) ;
Observe que o subconjunto não funciona para todas as fontes. Consulte #207 (comentário) para obter detalhes adicionais.
pdf-lib
pode criar, preencher e ler campos de formulário PDF. Os seguintes tipos de campo são suportados:
Consulte os exemplos de uso de criação e preenchimento de formulários para exemplos de código. Os testes 1, 14, 15, 16 e 17 nos exemplos completos contêm código de exemplo funcional para criação e preenchimento de formulários em uma variedade de ambientes JS diferentes.
IMPORTANTE: A fonte padrão usada para exibir texto em botões, menus suspensos, listas de opções e campos de texto é a fonte Helvetica padrão. Esta fonte suporta apenas caracteres do alfabeto latino (consulte Fontes e Unicode para obter detalhes). Isso significa que se qualquer um desses tipos de campo for criado ou modificado para conter texto fora do alfabeto latino (como costuma acontecer), você precisará incorporar e usar uma fonte personalizada para atualizar a aparência do campo. Caso contrário, um erro será gerado (provavelmente quando você salvar o PDFDocument
).
Você pode usar uma fonte incorporada ao preencher os campos do formulário da seguinte forma:
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 ( ) ;
Os campos de formulário existentes podem ser acessados com os seguintes métodos de PDFForm
:
PDFForm.getButton
PDFForm.getCheckBox
PDFForm.getDropdown
PDFForm.getOptionList
PDFForm.getRadioGroup
PDFForm.getTextField
Novos campos de formulário podem ser criados com os seguintes métodos de PDFForm
:
PDFForm.createButton
PDFForm.createCheckBox
PDFForm.createDropdown
PDFForm.createOptionList
PDFForm.createRadioGroup
PDFForm.createTextField
Abaixo estão alguns dos métodos mais comumente usados para leitura e preenchimento das subclasses de PDFField
mencionadas:
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
pode extrair o conteúdo de campos de texto (consulte PDFTextField.getText
), mas não pode extrair texto simples em uma página fora de um campo de formulário. Este é um recurso difícil de implementar, mas está dentro do escopo desta biblioteca e pode ser adicionado ao pdf-lib
no futuro. Consulte nº 93, nº 137, nº 177, nº 329 e nº 380.pdf-lib
pode remover e editar o conteúdo de campos de texto (consulte PDFTextField.setText
), mas não fornece APIs para remover ou editar texto em uma página fora de um campo de formulário. Este também é um recurso difícil de implementar, mas está dentro do escopo do pdf-lib
e pode ser adicionado no futuro. Consulte nº 93, nº 137, nº 177, nº 329 e nº 380.pdf-lib
não suporta o uso de HTML ou CSS ao adicionar conteúdo a um PDF. Da mesma forma, pdf-lib
não pode incorporar conteúdo HTML/CSS em PDFs. Por mais conveniente que seja esse recurso, seria extremamente difícil de implementar e está muito além do escopo desta biblioteca. Se esse recurso for algo que você precisa, considere usar o Puppeteer. Discussões é o melhor lugar para conversar conosco, fazer perguntas e aprender mais sobre o pdf-lib!
Consulte também MAINTAINERSHIP.md#communication e MAINTAINERSHIP.md#discord.
pdf-lib
atualmente não oferece suporte a documentos criptografados. Você não deve usar pdf-lib
com documentos criptografados. No entanto, este é um recurso que poderia ser adicionado ao pdf-lib
. Crie um problema se achar este recurso útil!
Quando um documento criptografado é passado para PDFDocument.load(...)
, um erro será gerado:
import { PDFDocument , EncryptedPDFError } from 'pdf-lib'
const encryptedPdfBytes = ...
// Assignment fails. Throws an `EncryptedPDFError`.
const pdfDoc = PDFDocument . load ( encryptedPdfBytes )
Esse comportamento padrão geralmente é o que você deseja. Ele permite detectar facilmente se um determinado documento está criptografado e evita que você tente modificá-lo. Porém, se você realmente deseja carregar o documento, você pode usar a opção { ignoreEncryption: true }
:
import { PDFDocument } from 'pdf-lib'
const encryptedPdfBytes = ...
// Assignment succeeds. Does not throw an error.
const pdfDoc = PDFDocument . load ( encryptedPdfBytes , { ignoreEncryption : true } )
Observe que usar esta opção não descriptografa o documento . Isso significa que quaisquer modificações que você tentar fazer no PDFDocument
retornado poderão falhar ou ter resultados inesperados.
Você não deve usar esta opção. Ele existe apenas por motivos de compatibilidade com versões anteriores.
Aceitamos contribuições da comunidade de código aberto! Se você estiver interessado em contribuir para pdf-lib
, dê uma olhada no arquivo CONTRIBUTING.md. Ele contém informações para ajudá-lo a configurar e executar pdf-lib
em sua máquina. (Tentamos tornar isso o mais simples e rápido possível!)
Confira MAINTAINERSHIP.md para obter detalhes sobre como este repositório é mantido e como usamos problemas, PRs e discussões.
pdfkit
é uma biblioteca de geração de PDF para Node e navegador. Esta biblioteca foi imensamente útil como referência e prova de existência ao criar pdf-lib
. O código do pdfkit
para incorporação de fontes, incorporação de PNG e incorporação de JPG foi especialmente útil.pdf.js
é uma biblioteca de renderização de PDF para o navegador. Esta biblioteca foi útil como referência ao escrever o analisador de pdf-lib
. Parte do código para decodificação de fluxo foi portado diretamente para TypeScript para uso em pdf-lib
.pdfbox
é uma biblioteca de geração e modificação de PDF escrita em Java. Esta biblioteca foi uma referência inestimável na implementação de APIs de criação e preenchimento de formulários para pdf-lib
.jspdf
é uma biblioteca de geração de PDF para o navegador.pdfmake
é uma biblioteca de geração de PDF para o navegador.hummus
é uma biblioteca de geração e modificação de PDF para ambientes Node. hummus
é um wrapper Node em torno de uma biblioteca C++, portanto não funciona em muitos ambientes JavaScript - como o Browser ou React Native.react-native-pdf-lib
é uma biblioteca de geração e modificação de PDF para ambientes React Native. react-native-pdf-lib
é um wrapper para bibliotecas C++ e Java.pdfassembler
é uma biblioteca de geração e modificação de PDF para Node e navegador. Para usar, é necessário algum conhecimento sobre a estrutura lógica dos documentos PDF. Este repositório costumava conter um arquivo chamado pdf_specification.pdf
no diretório raiz. Esta era uma cópia da especificação PDF 1.7, disponibilizada gratuitamente pela Adobe. Em 30/08/2021, recebemos uma reclamação DMCA exigindo a remoção do arquivo deste repositório. A simples remoção do arquivo por meio de um novo commit no master
não foi suficiente para satisfazer a reclamação. O arquivo precisava ser completamente removido do histórico git do repositório. Infelizmente, o arquivo foi adicionado há mais de dois anos, o que significou que tivemos que reescrever o histórico git do repositório e forçar o push para master
?.
Removemos o arquivo e reescrevemos o histórico do repositório usando BFG Repo-Cleaner conforme descrito aqui. Para total transparência, aqui estão os comandos exatos que executamos:
$ 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
Se você é usuário de pdf-lib
, não deveria se importar! Continue usando pdf-lib
normalmente? !
Se você é um desenvolvedor pdf-lib
(o que significa que você bifurcou pdf-lib
e/ou tem um PR aberto), isso terá impacto sobre você. Se você bifurcou ou clonou o repositório antes de 30/08/2021, o histórico git do seu fork está fora de sincronia com o branch master
deste repositório. Infelizmente, isso provavelmente será uma dor de cabeça para você. Desculpe! Não queríamos reescrever a história, mas realmente não havia alternativa.
É importante notar que o código-fonte do pdf-lib não mudou em nada. É exatamente o mesmo que era antes da reescrita do histórico do git. O repositório ainda tem exatamente o mesmo número de commits (e até mesmo o mesmo conteúdo do commit, exceto o commit que adicionou pdf_specification.pdf
). O que mudou foram os SHAs desses commits.
A maneira mais simples de lidar com esse fato é:
Veja esta resposta do StackOverflow para obter uma explicação excelente e detalhada sobre o que envolve uma reescrita do histórico do git.
MIT