تعرف على المزيد على 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
).
جرب العرض التوضيحي لـ JSFiddle
import { degrees , PDFDocument , rgb , StandardFonts } from 'pdf-lib' ;
// This should be a Uint8Array or ArrayBuffer
// This data can be obtained in a number of different ways
// If your running in a Node environment, you could use fs.readFile()
// In the browser, you could make a fetch() call and use res.arrayBuffer()
const existingPdfBytes = ...
// Load a PDFDocument from the existing PDF bytes
const pdfDoc = await PDFDocument . load ( existingPdfBytes )
// Embed the Helvetica font
const helveticaFont = await pdfDoc . embedFont ( StandardFonts . Helvetica )
// Get the first page of the document
const pages = pdfDoc . getPages ( )
const firstPage = pages [ 0 ]
// Get the width and height of the first page
const { width , height } = firstPage . getSize ( )
// Draw a string of text diagonally across the first page
firstPage . drawText ( 'This text was added with JavaScript!' , {
x : 5 ,
y : height / 2 + 300 ,
size : 50 ,
font : helveticaFont ,
color : rgb ( 0.95 , 0.1 , 0.1 ) ,
rotate : degrees ( - 45 ) ,
} )
// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc . save ( )
// For example, `pdfBytes` can be:
// • Written to a file in Node
// • Downloaded from the browser
// • Rendered in an <iframe>
هذا المثال ينتج ملف PDF هذا.
جرب العرض التوضيحي لـ JSFiddle
انظر أيضًا إنشاء النماذج وتعبئتها
import { PDFDocument } from 'pdf-lib'
// Create a new PDFDocument
const pdfDoc = await PDFDocument . create ( )
// Add a blank page to the document
const page = pdfDoc . addPage ( [ 550 , 750 ] )
// Get the form so we can add fields to it
const form = pdfDoc . getForm ( )
// Add the superhero text field and description
page . drawText ( 'Enter your favorite superhero:' , { x : 50 , y : 700 , size : 20 } )
const superheroField = form . createTextField ( 'favorite.superhero' )
superheroField . setText ( 'One Punch Man' )
superheroField . addToPage ( page , { x : 55 , y : 640 } )
// Add the rocket radio group, labels, and description
page . drawText ( 'Select your favorite rocket:' , { x : 50 , y : 600 , size : 20 } )
page . drawText ( 'Falcon Heavy' , { x : 120 , y : 560 , size : 18 } )
page . drawText ( 'Saturn IV' , { x : 120 , y : 500 , size : 18 } )
page . drawText ( 'Delta IV Heavy' , { x : 340 , y : 560 , size : 18 } )
page . drawText ( 'Space Launch System' , { x : 340 , y : 500 , size : 18 } )
const rocketField = form . createRadioGroup ( 'favorite.rocket' )
rocketField . addOptionToPage ( 'Falcon Heavy' , page , { x : 55 , y : 540 } )
rocketField . addOptionToPage ( 'Saturn IV' , page , { x : 55 , y : 480 } )
rocketField . addOptionToPage ( 'Delta IV Heavy' , page , { x : 275 , y : 540 } )
rocketField . addOptionToPage ( 'Space Launch System' , page , { x : 275 , y : 480 } )
rocketField . select ( 'Saturn IV' )
// Add the gundam check boxes, labels, and description
page . drawText ( 'Select your favorite gundams:' , { x : 50 , y : 440 , size : 20 } )
page . drawText ( 'Exia' , { x : 120 , y : 400 , size : 18 } )
page . drawText ( 'Kyrios' , { x : 120 , y : 340 , size : 18 } )
page . drawText ( 'Virtue' , { x : 340 , y : 400 , size : 18 } )
page . drawText ( 'Dynames' , { x : 340 , y : 340 , size : 18 } )
const exiaField = form . createCheckBox ( 'gundam.exia' )
const kyriosField = form . createCheckBox ( 'gundam.kyrios' )
const virtueField = form . createCheckBox ( 'gundam.virtue' )
const dynamesField = form . createCheckBox ( 'gundam.dynames' )
exiaField . addToPage ( page , { x : 55 , y : 380 } )
kyriosField . addToPage ( page , { x : 55 , y : 320 } )
virtueField . addToPage ( page , { x : 275 , y : 380 } )
dynamesField . addToPage ( page , { x : 275 , y : 320 } )
exiaField . check ( )
dynamesField . check ( )
// Add the planet dropdown and description
page . drawText ( 'Select your favorite planet*:' , { x : 50 , y : 280 , size : 20 } )
const planetsField = form . createDropdown ( 'favorite.planet' )
planetsField . addOptions ( [ 'Venus' , 'Earth' , 'Mars' , 'Pluto' ] )
planetsField . select ( 'Pluto' )
planetsField . addToPage ( page , { x : 55 , y : 220 } )
// Add the person option list and description
page . drawText ( 'Select your favorite person:' , { x : 50 , y : 180 , size : 18 } )
const personField = form . createOptionList ( 'favorite.person' )
personField . addOptions ( [
'Julius Caesar' ,
'Ada Lovelace' ,
'Cleopatra' ,
'Aaron Burr' ,
'Mark Antony' ,
] )
personField . select ( 'Ada Lovelace' )
personField . addToPage ( page , { x : 55 , y : 70 } )
// Just saying...
page . drawText ( `* Pluto should be a planet too!` , { x : 15 , y : 15 , size : 15 } )
// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc . save ( )
// For example, `pdfBytes` can be:
// • Written to a file in Node
// • Downloaded from the browser
// • Rendered in an <iframe>
ينتج عن هذا المثال ملف PDF هذا (عند استخدام ملف PDF هذا لمتغير formPdfBytes
، يتم استخدام هذه الصورة لمتغير marioImageBytes
، ويتم استخدام هذه الصورة لمتغير emblemImageBytes
).
جرب العرض التوضيحي لـ JSFiddle
انظر أيضًا إنشاء النماذج وتعبئتها
import { PDFDocument } from 'pdf-lib'
// These should be Uint8Arrays or ArrayBuffers
// This data can be obtained in a number of different ways
// If your running in a Node environment, you could use fs.readFile()
// In the browser, you could make a fetch() call and use res.arrayBuffer()
const formPdfBytes = ...
const marioImageBytes = ...
const emblemImageBytes = ...
// Load a PDF with form fields
const pdfDoc = await PDFDocument . load ( formPdfBytes )
// Embed the Mario and emblem images
const marioImage = await pdfDoc . embedPng ( marioImageBytes )
const emblemImage = await pdfDoc . embedPng ( emblemImageBytes )
// Get the form containing all the fields
const form = pdfDoc . getForm ( )
// Get all fields in the PDF by their names
const nameField = form . getTextField ( 'CharacterName 2' )
const ageField = form . getTextField ( 'Age' )
const heightField = form . getTextField ( 'Height' )
const weightField = form . getTextField ( 'Weight' )
const eyesField = form . getTextField ( 'Eyes' )
const skinField = form . getTextField ( 'Skin' )
const hairField = form . getTextField ( 'Hair' )
const alliesField = form . getTextField ( 'Allies' )
const factionField = form . getTextField ( 'FactionName' )
const backstoryField = form . getTextField ( 'Backstory' )
const traitsField = form . getTextField ( 'Feat+Traits' )
const treasureField = form . getTextField ( 'Treasure' )
const characterImageField = form . getButton ( 'CHARACTER IMAGE' )
const factionImageField = form . getTextField ( 'Faction Symbol Image' )
// Fill in the basic info fields
nameField . setText ( 'Mario' )
ageField . setText ( '24 years' )
heightField . setText ( `5' 1"` )
weightField . setText ( '196 lbs' )
eyesField . setText ( 'blue' )
skinField . setText ( 'white' )
hairField . setText ( 'brown' )
// Fill the character image field with our Mario image
characterImageField . setImage ( marioImage )
// Fill in the allies field
alliesField . setText (
[
`Allies:` ,
` • Princess Daisy` ,
` • Princess Peach` ,
` • Rosalina` ,
` • Geno` ,
` • Luigi` ,
` • Donkey Kong` ,
` • Yoshi` ,
` • Diddy Kong` ,
`` ,
`Organizations:` ,
` • Italian Plumbers Association` ,
] . join ( 'n' ) ,
)
// Fill in the faction name field
factionField . setText ( `Mario's Emblem` )
// Fill the faction image field with our emblem image
factionImageField . setImage ( emblemImage )
// Fill in the backstory field
backstoryField . setText (
`Mario is a fictional character in the Mario video game franchise, owned by Nintendo and created by Japanese video game designer Shigeru Miyamoto. Serving as the company's mascot and the eponymous protagonist of the series, Mario has appeared in over 200 video games since his creation. Depicted as a short, pudgy, Italian plumber who resides in the Mushroom Kingdom, his adventures generally center upon rescuing Princess Peach from the Koopa villain Bowser. His younger brother and sidekick is Luigi.` ,
)
// Fill in the traits field
traitsField . setText (
[
`Mario can use three basic three power-ups:` ,
` • the Super Mushroom, which causes Mario to grow larger` ,
` • the Fire Flower, which allows Mario to throw fireballs` ,
` • the Starman, which gives Mario temporary invincibility` ,
] . join ( 'n' ) ,
)
// Fill in the treasure field
treasureField . setText ( [ '• Gold coins' , '• Treasure chests' ] . join ( 'n' ) )
// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc . save ( )
// For example, `pdfBytes` can be:
// • Written to a file in Node
// • Downloaded from the browser
// • Rendered in an <iframe>
ينتج عن هذا المثال ملف PDF هذا (عند استخدام ملف PDF هذا لمتغير formPdfBytes
).
جرب العرض التوضيحي لـ JSFiddle
import { PDFDocument } from 'pdf-lib'
// This should be a Uint8Array or ArrayBuffer
// This data can be obtained in a number of different ways
// If your running in a Node environment, you could use fs.readFile()
// In the browser, you could make a fetch() call and use res.arrayBuffer()
const formPdfBytes = ...
// Load a PDF with form fields
const pdfDoc = await PDFDocument . load ( formPdfBytes )
// Get the form containing all the fields
const form = pdfDoc . getForm ( )
// Fill the form's fields
form . getTextField ( 'Text1' ) . setText ( 'Some Text' ) ;
form . getRadioGroup ( 'Group2' ) . select ( 'Choice1' ) ;
form . getRadioGroup ( 'Group3' ) . select ( 'Choice3' ) ;
form . getRadioGroup ( 'Group4' ) . select ( 'Choice1' ) ;
form . getCheckBox ( 'Check Box3' ) . check ( ) ;
form . getCheckBox ( 'Check Box4' ) . uncheck ( ) ;
form . getDropdown ( 'Dropdown7' ) . select ( 'Infinity' ) ;
form . getOptionList ( 'List Box6' ) . select ( 'Honda' ) ;
// Flatten the form's fields
form . flatten ( ) ;
// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc . save ( )
// For example, `pdfBytes` can be:
// • Written to a file in Node
// • Downloaded from the browser
// • Rendered in an <iframe>
ينتج عن هذا المثال ملف PDF هذا (عند استخدام ملف PDF هذا لمتغير firstDonorPdfBytes
ويتم استخدام ملف PDF هذا لمتغير secondDonorPdfBytes
).
جرب العرض التوضيحي لـ JSFiddle
import { PDFDocument } from 'pdf-lib'
// Create a new PDFDocument
const pdfDoc = await PDFDocument . create ( )
// These should be Uint8Arrays or ArrayBuffers
// This data can be obtained in a number of different ways
// If your running in a Node environment, you could use fs.readFile()
// In the browser, you could make a fetch() call and use res.arrayBuffer()
const firstDonorPdfBytes = ...
const secondDonorPdfBytes = ...
// Load a PDFDocument from each of the existing PDFs
const firstDonorPdfDoc = await PDFDocument . load ( firstDonorPdfBytes )
const secondDonorPdfDoc = await PDFDocument . load ( secondDonorPdfBytes )
// Copy the 1st page from the first donor document, and
// the 743rd page from the second donor document
const [ firstDonorPage ] = await pdfDoc . copyPages ( firstDonorPdfDoc , [ 0 ] )
const [ secondDonorPage ] = await pdfDoc . copyPages ( secondDonorPdfDoc , [ 742 ] )
// Add the first copied page
pdfDoc . addPage ( firstDonorPage )
// Insert the second copied page to index 0, so it will be the
// first page in `pdfDoc`
pdfDoc . insertPage ( 0 , secondDonorPage )
// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc . save ( )
// For example, `pdfBytes` can be:
// • Written to a file in Node
// • Downloaded from the browser
// • Rendered in an <iframe>
ينتج عن هذا المثال ملف PDF هذا (عند استخدام هذه الصورة لمتغير jpgImageBytes
ويتم استخدام هذه الصورة لمتغير pngImageBytes
).
جرب العرض التوضيحي لـ JSFiddle
import { PDFDocument } from 'pdf-lib'
// These should be Uint8Arrays or ArrayBuffers
// This data can be obtained in a number of different ways
// If your running in a Node environment, you could use fs.readFile()
// In the browser, you could make a fetch() call and use res.arrayBuffer()
const jpgImageBytes = ...
const pngImageBytes = ...
// Create a new PDFDocument
const pdfDoc = await PDFDocument . create ( )
// Embed the JPG image bytes and PNG image bytes
const jpgImage = await pdfDoc . embedJpg ( jpgImageBytes )
const pngImage = await pdfDoc . embedPng ( pngImageBytes )
// Get the width/height of the JPG image scaled down to 25% of its original size
const jpgDims = jpgImage . scale ( 0.25 )
// Get the width/height of the PNG image scaled down to 50% of its original size
const pngDims = pngImage . scale ( 0.5 )
// Add a blank page to the document
const page = pdfDoc . addPage ( )
// Draw the JPG image in the center of the page
page . drawImage ( jpgImage , {
x : page . getWidth ( ) / 2 - jpgDims . width / 2 ,
y : page . getHeight ( ) / 2 - jpgDims . height / 2 ,
width : jpgDims . width ,
height : jpgDims . height ,
} )
// Draw the PNG image near the lower right corner of the JPG image
page . drawImage ( pngImage , {
x : page . getWidth ( ) / 2 - pngDims . width / 2 + 75 ,
y : page . getHeight ( ) / 2 - pngDims . height ,
width : pngDims . width ,
height : pngDims . height ,
} )
// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc . save ( )
// For example, `pdfBytes` can be:
// • Written to a file in Node
// • Downloaded from the browser
// • Rendered in an <iframe>
ينتج عن هذا المثال ملف PDF هذا (عند استخدام ملف PDF هذا للمتغير americanFlagPdfBytes
ويتم استخدام ملف PDF هذا للمتغير usConstitutionPdfBytes
).
جرب العرض التوضيحي لـ JSFiddle
import { PDFDocument } from 'pdf-lib'
// These should be Uint8Arrays or ArrayBuffers
// This data can be obtained in a number of different ways
// If your running in a Node environment, you could use fs.readFile()
// In the browser, you could make a fetch() call and use res.arrayBuffer()
const americanFlagPdfBytes = ...
const usConstitutionPdfBytes = ...
// Create a new PDFDocument
const pdfDoc = await PDFDocument . create ( )
// Embed the American flag PDF bytes
const [ americanFlag ] = await pdfDoc . embedPdf ( americanFlagPdfBytes )
// Load the U.S. constitution PDF bytes
const usConstitutionPdf = await PDFDocument . load ( usConstitutionPdfBytes )
// Embed the second page of the constitution and clip the preamble
const preamble = await pdfDoc . embedPage ( usConstitutionPdf . getPages ( ) [ 1 ] , {
left : 55 ,
bottom : 485 ,
right : 300 ,
top : 575 ,
} )
// Get the width/height of the American flag PDF scaled down to 30% of
// its original size
const americanFlagDims = americanFlag . scale ( 0.3 )
// Get the width/height of the preamble clipping scaled up to 225% of
// its original size
const preambleDims = preamble . scale ( 2.25 )
// Add a blank page to the document
const page = pdfDoc . addPage ( )
// Draw the American flag image in the center top of the page
page . drawPage ( americanFlag , {
... americanFlagDims ,
x : page . getWidth ( ) / 2 - americanFlagDims . width / 2 ,
y : page . getHeight ( ) - americanFlagDims . height - 150 ,
} )
// Draw the preamble clipping in the center bottom of the page
page . drawPage ( preamble , {
... preambleDims ,
x : page . getWidth ( ) / 2 - preambleDims . width / 2 ,
y : page . getHeight ( ) / 2 - preambleDims . height / 2 - 50 ,
} )
// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc . save ( )
// For example, `pdfBytes` can be:
// • Written to a file in Node
// • Downloaded from the browser
// • Rendered in an <iframe>
يعتمد pdf-lib
على وحدة شقيقة لدعم تضمين الخطوط المخصصة: @pdf-lib/fontkit
. يجب عليك إضافة وحدة @pdf-lib/fontkit
إلى مشروعك وتسجيلها باستخدام pdfDoc.registerFontkit(...)
قبل تضمين الخطوط المخصصة.
انظر أدناه للحصول على تعليمات التثبيت التفصيلية حول تثبيت
@pdf-lib/fontkit
كوحدة UMD أو NPM.
ينتج عن هذا المثال ملف PDF هذا (عند استخدام هذا الخط لمتغير fontBytes
).
جرب العرض التوضيحي لـ JSFiddle
import { PDFDocument , rgb } from 'pdf-lib'
import fontkit from '@pdf-lib/fontkit'
// This should be a Uint8Array or ArrayBuffer
// This data can be obtained in a number of different ways
// If you're running in a Node environment, you could use fs.readFile()
// In the browser, you could make a fetch() call and use res.arrayBuffer()
const fontBytes = ...
// Create a new PDFDocument
const pdfDoc = await PDFDocument . create ( )
// Register the `fontkit` instance
pdfDoc . registerFontkit ( fontkit )
// Embed our custom font in the document
const customFont = await pdfDoc . embedFont ( fontBytes )
// Add a blank page to the document
const page = pdfDoc . addPage ( )
// Create a string of text and measure its width and height in our custom font
const text = 'This is text in an embedded font!'
const textSize = 35
const textWidth = customFont . widthOfTextAtSize ( text , textSize )
const textHeight = customFont . heightAtSize ( textSize )
// Draw the string of text on the page
page . drawText ( text , {
x : 40 ,
y : 450 ,
size : textSize ,
font : customFont ,
color : rgb ( 0 , 0.53 , 0.71 ) ,
} )
// Draw a box around the string of text
page . drawRectangle ( {
x : 40 ,
y : 450 ,
width : textWidth ,
height : textHeight ,
borderColor : rgb ( 1 , 0 , 0 ) ,
borderWidth : 1.5 ,
} )
// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc . save ( )
// For example, `pdfBytes` can be:
// • Written to a file in Node
// • Downloaded from the browser
// • Rendered in an <iframe>
ينتج عن هذا المثال ملف PDF هذا (عند استخدام هذه الصورة لمتغير jpgAttachmentBytes
ويتم استخدام ملف PDF هذا لمتغير pdfAttachmentBytes
).
جرب العرض التوضيحي لـ JSFiddle
import { PDFDocument } from 'pdf-lib'
// These should be Uint8Arrays or ArrayBuffers
// This data can be obtained in a number of different ways
// If your running in a Node environment, you could use fs.readFile()
// In the browser, you could make a fetch() call and use res.arrayBuffer()
const jpgAttachmentBytes = ...
const pdfAttachmentBytes = ...
// Create a new PDFDocument
const pdfDoc = await PDFDocument . create ( )
// Add the JPG attachment
await pdfDoc . attach ( jpgAttachmentBytes , 'cat_riding_unicorn.jpg' , {
mimeType : 'image/jpeg' ,
description : 'Cool cat riding a unicorn! ???️' ,
creationDate : new Date ( '2019/12/01' ) ,
modificationDate : new Date ( '2020/04/19' ) ,
} )
// Add the PDF attachment
await pdfDoc . attach ( pdfAttachmentBytes , 'us_constitution.pdf' , {
mimeType : 'application/pdf' ,
description : 'Constitution of the United States ???' ,
creationDate : new Date ( '1787/09/17' ) ,
modificationDate : new Date ( '1992/05/07' ) ,
} )
// Add a page with some text
const page = pdfDoc . addPage ( ) ;
page . drawText ( 'This PDF has two attachments' , { x : 135 , y : 415 } )
// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc . save ( )
// For example, `pdfBytes` can be:
// • Written to a file in Node
// • Downloaded from the browser
// • Rendered in an <iframe>
ينتج عن هذا المثال ملف PDF هذا .
جرب العرض التوضيحي لـ JSFiddle
import { PDFDocument , StandardFonts } from 'pdf-lib'
// Create a new PDFDocument
const pdfDoc = await PDFDocument . create ( )
// Embed the Times Roman font
const timesRomanFont = await pdfDoc . embedFont ( StandardFonts . TimesRoman )
// Add a page and draw some text on it
const page = pdfDoc . addPage ( [ 500 , 600 ] )
page . setFont ( timesRomanFont )
page . drawText ( 'The Life of an Egg' , { x : 60 , y : 500 , size : 50 } )
page . drawText ( 'An Epic Tale of Woe' , { x : 125 , y : 460 , size : 25 } )
// Set all available metadata fields on the PDFDocument. Note that these fields
// are visible in the "Document Properties" section of most PDF readers.
pdfDoc . setTitle ( '? The Life of an Egg ?' )
pdfDoc . setAuthor ( 'Humpty Dumpty' )
pdfDoc . setSubject ( ' An Epic Tale of Woe ' )
pdfDoc . setKeywords ( [ 'eggs' , 'wall' , 'fall' , 'king' , 'horses' , 'men' ] )
pdfDoc . setProducer ( 'PDF App 9000 ?' )
pdfDoc . setCreator ( 'pdf-lib (https://github.com/Hopding/pdf-lib)' )
pdfDoc . setCreationDate ( new Date ( '2018-06-24T01:58:37.228Z' ) )
pdfDoc . setModificationDate ( new Date ( '2019-12-21T07:00:11.000Z' ) )
// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc . save ( )
// For example, `pdfBytes` can be:
// • Written to a file in Node
// • Downloaded from the browser
// • Rendered in an <iframe>
جرب العرض التوضيحي لـ JSFiddle
import { PDFDocument } from 'pdf-lib'
// This should be a Uint8Array or ArrayBuffer
// This data can be obtained in a number of different ways
// If your running in a Node environment, you could use fs.readFile()
// In the browser, you could make a fetch() call and use res.arrayBuffer()
const existingPdfBytes = ...
// Load a PDFDocument without updating its existing metadata
const pdfDoc = await PDFDocument . load ( existingPdfBytes , {
updateMetadata : false
} )
// Print all available metadata fields
console . log ( 'Title:' , pdfDoc . getTitle ( ) )
console . log ( 'Author:' , pdfDoc . getAuthor ( ) )
console . log ( 'Subject:' , pdfDoc . getSubject ( ) )
console . log ( 'Creator:' , pdfDoc . getCreator ( ) )
console . log ( 'Keywords:' , pdfDoc . getKeywords ( ) )
console . log ( 'Producer:' , pdfDoc . getProducer ( ) )
console . log ( 'Creation Date:' , pdfDoc . getCreationDate ( ) )
console . log ( 'Modification Date:' , pdfDoc . getModificationDate ( ) )
يقوم هذا البرنامج النصي بإخراج ما يلي ( عند استخدام ملف PDF هذا لمتغير existingPdfBytes
):
Title: Microsoft Word - Basic Curriculum Vitae example.doc
Author: Administrator
Subject: undefined
Creator: PScript5.dll Version 5.2
Keywords: undefined
Producer: Acrobat Distiller 8.1.0 (Windows)
Creation Date: 2010-07-29T14:26:00.000Z
Modification Date: 2010-07-29T14:26:00.000Z
import {
PDFDocument ,
StandardFonts ,
NonFullScreenPageMode ,
ReadingDirection ,
PrintScaling ,
Duplex ,
PDFName ,
} from 'pdf-lib'
// Create a new PDFDocument
const pdfDoc = await PDFDocument . create ( )
// Embed the Times Roman font
const timesRomanFont = await pdfDoc . embedFont ( StandardFonts . TimesRoman )
// Add a page and draw some text on it
const page = pdfDoc . addPage ( [ 500 , 600 ] )
page . setFont ( timesRomanFont )
page . drawText ( 'The Life of an Egg' , { x : 60 , y : 500 , size : 50 } )
page . drawText ( 'An Epic Tale of Woe' , { x : 125 , y : 460 , size : 25 } )
// Set all available viewer preferences on the PDFDocument:
const viewerPrefs = pdfDoc . catalog . getOrCreateViewerPreferences ( )
viewerPrefs . setHideToolbar ( true )
viewerPrefs . setHideMenubar ( true )
viewerPrefs . setHideWindowUI ( true )
viewerPrefs . setFitWindow ( true )
viewerPrefs . setCenterWindow ( true )
viewerPrefs . setDisplayDocTitle ( true )
// Set the PageMode (otherwise setting NonFullScreenPageMode has no meaning)
pdfDoc . catalog . set ( PDFName . of ( 'PageMode' ) , PDFName . of ( 'FullScreen' ) )
// Set what happens when fullScreen is closed
viewerPrefs . setNonFullScreenPageMode ( NonFullScreenPageMode . UseOutlines )
viewerPrefs . setReadingDirection ( ReadingDirection . L2R )
viewerPrefs . setPrintScaling ( PrintScaling . None )
viewerPrefs . setDuplex ( Duplex . DuplexFlipLongEdge )
viewerPrefs . setPickTrayByPDFSize ( true )
// We can set the default print range to only the first page
viewerPrefs . setPrintPageRange ( { start : 0 , end : 0 } )
// Or we can supply noncontiguous ranges (e.g. pages 1, 3, and 5-7)
viewerPrefs . setPrintPageRange ( [
{ start : 0 , end : 0 } ,
{ start : 2 , end : 2 } ,
{ start : 4 , end : 6 } ,
] )
viewerPrefs . setNumCopies ( 2 )
// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc . save ( )
// For example, `pdfBytes` can be:
// • Written to a file in Node
// • Downloaded from the browser
// • Rendered in an <iframe>
import { PDFDocument } from 'pdf-lib'
// This should be a Uint8Array or ArrayBuffer
// This data can be obtained in a number of different ways
// If your running in a Node environment, you could use fs.readFile()
// In the browser, you could make a fetch() call and use res.arrayBuffer()
const existingPdfBytes = ...
// Load a PDFDocument without updating its existing metadata
const pdfDoc = await PDFDocument . load ( existingPdfBytes )
const viewerPrefs = pdfDoc . catalog . getOrCreateViewerPreferences ( )
// Print all available viewer preference fields
console . log ( 'HideToolbar:' , viewerPrefs . getHideToolbar ( ) )
console . log ( 'HideMenubar:' , viewerPrefs . getHideMenubar ( ) )
console . log ( 'HideWindowUI:' , viewerPrefs . getHideWindowUI ( ) )
console . log ( 'FitWindow:' , viewerPrefs . getFitWindow ( ) )
console . log ( 'CenterWindow:' , viewerPrefs . getCenterWindow ( ) )
console . log ( 'DisplayDocTitle:' , viewerPrefs . getDisplayDocTitle ( ) )
console . log ( 'NonFullScreenPageMode:' , viewerPrefs . getNonFullScreenPageMode ( ) )
console . log ( 'ReadingDirection:' , viewerPrefs . getReadingDirection ( ) )
console . log ( 'PrintScaling:' , viewerPrefs . getPrintScaling ( ) )
console . log ( 'Duplex:' , viewerPrefs . getDuplex ( ) )
console . log ( 'PickTrayByPDFSize:' , viewerPrefs . getPickTrayByPDFSize ( ) )
console . log ( 'PrintPageRange:' , viewerPrefs . getPrintPageRange ( ) )
console . log ( 'NumCopies:' , viewerPrefs . getNumCopies ( ) )
يقوم هذا البرنامج النصي بإخراج ما يلي ( عند استخدام ملف PDF هذا لمتغير existingPdfBytes
):
HideToolbar: true
HideMenubar: true
HideWindowUI: false
FitWindow: true
CenterWindow: true
DisplayDocTitle: true
NonFullScreenPageMode: UseNone
ReadingDirection: R2L
PrintScaling: None
Duplex: DuplexFlipLongEdge
PickTrayByPDFSize: true
PrintPageRange: [ { start: 1, end: 1 }, { start: 3, end: 4 } ]
NumCopies: 2
ينتج عن هذا المثال ملف PDF هذا .
جرب العرض التوضيحي لـ JSFiddle
import { PDFDocument , rgb } from 'pdf-lib'
// SVG path for a wavy line
const svgPath =
'M 0,20 L 100,160 Q 130,200 150,120 C 190,-40 200,200 300,150 L 400,90'
// Create a new PDFDocument
const pdfDoc = await PDFDocument . create ( )
// Add a blank page to the document
const page = pdfDoc . addPage ( )
page . moveTo ( 100 , page . getHeight ( ) - 5 )
// Draw the SVG path as a black line
page . moveDown ( 25 )
page . drawSvgPath ( svgPath )
// Draw the SVG path as a thick green line
page . moveDown ( 200 )
page . drawSvgPath ( svgPath , { borderColor : rgb ( 0 , 1 , 0 ) , borderWidth : 5 } )
// Draw the SVG path and fill it with red
page . moveDown ( 200 )
page . drawSvgPath ( svgPath , { color : rgb ( 1 , 0 , 0 ) } )
// Draw the SVG path at 50% of its original size
page . moveDown ( 200 )
page . drawSvgPath ( svgPath , { scale : 0.5 } )
// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc . save ( )
// For example, `pdfBytes` can be:
// • Written to a file in Node
// • Downloaded from the browser
// • Rendered in an <iframe>
pdf-lib
يدعم بشكل كامل وقت تشغيل Deno الجديد والمثير! جميع أمثلة الاستخدام تعمل في Deno. الشيء الوحيد الذي عليك القيام به هو تغيير عمليات الاستيراد لـ 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
في بيئات العقدة. تعد هذه الاختبارات مرجعًا مفيدًا عند محاولة حفظ/تحميل ملفات 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 أو الغزل كمدير للحزم لديك.
يمكنك أيضًا تنزيل 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 )
وثائق واجهة برمجة التطبيقات متاحة على موقع المشروع على 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
. عندما تقوم بتضمين الخط الخاص بك، يمكنك استخدام أي أحرف Unicode يدعمها. تحررك هذه الإمكانية من القيود التي تفرضها الخطوط القياسية. تستخدم معظم ملفات PDF الخطوط المضمنة. يمكنك تضمين واستخدام خط مخصص مثل ذلك (انظر أيضًا): import { PDFDocument } from 'pdf-lib'
import fontkit from '@pdf-lib/fontkit'
const url = 'https://pdf-lib.js.org/assets/ubuntu/Ubuntu-R.ttf'
const fontBytes = await fetch ( url ) . then ( ( res ) => res . arrayBuffer ( ) )
const pdfDoc = await PDFDocument . create ( )
pdfDoc . registerFontkit ( fontkit )
const ubuntuFont = await pdfDoc . embedFont ( fontBytes )
const page = pdfDoc . addPage ( )
page . drawText ( 'Some fancy Unicode text in the ŪЬȕǹƚü font' , {
font : ubuntuFont ,
} )
لاحظ أنه سيتم ظهور أخطاء الترميز إذا حاولت استخدام حرف بخط لا يدعمه. على سبيل المثال، Ω
غير موجود في مجموعة أحرف WinAnsi. لذا فإن محاولة رسمه على صفحة باستخدام خط Helvetica القياسي سيؤدي إلى ظهور الخطأ التالي:
Error: WinAnsi cannot encode "Ω" (0x03a9)
at Encoding.encodeUnicodeCodePoint
عادةً ما يؤدي تضمين خط في مستند PDF إلى زيادة حجم الملف. يمكنك تقليل مقدار زيادة حجم الملف عن طريق تعيين الخط فرعيًا بحيث يتم تضمين الأحرف الضرورية فقط. يمكنك تعيين خط فرعي عن طريق ضبط خيار subset
على true
. على سبيل المثال:
const font = await pdfDoc . embedFont ( fontBytes , { subset : true } ) ;
لاحظ أن الإعداد الفرعي لا يعمل مع كافة الخطوط. انظر رقم 207 (تعليق) لمزيد من التفاصيل.
يمكن لـ pdf-lib
إنشاء حقول نماذج PDF وملؤها وقراءتها. يتم دعم أنواع الحقول التالية:
راجع أمثلة استخدام إنشاء النموذج وملء النموذج للحصول على نماذج التعليمات البرمجية. تحتوي الاختبارات 1 و14 و15 و16 و17 في الأمثلة الكاملة على رمز مثال عملي لإنشاء النموذج وملء مجموعة متنوعة من بيئات JS المختلفة.
هام: الخط الافتراضي المستخدم لعرض النص في الأزرار والقوائم المنسدلة وقوائم الخيارات وحقول النص هو خط Helvetica القياسي. يدعم هذا الخط الحروف الأبجدية اللاتينية فقط (راجع الخطوط وUnicode للحصول على التفاصيل). وهذا يعني أنه إذا تم إنشاء أي من أنواع الحقول هذه أو تعديلها لتحتوي على نص خارج الأبجدية اللاتينية (كما هو الحال غالبًا)، فستحتاج إلى تضمين خط مخصص واستخدامه لتحديث مظاهر الحقول. وإلا فسيتم ظهور خطأ (على الأرجح عند حفظ ملف PDFDocument
).
يمكنك استخدام الخط المضمن عند ملء حقول النموذج كما يلي:
import { PDFDocument } from 'pdf-lib' ;
import fontkit from '@pdf-lib/fontkit' ;
// Fetch the PDF with form fields
const formUrl = 'https://pdf-lib.js.org/assets/dod_character.pdf' ;
const formBytes = await fetch ( formUrl ) . then ( ( res ) => res . arrayBuffer ( ) ) ;
// Fetch the Ubuntu font
const fontUrl = 'https://pdf-lib.js.org/assets/ubuntu/Ubuntu-R.ttf' ;
const fontBytes = await fetch ( fontUrl ) . then ( ( res ) => res . arrayBuffer ( ) ) ;
// Load the PDF with form fields
const pdfDoc = await PDFDocument . load ( formBytes ) ;
// Embed the Ubuntu font
pdfDoc . registerFontkit ( fontkit ) ;
const ubuntuFont = await pdfDoc . embedFont ( fontBytes ) ;
// Get two text fields from the form
const form = pdfDoc . getForm ( ) ;
const nameField = form . getTextField ( 'CharacterName 2' ) ;
const ageField = form . getTextField ( 'Age' ) ;
// Fill the text fields with some fancy Unicode characters (outside
// the WinAnsi latin character set)
nameField . setText ( 'Ӎӑȑїõ' ) ;
ageField . setText ( '24 ŷȇȁŗš' ) ;
// **Key Step:** Update the field appearances with the Ubuntu font
form . updateFieldAppearances ( ubuntuFont ) ;
// Save the PDF with filled form fields
const pdfBytes = await pdfDoc . save ( ) ;
يمكن الوصول إلى حقول النموذج الموجودة بالطرق التالية في PDFForm
:
PDFForm.getButton
PDFForm.getCheckBox
PDFForm.getDropdown
PDFForm.getOptionList
PDFForm.getRadioGroup
PDFForm.getTextField
يمكن إنشاء حقول نموذج جديدة بالطرق التالية في PDFForm
:
PDFForm.createButton
PDFForm.createCheckBox
PDFForm.createDropdown
PDFForm.createOptionList
PDFForm.createRadioGroup
PDFForm.createTextField
فيما يلي بعض الطرق الأكثر استخدامًا لقراءة وملء الفئات الفرعية المذكورة أعلاه لـ PDFField
:
PDFCheckBox.check
PDFCheckBox.uncheck
PDFCheckBox.isChecked
PDFDropdown.select
PDFDropdown.clear
PDFDropdown.getSelected
PDFDropdown.getOptions
PDFDropdown.addOptions
PDFOptionList.select
PDFOptionList.clear
PDFOptionList.getSelected
PDFOptionList.getOptions
PDFOptionList.addOptions
PDFRadioGroup.select
PDFRadioGroup.clear
PDFRadioGroup.getSelected
PDFRadioGroup.getOptions
PDFRadioGroup.addOptionToPage
PDFTextField.setText
PDFTextField.getText
PDFTextField.setMaxLength
PDFTextField.getMaxLength
PDFTextField.removeMaxLength
pdf-lib
استخراج محتوى الحقول النصية (راجع PDFTextField.getText
)، لكن لا يمكنه استخراج نص عادي في صفحة خارج حقل النموذج. هذه ميزة يصعب تنفيذها، ولكنها تقع ضمن نطاق هذه المكتبة ويمكن إضافتها إلى pdf-lib
في المستقبل. انظر الأرقام 93، و137، و177، و329، و380.pdf-lib
إزالة محتوى الحقول النصية وتحريرها (راجع PDFTextField.setText
)، ولكنه لا يوفر واجهات برمجة التطبيقات لإزالة النص أو تحريره على صفحة خارج حقل النموذج. تعد هذه أيضًا ميزة صعبة التنفيذ، ولكنها تقع ضمن نطاق pdf-lib
ويمكن إضافتها في المستقبل. انظر الأرقام 93، و137، و177، و329، و380.pdf-lib
استخدام HTML أو CSS عند إضافة محتوى إلى ملف PDF. وبالمثل، لا يمكن pdf-lib
تضمين محتوى HTML/CSS في ملفات PDF. على الرغم من أن هذه الميزة قد تكون ملائمة، إلا أنه سيكون من الصعب للغاية تنفيذها وهي خارج نطاق هذه المكتبة. إذا كنت بحاجة إلى هذه الإمكانية، ففكر في استخدام محرك الدمى. المناقشات هي أفضل مكان للدردشة معنا وطرح الأسئلة ومعرفة المزيد عن 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 للحصول على تفاصيل حول كيفية الحفاظ على هذا الريبو وكيفية استخدامنا للقضايا والعلاقات العامة والمناقشات.
pdfkit
هي مكتبة إنشاء PDF للعقدة والمتصفح. كانت هذه المكتبة مفيدة للغاية كمرجع ودليل على الوجود عند إنشاء pdf-lib
. كان كود pdfkit
لتضمين الخطوط، وتضمين PNG، وتضمين JPG مفيدًا بشكل خاص.pdf.js
هي مكتبة عرض PDF للمتصفح. كانت هذه المكتبة مفيدة كمرجع عند كتابة محلل pdf-lib
. تم نقل بعض التعليمات البرمجية الخاصة بفك تشفير الدفق مباشرة إلى TypeScript لاستخدامها في pdf-lib
.pdfbox
هي مكتبة لإنشاء ملفات PDF وتعديلها مكتوبة بلغة Java. كانت هذه المكتبة مرجعًا لا يقدر بثمن عند تنفيذ إنشاء النماذج وملء واجهات برمجة التطبيقات لـ pdf-lib
.jspdf
هي مكتبة إنشاء ملفات PDF للمتصفح.pdfmake
هي مكتبة إنشاء PDF للمتصفح.hummus
عبارة عن مكتبة لإنشاء ملفات PDF وتعديلها لبيئات العقدة. hummus
عبارة عن غلاف عقدة حول مكتبة C++، لذا فهو لا يعمل في العديد من بيئات JavaScript - مثل المتصفح أو React Native.react-native-pdf-lib
عبارة عن مكتبة لإنشاء ملفات PDF وتعديلها لبيئات React Native. react-native-pdf-lib
عبارة عن غلاف حول مكتبات C++ وJava.pdfassembler
عبارة عن مكتبة لإنشاء ملفات PDF وتعديلها للعقدة والمتصفح. يتطلب الأمر بعض المعرفة حول البنية المنطقية لمستندات PDF لاستخدامها. يستخدم هذا الريبو ليحتوي على ملف يسمى pdf_specification.pdf
في الدليل الجذر. كانت هذه نسخة من مواصفات PDF 1.7، والتي تم توفيرها مجانًا بواسطة Adobe. في 30/8/2021، تلقينا شكوى بموجب قانون الألفية الجديدة لحقوق طبع ونشر المواد الرقمية تطالبنا بإزالة الملف من هذا الريبو. إن مجرد إزالة الملف عبر التزام جديد 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
و/أو لديك علاقات عامة مفتوحة)، فإن هذا يؤثر عليك. إذا قمت بتقسيم الريبو أو استنساخه قبل 30/8/2021، فإن سجل git الخاص بالشوكة الخاص بك غير متزامن مع الفرع master
لهذا الريبو. لسوء الحظ، من المحتمل أن يكون هذا بمثابة صداع بالنسبة لك للتعامل معه. آسف! لم نرغب في إعادة كتابة التاريخ، لكن لم يكن هناك بديل حقًا.
من المهم ملاحظة أن الكود المصدري لـ pdf-lib لم يتغير على الإطلاق. إنه تمامًا كما كان قبل إعادة كتابة سجل git. لا يزال الريبو يحتوي على نفس عدد الالتزامات (وحتى نفس محتويات الالتزام، باستثناء الالتزام الذي أضاف pdf_specification.pdf
). ما تغير هو SHAs لتلك الالتزامات.
إن أبسط طريقة للتعامل مع هذه الحقيقة هي:
راجع إجابة StackOverflow هذه للحصول على شرح رائع ومتعمق لما تستلزمه إعادة كتابة سجل git.
معهد ماساتشوستس للتكنولوجيا