diff --git a/lib/prawn.rb b/lib/prawn.rb
index 05f4aeb78..06b441a3d 100644
--- a/lib/prawn.rb
+++ b/lib/prawn.rb
@@ -61,6 +61,7 @@ def verify_options(accepted, actual)
require_relative 'prawn/images/image'
require_relative 'prawn/images/jpg'
require_relative 'prawn/images/png'
+require_relative 'prawn/embedded_files'
require_relative 'prawn/stamp'
require_relative 'prawn/soft_mask'
require_relative 'prawn/security'
diff --git a/lib/prawn/document.rb b/lib/prawn/document.rb
index 439667d5a..03cd472b7 100644
--- a/lib/prawn/document.rb
+++ b/lib/prawn/document.rb
@@ -55,6 +55,7 @@ class Document
include Prawn::Text
include Prawn::Graphics
include Prawn::Images
+ include Prawn::EmbeddedFiles
include Prawn::Stamp
include Prawn::SoftMask
include Prawn::TransformationStack
diff --git a/lib/prawn/embedded_files.rb b/lib/prawn/embedded_files.rb
new file mode 100644
index 000000000..01af76343
--- /dev/null
+++ b/lib/prawn/embedded_files.rb
@@ -0,0 +1,74 @@
+# frozen_string_literal: true
+
+module Prawn
+ module EmbeddedFiles
+ # include PDF::Core::EmbeddedFiles
+ # Link to PR (https://github.com/prawnpdf/pdf-core/pull/47)
+
+ # Add the file's data from a source to the document. Any kind of data with
+ # a string representation can be embedded.
+ #
+ # Arguments:
+ # src:: path to file, string or an object that responds to #to_str
+ # and #length.
+ #
+ # Options:
+ # :name:: explicit default filename override.
+ # :creation_date:: date when the file was created.
+ # :modification_date:: date when the file was last modified.
+ # :description:: file description.
+ # :hidden:: if true, prevents the file from appearing in the
+ # catalog. (default false)
+ #
+ # Prawn::Document.generate("file1.pdf") do
+ # dice = "#{Prawn::DATADIR}/images/dice.png"
+ # file dice, description: 'Example of an embedded image file'
+ # end
+ #
+ # This method returns an instance of PDF::Core::NameTree::Value
+ # corresponding to the file in the embedded files catalog entry node. If
+ # hidden, then nil is returned.
+ #
+ def file(src, options = {})
+ path = Pathname.new(src)
+ mut_opts = options.dup
+
+ if path.directory?
+ raise ArgumentError, 'Data source can\'t be a directory'
+ elsif path.file?
+ data = path.read
+ mut_opts[:name] ||= src
+ mut_opts[:creation_date] ||= path.birthtime
+ mut_opts[:modification_date] ||= path.mtime
+ else
+ data = src
+ end
+
+ file = EmbeddedFile.new(data, mut_opts)
+ file_obj = file_registry[file.checksum]
+
+ if file_obj.nil?
+ file_obj = file.build_pdf_object(self)
+ file_registry[file.checksum] = file_obj
+ end
+
+ filespec = Filespec.new(file_obj, mut_opts)
+ filespec_obj = filespec.build_pdf_object(self)
+
+ unless filespec.hidden?
+ # Wait for pdf-core PR
+
+ # attach_file(filespec.file_name, filespec_obj)
+ end
+ end
+
+ private
+
+ def file_registry
+ @file_registry ||= {}
+ end
+ end
+end
+
+require_relative 'embedded_files/embedded_file'
+require_relative 'embedded_files/filespec'
diff --git a/lib/prawn/embedded_files/embedded_file.rb b/lib/prawn/embedded_files/embedded_file.rb
new file mode 100644
index 000000000..524092071
--- /dev/null
+++ b/lib/prawn/embedded_files/embedded_file.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require 'digest'
+
+module Prawn
+ module EmbeddedFiles
+ class EmbeddedFile
+ attr_reader :checksum
+
+ def initialize(data, options = {})
+ @creation_date = options[:creation_date]
+ unless @creation_date.is_a?(Time)
+ @creation_date = Time.now.utc
+ end
+
+ @modification_date = options[:modification_date]
+ unless @modification_date.is_a?(Time)
+ @modification_date = Time.now.utc
+ end
+
+ @checksum = Digest::MD5.digest(data)
+ @data = data
+ end
+
+ def build_pdf_object(document)
+ obj = document.ref!(
+ Type: :EmbeddedFile,
+ Params: {
+ CreationDate: creation_date,
+ ModDate: modification_date,
+ CheckSum: PDF::Core::LiteralString.new(checksum),
+ Size: data.length
+ }
+ )
+
+ obj << data
+ obj.stream.compress! if document.compression_enabled?
+ obj
+ end
+
+ private
+
+ attr_reader :data, :creation_date, :modification_date
+ end
+ end
+end
diff --git a/lib/prawn/embedded_files/filespec.rb b/lib/prawn/embedded_files/filespec.rb
new file mode 100644
index 000000000..07b51337b
--- /dev/null
+++ b/lib/prawn/embedded_files/filespec.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require 'digest'
+
+module Prawn
+ module EmbeddedFiles
+ class Filespec
+ attr_reader :file_name
+
+ def initialize(file, options = {})
+ hexdigest = Digest.hexencode(file.data[:Params][:CheckSum])
+ name = options[:name] || hexdigest
+
+ @file_name = PDF::Core::LiteralString.new(name)
+
+ if options[:description]
+ desc_str = options[:description].to_s
+ @description = PDF::Core::LiteralString.new(desc_str)
+ end
+
+ @hidden = options[:hidden]
+ @file = file
+ end
+
+ def hidden?
+ @hidden
+ end
+
+ def build_pdf_object(document)
+ obj = document.ref!(
+ Type: :Filespec,
+ F: file_name,
+ EF: { F: file, UF: file },
+ UF: file_name
+ )
+
+ obj.data[:Desc] = description if description
+ obj
+ end
+
+ private
+
+ attr_reader :file, :description
+ end
+ end
+end