Commit 90c80bb9 by Alex Pounds

Support for readbyte in Paperclip attachments; better documentation of custom processors.

I recently implemented a custom processor that used the Exifr gem to
extract EXIF information from images uploaded to a Paperclip attachment.
Exifr's processor uses readbyte to parse the EXIF header, so it hit
errors when Paperclip's File-like object didn't have one. There's also a
test for this delegation.

I've also tidied up the README documentation for custom processors,
hopefully to be more clear than before. There was some duplicated
content between the "Post Processing" section and the "Custom Attachment
Processing" section, and those sections were separated in the file. I've
dedicated the "Post Processing" section to Paperclip's built in
thumbnailing processors, and made "Custom Attachment Processing" section
solely about writing & using your own custom processors. This should be
a more understandable progression, as built-in functionality is
discussed first & separately from extending Paperclip.k
parent e367efc2
......@@ -43,11 +43,11 @@ https://github.com/thoughtbot/paperclip/releases
- [Storage](#storage)
- [Understanding Storage](#understanding-storage)
- [Post Processing](#post-processing)
- [Custom Attachment Processors](#custom-attachment-processors)
- [Events](#events)
- [URI Obfuscation](#uri-obfuscation)
- [MD5 Checksum / Fingerprint](#md5-checksum--fingerprint)
- [File Preservation for Soft-Delete](#file-preservation-for-soft-delete)
- [Custom Attachment Processors](#custom-attachment-processors)
- [Dynamic Configuration](#dynamic-configuration)
- [Dynamic Styles:](#dynamic-styles)
- [Dynamic Processors:](#dynamic-processors)
......@@ -602,60 +602,72 @@ Post Processing
Paperclip supports an extensible selection of post-processors. When you define
a set of styles for an attachment, by default it is expected that those
"styles" are actually "thumbnails." However, you can do much more than just
thumbnail images. By defining a subclass of Paperclip::Processor, you can
perform any processing you want on the files that are attached. Any file in
your Rails app's `lib/paperclip` and `lib/paperclip_processors` directories is
automatically loaded by Paperclip, allowing you to easily define custom
processors. You can specify a processor with the `:processors` option to
`has_attached_file`:
"styles" are actually "thumbnails." These are processed by
`Paperclip::Thumbnail`. For backward compatibility reasons you can pass either
a single geometry string, or an array containing a geometry and a format that
the file will be converted to, like so:
```ruby
has_attached_file :scan, styles: { text: { quality: :better } },
processors: [:ocr]
has_attached_file :avatar, styles: { thumb: ["32x32#", :png] }
```
This would load the hypothetical class Paperclip::Ocr, which would have the
hash "{ quality: :better }" passed to it along with the uploaded file. For
more information about defining processors, see
[Paperclip::Processor](https://github.com/thoughtbot/paperclip/blob/master/lib/paperclip/processor.rb).
This will convert the "thumb" style to a 32x32 square in PNG format, regardless
of what was uploaded. If the format is not specified, it is kept the same (e.g.
JPGs will remain JPGs). `Paperclip::Thumbnail` uses ImageMagick to process
images; [ImageMagick's geometry documentation](http://www.imagemagick.org/script/command-line-processing.php#geometry)
has more information on the accepted style formats.
---
Custom Attachment Processors
-------
The default processor is Paperclip::Thumbnail. For backward compatibility
reasons, you can pass a single geometry string or an array containing a
geometry and a format that the file will be converted to, like so:
You can write your own custom attachment processors to carry out tasks like
adding watermarks, compressing images, or encrypting files. Custom processors
must be defined within the `Paperclip` module, inherit from
`Paperclip::Processor` (see [`lib/paperclip/processor.rb`](https://github.com/thoughtbot/paperclip/blob/master/lib/paperclip/processor.rb)),
and implement a `make` method that returns a `File`. All files in your Rails
app's `lib/paperclip` and `lib/paperclip_processors` directories will be
automatically loaded by Paperclip. Processors are specified using the
`:processors` option to `has_attached_file`:
```ruby
has_attached_file :avatar, styles: { thumb: ["32x32#", :png] }
has_attached_file :scan, styles: { text: { quality: :better } },
processors: [:ocr]
```
This will convert the "thumb" style to a 32x32 square in PNG format, regardless
of what was uploaded. If the format is not specified, it is kept the same (i.e.
JPGs will remain JPGs). For more information on the accepted style formats, see
[here](http://www.imagemagick.org/script/command-line-processing.php#geometry).
This would load the hypothetical class `Paperclip::Ocr`, and pass it the
options hash `{ quality: :better }`, along with the uploaded file.
Multiple processors can be specified, and they will be invoked in the order
they are defined in the `:processors` array. Each successive processor will
be given the result of the previous processor's execution. All processors will
receive the same parameters, which are defined in the `:styles` hash.
For example, assuming we had this definition:
they are defined in the `:processors` array. Each successive processor is given
the result from the previous processor. All processors receive the same
parameters, which are defined in the `:styles` hash. For example, assuming we
had this definition:
```ruby
has_attached_file :scan, styles: { text: { quality: :better } },
processors: [:rotator, :ocr]
```
then both the :rotator processor and the :ocr processor would receive the
options `{ quality: :better }`. This parameter may not mean anything to one
or more or the processors, and they are expected to ignore it.
Both the `:rotator` processor and the `:ocr` processor would receive the
options `{ quality: :better }`. If a processor receives an option it doesn't
recognise, it's expected to ignore it.
_NOTE: Because processors operate by turning the original attachment into the
styles, no processors will be run if there are no styles defined._
If you're interested in caching your thumbnail's width, height and size in the
database, take a look at the [paperclip-meta](https://github.com/teeparham/paperclip-meta) gem.
database, take a look at the [paperclip-meta](https://github.com/teeparham/paperclip-meta)
gem.
Also, if you're interested in generating the thumbnail on-the-fly, you might want
to look into the [attachment_on_the_fly](https://github.com/drpentode/Attachment-on-the-Fly) gem.
to look into the [attachment_on_the_fly](https://github.com/drpentode/Attachment-on-the-Fly)
gem.
Paperclip's thumbnail generator (see [`lib/paperclip/thumbnail.rb`](lib/paperclip/thumbnail.rb))
is implemented as a processor, and may be a good reference for writing your own
processors.
---
......@@ -748,25 +760,6 @@ This will prevent ```some_attachment``` from being wiped out when the model gets
---
Custom Attachment Processors
-------
Custom attachment processors can be implemented and their only requirement is
to inherit from `Paperclip::Processor` (see `lib/paperclip/processor.rb`).
For example, when `:styles` are specified for an image attachment, the
thumbnail processor (see `lib/paperclip/thumbnail.rb`) is loaded without having
to specify it as a `:processor` parameter to `has_attached_file`. When any
other processor is defined, it must be called out in the `:processors`
parameter if it is to be applied to the attachment. The thumbnail processor
uses the ImageMagick `convert` command to do the work of resizing image
thumbnails. It would be easy to create a custom processor that watermarks
an image using ImageMagick's `composite` command. Following the
implementation pattern of the thumbnail processor would be a way to implement a
watermark processor. All kinds of attachment processors can be created;
a few utility examples would be compression and encryption processors.
---
Dynamic Configuration
---------------------
......
......@@ -5,7 +5,7 @@ module Paperclip
OS_RESTRICTED_CHARACTERS = %r{[/:]}
attr_reader :content_type, :original_filename, :size
delegate :binmode, :binmode?, :close, :close!, :closed?, :eof?, :path, :rewind, :unlink, :to => :@tempfile
delegate :binmode, :binmode?, :close, :close!, :closed?, :eof?, :path, :readbyte, :rewind, :unlink, :to => :@tempfile
alias :length :size
def fingerprint
......
......@@ -7,13 +7,14 @@ module Paperclip
# Processors are required to be defined inside the Paperclip module and
# are also required to be a subclass of Paperclip::Processor. There is
# only one method you *must* implement to properly be a subclass:
# #make, but #initialize may also be of use. Both methods accept 3
# #make, but #initialize may also be of use. #initialize accepts 3
# arguments: the file that will be operated on (which is an instance of
# File), a hash of options that were defined in has_attached_file's
# style hash, and the Paperclip::Attachment itself.
# style hash, and the Paperclip::Attachment itself. These are set as
# instance variables that can be used within `#make`.
#
# All #make needs to return is an instance of File (Tempfile is
# acceptable) which contains the results of the processing.
# #make must return an instance of File (Tempfile is acceptable) which
# contains the results of the processing.
#
# See Paperclip.run for more information about using command-line
# utilities from within Processors.
......
......@@ -34,7 +34,7 @@ describe Paperclip::AbstractAdapter do
@adapter.tempfile = stub("Tempfile")
end
[:binmode, :binmode?, :close, :close!, :closed?, :eof?, :path, :rewind, :unlink].each do |method|
[:binmode, :binmode?, :close, :close!, :closed?, :eof?, :path, :readbyte, :rewind, :unlink].each do |method|
it "delegates #{method} to @tempfile" do
@adapter.tempfile.stubs(method)
@adapter.public_send(method)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment