open videos on popup overlay
@@ -0,0 +1,170 @@
|
||||
Imagecache Actions
|
||||
------------------
|
||||
|
||||
Imagecache Actions 7.x-1.x-dev
|
||||
------------------------------
|
||||
|
||||
Imagecache Actions 7.x-1.7
|
||||
--------------------------
|
||||
- [#2671526]: Fatal error on image style flush when image styles are defined in
|
||||
Features.
|
||||
|
||||
Imagecache Actions 7.x-1.6
|
||||
--------------------------
|
||||
- [#2664020]: IE fails to display images whose extension and Content-Type header
|
||||
do not match the actual image type.
|
||||
- [#1591484]: Underlay not working (on IM).
|
||||
- [#2359523]: Follow up to improve help text.
|
||||
- [#2615986] by hargobind: Effect summary in image_styles_admin.module.
|
||||
- Notice: Undefined index: element in theme_coloractions_alpha_summary() (line
|
||||
98 of coloractions\transparency.inc).
|
||||
- Removed superfluous theme entry 'imagecache_subroutine_summary' from
|
||||
autorotate sub module.
|
||||
- [#2080877] by heathdutton: Interlace / Progressive effect.
|
||||
- [#760438] by fietserwin: Resize Overlay / Watermark for ImageMagick.
|
||||
- [#760438] by raintonr, Ace Cooper, ttkaminski, thijsvdanker, fietserwin:
|
||||
Resize Overlay / Watermark (GD only).
|
||||
- [#768980] by idebr, fietserwin: Blur effect.
|
||||
- [#2636314]: 'Import style' can fail on newline characters.
|
||||
- [#2573225]: Resize by percentage not calculating other field.
|
||||
- [#2447419]: Correct erroneous call to module_load_include in
|
||||
imagecache_canvasactions.module.
|
||||
- [#2416805]: Remove reference to non-existent imagecache_coloractions.install.
|
||||
- [#2416805]: remove deprecated jquery attr() and replace with FAPI #states
|
||||
(rounded corners UI form).
|
||||
- [#2580805]: Coding standards corrections.
|
||||
|
||||
|
||||
Imagecache Actions 7.x-1.5 2014-11-29
|
||||
-------------------------------------
|
||||
- [#2366163]: autorotate sometimes doesn't work with ImageMagick.
|
||||
- Text effect: small clean-up of hook_exit().
|
||||
- [#2379359]: image_imagemagick_overlay() passes a stream wrapper to convert.
|
||||
- [#2359523]: Overlay: allow to define offsets from all sides.
|
||||
- [#1717436]: Add effects: color level adjustment and desaturate while retaining
|
||||
alpha.
|
||||
- [#2278233]: Call to undefined function imagecache_actions_get_style_label().
|
||||
- [#2183721]: Duplicate/Export links just edit, they don't duplicate or export.
|
||||
possible solution only.
|
||||
- [#2176727]: New actions: scale / resize by percent.
|
||||
- [#2190759]: hook_image_style_flush(): Prefer silent failure over clear failure.
|
||||
- [#2166715]: Typo causes extra query every page load.
|
||||
- [#2139091]: # sign before HEX in settings form breaks Define canvas action.
|
||||
- [#2085967]: Remove .gitignore from version control.
|
||||
- Text overlay: treat empty texts as normal situation.
|
||||
- [#2003446]: Clean up or remove .install files, adapt .info files.
|
||||
- [1854270-48]: Minor optimization for Posterize.
|
||||
- Refactor: eliminate test warnings and errors.
|
||||
- Refactor: standardize function and parameter naming, function order, doxygen
|
||||
documentation and comments, remove spelling errors in doc and comments.
|
||||
|
||||
|
||||
Imagecache Actions 7.x-1.4 2013-08-24
|
||||
-------------------------------------
|
||||
- [#1778214]: Remove project from image_effects_text_test.info
|
||||
- [#1854270]: Posterize action for file size/bandwidth saving on PNGs.
|
||||
- [#2060173]: Support image labels (introduced by D7.23).
|
||||
- Cleaned up the output of image style export. Id's and help texts are not used
|
||||
on import, so don't have to be exported.
|
||||
- Repaired farbtastic colorpicker. It seems the library invocation changed
|
||||
sometime in history. Rebuilt the color picker form to use #attached libraries
|
||||
and simpler inline script instead. REMOVED the theme function that is now
|
||||
redundant as #attached is a better way than drupal_add_js.
|
||||
- [#1152736]: Support tokens in text actions for images.
|
||||
- [#2025631]: Imagecache Testsuite refers to non-existent permissions.
|
||||
- Drupal.org went from http to https: changed all links in our documentation and
|
||||
code.
|
||||
- Added ImageEffects as other image effect providing module.
|
||||
|
||||
|
||||
Imagecache Actions 7.x-1.3 2013-06-04
|
||||
-------------------------------------
|
||||
- Removed some errors and warnings from the test suite code (but not all).
|
||||
- [#2010560]: Fix spelling for "Update 7001".
|
||||
|
||||
|
||||
Imagecache Actions 7.x-1.2 2013-06-01
|
||||
-------------------------------------
|
||||
- [#1830130]: Allow file fields as referring entities in effects with context.
|
||||
- [#1446160]: Integrate with media module: Title and Alt text.
|
||||
- [#1591198]: Have dimensions calculations not ignore NULL's.
|
||||
- Refactored canvas effects: added parameter types in documentation and
|
||||
signatures. Standardized function documentation. Comments according to Drupal
|
||||
coding standards.
|
||||
- [#1999140]: Canvas effects using imagemagick might fail due to earlier
|
||||
-gravity settings.
|
||||
- Refactored the image_effects_text_test module to no longer depend on features.
|
||||
- [#1998354]: Non-ASCII characters fail to display correctly on many systems
|
||||
(when using Imagemagick).
|
||||
- Further code enhancements (messages, comments) to autorotate.
|
||||
- [#1930728]: Autorotate does not reset EXIF orientation tag.
|
||||
- [#1990620] Many config form docs missing from the D7 upgrade. Converted all
|
||||
legacy instances of #type=markup into #markup='content..'
|
||||
- Removed deprecated functions imagecache_actions_entities_from_references() and
|
||||
imagecache_actions_fields_from_filepath() (see [#1844298]).
|
||||
- [#1983168]: Custom text via PHP causing EntityMalformedException ...
|
||||
- Replaced lhandw.ttf font with some real free fonts that may also be
|
||||
distributed for free. Changed all text effect tests accordingly.
|
||||
- Better text effect defaults (translated sample text, text visible by default,
|
||||
sample font file).
|
||||
- [#1986304]: Strict warning: Only variables should be passed by reference ...
|
||||
- [#1981490]: Wrong filename imagecache_Actions.install.
|
||||
- [#1858760]: Unable to find the file 'lhandw.ttf'. Please check the path.
|
||||
|
||||
|
||||
Imagecache Actions 7.x-1.1 2012-12-04
|
||||
-------------------------------------
|
||||
- [#1591198]: Image dimensions callbacks should handle unknown (NULL) dimensions
|
||||
as valid input.
|
||||
- [#464092]: Aspect Switcher -- Need to Flush Presets. Side-effect: now allows
|
||||
to define no image style for either landscape or portrait.
|
||||
- [#1676924]: Autorotate: check for exif extension and test dimensions callback.
|
||||
- [#1849020]: Cant get text test examples to work.
|
||||
- [#1702716]: System Stream Wrappers Conflict.
|
||||
- [#1844298]: Remove dependency from entity module.
|
||||
- [#1778594]: Negative image effect does not work.
|
||||
- [#1778214]: Remove version from image_effects_text_test.info.
|
||||
- [#1752664]: Error on importing image style.
|
||||
- [#1676924]: Autorotate: check for exif extension.
|
||||
- [#1666912] by Dubs: Call to undefined function.
|
||||
imagecache_actions_get_image_context() in imagecache_customactions.module.
|
||||
- [#1630194]: Custom actions broken after upgrading from dev to prod.
|
||||
- [#1591484] by epieddy: Underlay Center or Right parameter not working.
|
||||
- Moved the image styles administrative features to its own module.
|
||||
- Augment the duplicate with an export and import. This will allow users to
|
||||
duplicate between sites or to post failing styles in the issue queue (without
|
||||
using the features module).
|
||||
- Backport of patch from geoffreyr for [#1403962]: Add action "duplicate" to
|
||||
image style admin screen. This will allow us to easily create large sets of
|
||||
test/showcase styles and to fine tune this request before it lands in D8 core.
|
||||
|
||||
|
||||
Imagecache Actions 7.x-1.0 2012-05-19
|
||||
-------------------------------------
|
||||
Incompatibilities:
|
||||
- Effects that operate on the transparency layer, do not automatically change
|
||||
the format anymore to png. You will have to add this as a separate effect.
|
||||
- File handling: the way that files (e.g. fonts, watermarks, backgrounds) are
|
||||
searched for has been aligned over all effects that work with an additional
|
||||
file. This may cause current styles to not being able to find specified files
|
||||
anymore.
|
||||
- Custom actions: custom snippets are now executed using the PHP filter module,
|
||||
meaning that the image style editor must have the 'Use PHP for settings'
|
||||
permission to be able to edit the custom action snippet.
|
||||
- Custom actions: information and variables that are available in your custom
|
||||
snippet have changed. See the README.txt of the custom actions module.
|
||||
|
||||
No changelog exists from before this 7.x-1.0 version. So the changelog starts
|
||||
from here. 7.x-1.0 is the first reasonably well working D7 version. The 7.x-0.0
|
||||
version was based on posted patches in the D7 port request issue and has never
|
||||
been tested well. This 7.x-1.0 version is also not extensively tested by the
|
||||
maintainers, but has been used in many (live) sites - currently (may 2012) over
|
||||
5.000 reported 7.x-1.x-dev installs - so has received fairly good "test
|
||||
coverage".
|
||||
|
||||
|
||||
Current and past maintainers for Imagecache Actions
|
||||
---------------------------------------------------
|
||||
- dman (https://drupal.org/user/33240)
|
||||
- sidneyshan (https://drupal.org/user/652426)
|
||||
- fietserwin (https://drupal.org/user/750928)
|
||||
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
@@ -0,0 +1,225 @@
|
||||
README for the Imagecache Actions Drupal module
|
||||
-----------------------------------------------
|
||||
|
||||
Project page: https://drupal.org/project/imagecache_actions
|
||||
|
||||
Current and past maintainers for Imagecache Actions:
|
||||
- dman (https://drupal.org/user/33240)
|
||||
- sidneyshan (https://drupal.org/user/652426)
|
||||
- fietserwin (https://drupal.org/user/750928)
|
||||
|
||||
|
||||
Release notes for 7.x-1.x-dev
|
||||
-----------------------------
|
||||
- Clear all caches after updating.
|
||||
|
||||
|
||||
Release notes for 7.x-1.4
|
||||
-------------------------
|
||||
- This release supports image labels as introduced by Drupal 7.23.
|
||||
- See CHANGELOG.txt for a full overview of changes.
|
||||
|
||||
|
||||
Release notes for 7.x-1.1
|
||||
-------------------------
|
||||
- If you use the module:// notation anywhere in an image effect, you must now
|
||||
install the System Stream Wrapper module
|
||||
(https://drupal.org/project/system_stream_wrapper).
|
||||
- Clear the cache after updating.
|
||||
|
||||
|
||||
Release notes for 7.x-1.0
|
||||
-------------------------
|
||||
- Clear the (registry) cache after installing or updating to 7.x-1.0.
|
||||
- If you use custom actions, run update.php.
|
||||
- If you use custom actions, be sure to enable the 'PHP filter' module and give
|
||||
image style editors that may create custom actions the 'use PHP for settings'
|
||||
permission. The module must also be enabled on image creation.
|
||||
- If you use custom actions, please read the README.txt from that sub-module to
|
||||
find out about how information and resources are available to you. You will
|
||||
probably have to change your code snippets.
|
||||
- If you use effects that use files (mask, overlays, underlays, text fonts),
|
||||
check the way they are specified. From 7.x-1.0 on, you have to specify the
|
||||
location using one of the schemes private://, public://, module:// or
|
||||
temporary://. If no scheme is specified, the file is searched for as is, thus
|
||||
relative to the current directory or as an absolute path.
|
||||
- Effects that use the transparency layer (e.g. mask, rounded corners) do not
|
||||
automatically convert to PNG anymore. Use the "Change file format" for that.
|
||||
- There's no upgrade from D6. You will have to recreate your styles manually.
|
||||
|
||||
Warning:
|
||||
Ongoing development in the area of e.g. making the effects more consistent,
|
||||
adding and/or removing parameters or redefining their meaning, might cause
|
||||
backward incompatibilities between future versions and the current version.
|
||||
Thus, we cannot and do not guarantee backwards compatibility or automatic
|
||||
upgrade paths for future versions.
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
The Imagecache Actions module provides a suite of additional image effects that
|
||||
can be added to image styles. Image styles let you create derivations of images
|
||||
by applying (a series of) effect(s) to it. Think of resizing, desaturating,
|
||||
masking, etc.
|
||||
|
||||
Furthermore, imagecache_actions extends the administrative interface for image
|
||||
styles by providing additional features. It does so in the "Image styles admin"
|
||||
sub module.
|
||||
|
||||
The additional effects that Imagecache Actions provides include:
|
||||
- Watermark: place a image with transparency anywhere over a source picture.
|
||||
- Overlay: add photo-corners etc to the image
|
||||
- Text overlay: add e.g. a copyright notice to your image.
|
||||
- Color-shifting: colorize images.
|
||||
- Brighten/Darken.
|
||||
- Alpha blending: use a gray scale image to define the transparency layer of an
|
||||
image.
|
||||
- Canvas manipulation: resize the canvas and add a background color or image.
|
||||
- File Format switcher: if you need transparency in JPGs, make them PNG. If your
|
||||
PNG thumbnails are 30K each, save them as JPGs.
|
||||
- Rounded corners.
|
||||
- TODO: complete list, check short descriptions
|
||||
|
||||
These effects are grouped in sub-modules. Just enable the ones you want to use.
|
||||
TODO: list sub-modules and their sets of effects.
|
||||
|
||||
Imagecache Actions supports both the GD toolkit from Drupal core and the
|
||||
Imagemagick toolkit. However, please note that Imagemagick support is not yet
|
||||
complete. Please file an issue if you encounter problems in using Imagemagick.
|
||||
|
||||
|
||||
What is imagecache_action not?
|
||||
------------------------------
|
||||
Imagecache Actions does not provide a new UI or new menu items. It hooks into
|
||||
the already existing image styles system (from Drupal core). See
|
||||
https://drupal.org/documentation/modules/image for more information about
|
||||
working with images.
|
||||
|
||||
|
||||
A note about the name of this module
|
||||
------------------------------------
|
||||
Image styles are part of Drupal 7 core and are the successor of the Drupal 6
|
||||
imagecache module. In Drupal 6 image styles were called (imagecache) presets and
|
||||
the separate effects that made up a style were called (imagecache) actions. In
|
||||
porting to D7, that name has not been changed (yet).
|
||||
|
||||
|
||||
Which toolkit to use?
|
||||
---------------------
|
||||
Personally, I (fietserwin) prefer the imagemagick toolkit:
|
||||
- It is better in anti-aliasing. Try to rotate an image using both toolkits and
|
||||
you will see what I mean.
|
||||
- It does not execute in the PHP memory space, so is not restricted by the
|
||||
memory_limit PHP setting.
|
||||
- The GD toolkit will, at least on my Windows configuration, keep the font file
|
||||
open after a text operation, so you cannot delete, move or rename it anymore.
|
||||
|
||||
On the other hand: the GD toolkit is always available (in the correct version),
|
||||
whereas imagemagick is not always present on shared hosting or may be present in
|
||||
an antique version that might give problems.
|
||||
|
||||
Please note that effects may give different results depending on the
|
||||
toolkit used.
|
||||
|
||||
Please also note that a 3rd image toolkit exists:
|
||||
Imagick (https://www.drupal.org/project/imagick)
|
||||
This toolkit uses the Imagick extension and thus does not call the ImageMagick
|
||||
binaries directly. However our module does not implement the toolkit specific
|
||||
parts for the effects we provide for the Imagick toolkit, but the Imagick
|
||||
toolkit comes with its own set of effects that partly covers our effects. So,
|
||||
depending on the effects you require it may be a replacement for both our module
|
||||
and the Imagemagick module or the core GD toolkit.
|
||||
|
||||
Hard Dependencies
|
||||
-----------------
|
||||
- Image module from Drupal core
|
||||
|
||||
At least 1 of the available image toolkits:
|
||||
- GD toolkit from Drupal core.
|
||||
- Imagemagick toolkit: https://drupal.org/project/imagemagick.
|
||||
|
||||
|
||||
Soft Dependencies
|
||||
-----------------
|
||||
- System stream wrapper (https://drupal.org/project/system_stream_wrapper)
|
||||
- Remote stream wrapper (https://drupal.org/project/remote_stream_wrapper)
|
||||
These modules provide additional stream wrappers. Especially the system stream
|
||||
wrapper is very handy as it provides, among others, a module:// and theme://
|
||||
wrapper.
|
||||
|
||||
|
||||
Installing
|
||||
----------
|
||||
As usual.
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
After enabling the module:
|
||||
- Assure that the Image module from core is enabled.
|
||||
- Configure your toolkit and its settings at admin/config/media/image-toolkit.
|
||||
- Define image styles at admin/config/media/image-styles and add 1 or more
|
||||
effects as defined by this module
|
||||
- Use the image styles via e.g. the formatters of image fields.
|
||||
|
||||
|
||||
Upgrading from D6
|
||||
-----------------
|
||||
There's no upgrade path defined for sites upgrading from D6 to D7. This means
|
||||
that you will have to manually redefine your D6 imagecache presets as D7 image
|
||||
styles. Note that actually an upgrade path would have to be defined by the
|
||||
imagecache module, not this imagecache actions module. However, as there is no
|
||||
D7 version of imagecache that provides an upgrade, users may post an upgrade
|
||||
function to the issue queue and we will incorporate it.
|
||||
|
||||
|
||||
Backwards compatibility
|
||||
-----------------------
|
||||
Future releases will not be guaranteed to be backwards compatible. Implementing
|
||||
Imagemagick support e.g. might give unforeseen problems that can only be solved
|
||||
by changing the details of what an effect does. We will document these kind of
|
||||
incompatibilities in the changelog and the release notes.
|
||||
|
||||
|
||||
File form fields
|
||||
----------------
|
||||
A number of effects have a file form field where the editor can define a file
|
||||
name to use. This can be e.g. for overlays, masks or fonts. The file name should
|
||||
be defined using either:
|
||||
- 1 of the (enabled) scheme's:
|
||||
* public://
|
||||
* private:// Preferred for site specific masks, overlays, etc, that do not
|
||||
need to be shared publicly.
|
||||
* temporary:// Unlikely to be useful, but supported anyway as all schemes are
|
||||
supported.
|
||||
* module:// Introduced by the system stream wrapper module and preferred for
|
||||
module provided resources.
|
||||
* theme:// idem.
|
||||
* profile:// idem.
|
||||
* library:// idem.
|
||||
- A relative (to the current directory, probably Drupal root) or absolute path.
|
||||
|
||||
|
||||
Support
|
||||
-------
|
||||
Via the issue queue of this project at Drupal.org.
|
||||
|
||||
|
||||
Known problems
|
||||
--------------
|
||||
These are better documented in the issue queue, but might be listed here (as
|
||||
well).
|
||||
|
||||
- Underlay does not work in imagemagick if the dimensions of both images are not
|
||||
equal. As a workaround first add a canvas effect with a fully transparent
|
||||
background.
|
||||
- Underlay/overlay: keywords in the x and y offset fields do not work.
|
||||
- Underlay does still display a message about Imagemagick not being supported.
|
||||
- Brightness values outside the -250 .. 250 range are accepted.
|
||||
- Check color fields that allow a transparency component or allow to be empty to
|
||||
specify fully transparent.
|
||||
|
||||
Known problems: Imagemagick
|
||||
---------------------------
|
||||
- Define canvas using offsets may bot work on older versions. We have an error
|
||||
report for version 6.5.4.7 (2009-07) (https://drupal.org/node/888644).
|
||||
@@ -0,0 +1,112 @@
|
||||
Imagecache Actions roadmap
|
||||
--------------------------
|
||||
|
||||
This is a non-contractual roadmap for the D7 branch of the imagecache actions
|
||||
module. Actual release dates and completed features will largely depend on
|
||||
available time. So support is always welcome. Furthermore, critical bugs may
|
||||
make us release more often, but that should only change the release number in
|
||||
which certain features are planned, not the timeline.
|
||||
|
||||
|
||||
Imagecache Actions 7.x-1.0
|
||||
--------------------------
|
||||
Targeted release date: may 2012
|
||||
|
||||
- (DONE) Clean up D7 issue queue
|
||||
- (DONE) Commit posted patches from the issue queue
|
||||
- (DONE) Solve easy to solve bug reports
|
||||
- Do some basic testing
|
||||
- (DONE) Reintroduce the text action, currently living in a sandbox project at
|
||||
https://drupal.org/node/1090312
|
||||
- (DONE) Update README.txt
|
||||
- (DONE) Introduce CHANGELOG.txt
|
||||
- (DONE) Add this ROADMAP.txt
|
||||
|
||||
|
||||
Imagecache Actions 7.x-1.1
|
||||
--------------------------
|
||||
Targeted release date: end 2012
|
||||
|
||||
Mainly a bug fix release
|
||||
- (DONE) Solve remaining outstanding bug reports
|
||||
- (ALMOST DONE) Keep D7 issue queue clean
|
||||
|
||||
|
||||
Imagecache Actions 7.x-1.2
|
||||
--------------------------
|
||||
Targeted release date: spring 2013
|
||||
|
||||
- Check help and documentation. a.o: hook_help, effect descriptions.
|
||||
- (DONE) Continue to keep the D7 issue queue clean.
|
||||
- Improve Imagemagick support and/or document what effects are not working for
|
||||
which toolkit (version).
|
||||
- (ALMOST DONE) Check that all effects implement all of the effects API (especially the
|
||||
dimensions callback).
|
||||
- Add testing. The idea is to create a set of image styles that cover all
|
||||
effects and can be used to visually check for regressions.
|
||||
|
||||
Automated testing would be nice, but I am not sure that we can guarantee that
|
||||
jpeg or png files are binary identical on each run across different computers.
|
||||
But if the number of false positives is small, it would certainly be a useful
|
||||
addition.
|
||||
|
||||
|
||||
Imagecache Actions 7.x-1.3
|
||||
--------------------------
|
||||
Targeted release date: ...
|
||||
|
||||
- Continue to keep the D7 issue queue clean.
|
||||
- Check help and documentation. a.o: hook_help, effect descriptions.
|
||||
- Improve Imagemagick support and/or document what effects are not working for
|
||||
which toolkit (version).
|
||||
- Add testing. The idea is to create a set of image styles that cover all
|
||||
effects and can be used to visually check for regressions.
|
||||
|
||||
Automated testing would be nice, but I am not sure that we can guarantee that
|
||||
jpeg or png files are binary identical on each run across different computers.
|
||||
But if the number of false positives is small, it would certainly be a useful
|
||||
addition.
|
||||
- Refactor code:
|
||||
- Extract common form fields.
|
||||
- Extract common error handling.
|
||||
- (STARTED) Clean up comments, todo's, etc.
|
||||
- (STARTED) Doxygen code documentation according to latest standards
|
||||
- Increase the amount of lazy loaded code.
|
||||
|
||||
|
||||
Imagecache Actions 7.x-1.5
|
||||
--------------------------
|
||||
Targeted release date: ...
|
||||
|
||||
- Look at outstanding feature requests
|
||||
- Continue to keep the D7 issue queue clean.
|
||||
- Keep improving Imagemagick support, a.o:
|
||||
- Try to get insight into what version of imagemagick is required by what
|
||||
effect.
|
||||
- Document which effects might produce different results.
|
||||
- Continue refactoring code:
|
||||
- Extract common form fields.
|
||||
- Extract common error handling.
|
||||
- (STARTED) Clean up comments, todo's, etc.
|
||||
- (STARTED) Doxygen code documentation according to latest standards.
|
||||
- Increase the amount of lazy loaded code.
|
||||
|
||||
|
||||
Imagecache Actions 8.x-2.x
|
||||
--------------------------
|
||||
Targeted release date: ...
|
||||
|
||||
- Convert image effects into plugins (as [#1821854] does for core).
|
||||
- This will make adding new effects much simpler, so we can easier add them.
|
||||
- Should we rename the module to image_effects?
|
||||
- We should strive to merge with other modules that provide image effects:
|
||||
- FiltersIE module (https://drupal.org/project/filtersie)
|
||||
- Imagecache Effects: https://drupal.org/project/imagecache_effects (D6 only,
|
||||
but are their effects more advanced then our counterparts or do they add new
|
||||
effects?)
|
||||
- Image watermark: https://drupal.org/project/watermark (D5 only, but is their
|
||||
watermark effect more advanced?)
|
||||
- ImageCache Scale-9 Actions: https://drupal.org/project/imagecache_scale9actions
|
||||
- ImageEffects: https://drupal.org/project/imageeffects (pixelate and flip).
|
||||
- Imagick: https://www.drupal.org/project/imagick
|
||||
- etc.
|
||||
@@ -0,0 +1,13 @@
|
||||
name = Imagecache Autorotate
|
||||
description = Provides an image effect to autorotate an image based on EXIF data.
|
||||
package = Media
|
||||
core = 7.x
|
||||
|
||||
dependencies[] = image
|
||||
|
||||
; Information added by Drupal.org packaging script on 2016-02-19
|
||||
version = "7.x-1.7"
|
||||
core = "7.x"
|
||||
project = "imagecache_actions"
|
||||
datestamp = "1455872655"
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/**
|
||||
* Implements hook_requirements().
|
||||
*/
|
||||
function imagecache_autorotate_requirements($phase) {
|
||||
$result = array();
|
||||
$t = get_t();
|
||||
if (!extension_loaded('exif')) {
|
||||
$result['imagecache_autorotate_exif_extension'] = array(
|
||||
'title'=> 'EXIF extension',
|
||||
'value'=> $phase === 'runtime' ? $t('Disabled') : '',
|
||||
'description'=> $t('The autorotate image effect requires the exif extension to be enabled.'),
|
||||
'severity' => REQUIREMENT_ERROR,
|
||||
);
|
||||
}
|
||||
else {
|
||||
$result['imagecache_autorotate_exif_extension'] = array(
|
||||
'title'=> 'EXIF extension',
|
||||
'value'=> $t('Enabled'),
|
||||
'severity' => REQUIREMENT_OK,
|
||||
);
|
||||
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
<?php
|
||||
/**
|
||||
* @file Autorotate image based on EXIF Orientation tag.
|
||||
*
|
||||
* EXIF: https://en.wikipedia.org/wiki/Exchangeable_image_file_format
|
||||
* EXIF orientation tag: http://sylvana.net/jpegcrop/exif_orientation.html
|
||||
*
|
||||
* Originally contributed by jonathan_hunt https://drupal.org/user/28976,
|
||||
* September 1, 2009
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_image_effect_info().
|
||||
*
|
||||
* Defines information about the supported effects.
|
||||
*/
|
||||
function imagecache_autorotate_image_effect_info() {
|
||||
$effects = array();
|
||||
|
||||
$effects['imagecache_autorotate'] = array(
|
||||
'label' => t('Autorotate'),
|
||||
'help' => t('Autorotate image based on EXIF orientation and reset that tag.'),
|
||||
'effect callback' => 'imagecache_autorotate_effect',
|
||||
'dimensions callback' => 'imagecache_autorotate_dimensions',
|
||||
'form callback' => 'imagecache_autorotate_form',
|
||||
'summary theme' => 'imagecache_autorotate_summary',
|
||||
);
|
||||
|
||||
return $effects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_theme().
|
||||
*
|
||||
* Registers theme functions for the effect summaries.
|
||||
*/
|
||||
function imagecache_autorotate_theme() {
|
||||
return array(
|
||||
'imagecache_autorotate_summary' => array(
|
||||
'variables' => array('data' => NULL),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the auto-rotate form.
|
||||
*
|
||||
* This effect has no options, only some help text, so the form is displayed
|
||||
* anyway.
|
||||
*/
|
||||
function imagecache_autorotate_form() {
|
||||
$form = array();
|
||||
$form['help'] = array(
|
||||
'#markup' => "<p><strong>There are no user-configurable options for this process.</strong></p>
|
||||
<p>Certain cameras can embed <em>orientation</em> information into image
|
||||
files when they save them. This information is embedded in an EXIF tag
|
||||
and can be used to rotate images to their correct position for display.
|
||||
<em>Not all cameras or images contain this information.</em>
|
||||
This process is only useful for images that contain this information,
|
||||
whereas for other images it is harmless.
|
||||
</p>
|
||||
<p>Although most modern browsers do support the orientation tag, the
|
||||
information may get lost or become incorrect by other operations.
|
||||
So, to support all browsers and prevent rotation errors, it is better to
|
||||
start each image style with this effect.
|
||||
</p>
|
||||
<p>The expected/supported values are:<br/>
|
||||
<strong>Tag</strong>: <code>0x0112 Orientation</code>
|
||||
</p>
|
||||
<ul>
|
||||
<li>1 = Horizontal (normal)</li>
|
||||
<li>3 = Rotate 180</li>
|
||||
<li>6 = Rotate 90 CW</li>
|
||||
<li>8 = Rotate 270 CW</li>
|
||||
</ul>
|
||||
<p>Wikipedia: <a href='https://en.wikipedia.org/wiki/Exchangeable_image_file_format'>Exchangeable image file format</a></p>
|
||||
",
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements theme_hook() for the autorotate effect summary.
|
||||
*
|
||||
* param array $variables
|
||||
* An associative array containing:
|
||||
* - data: The current configuration for this image effect.
|
||||
*
|
||||
* @return string
|
||||
* The HTML for the summary of this image effect.
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_imagecache_autorotate_summary(/*array $variables*/) {
|
||||
return 'image based on its EXIF data.';
|
||||
}
|
||||
|
||||
/**
|
||||
* Autorotate image based on EXIF Orientation tag.
|
||||
*/
|
||||
function imagecache_autorotate_effect(stdClass $image /*, $data*/) {
|
||||
// Test to see if EXIF is supported by the current image type.
|
||||
if (in_array($image->info['mime_type'], array('image/jpeg', 'image/tiff'))) {
|
||||
// Hand over to toolkit.
|
||||
return image_toolkit_invoke('imagecache_autorotate', $image);
|
||||
}
|
||||
else if ($image->source === 'modules/image/sample.png' && user_access('administer image styles')) {
|
||||
if (!extension_loaded('exif')) {
|
||||
// Issue a warning if we are in the admin screen and the exif extension is
|
||||
// not enabled.
|
||||
drupal_set_message(t('The autorotate image effect requires the exif extension to be enabled.'), 'warning');
|
||||
if ($image->toolkit === 'imagemagick') {
|
||||
drupal_set_message(t('Though imagemagick will work without the exif extension, subsequent effects may fail as the image dimensions cannot be updated.'), 'warning');
|
||||
}
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* GD toolkit specific implementation of this image effect.
|
||||
*
|
||||
* @param stdClass $image
|
||||
*
|
||||
* @return bool
|
||||
* true on success, false otherwise.
|
||||
*/
|
||||
function image_gd_imagecache_autorotate(stdClass $image) {
|
||||
if (!function_exists('exif_read_data')) {
|
||||
watchdog('imagecache_actions', 'Image %file could not be auto-rotated: !message', array('%file' => $image->source, '!message' => t('The exif_read_data() function is not available in this PHP installation. You probably have to enable the exif extension.')));
|
||||
return FALSE;
|
||||
}
|
||||
$exif = exif_read_data(drupal_realpath($image->source));
|
||||
if (isset($exif['Orientation'])) {
|
||||
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/EXIF.html:
|
||||
// 1 = Horizontal (normal)
|
||||
// 2 = Mirror horizontal
|
||||
// 3 = Rotate 180
|
||||
// 4 = Mirror vertical
|
||||
// 5 = Mirror horizontal and rotate 270 CW
|
||||
// 6 = Rotate 90 CW
|
||||
// 7 = Mirror horizontal and rotate 90 CW
|
||||
// 8 = Rotate 270 CW
|
||||
// @todo: Add horizontal and vertical flips etc.
|
||||
// imagecopy seems to be able to mirror, see conmments on
|
||||
// http://php.net/manual/en/function.imagecopy.php
|
||||
// @todo: Create sample set for tests.
|
||||
switch ($exif['Orientation']) {
|
||||
case 3:
|
||||
$degrees = 180;
|
||||
break;
|
||||
case 6:
|
||||
$degrees = 90;
|
||||
break;
|
||||
case 8:
|
||||
$degrees = 270;
|
||||
break;
|
||||
default:
|
||||
$degrees = 0;
|
||||
}
|
||||
if ($degrees != 0) {
|
||||
return image_rotate($image, $degrees);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imagemagick toolkit specific implementation of this image effect.
|
||||
*
|
||||
* @param stdClass $image
|
||||
* An image object.
|
||||
*
|
||||
* @return bool
|
||||
* true on success, false otherwise.
|
||||
*
|
||||
* @see http://www.imagemagick.org/script/command-line-options.php#auto-orient
|
||||
*/
|
||||
function image_imagemagick_imagecache_autorotate(stdClass $image) {
|
||||
// Use the exif extension, if enabled, to figure out the new dimensions.
|
||||
// Moreover (see [#2366163]): to prevent a bug in IM to incorrectly rotate the
|
||||
// image when it should not, we only pass the auto-orient argument when the
|
||||
// exif extension could detect the 'Orientation' tag.
|
||||
if (function_exists('exif_read_data')) {
|
||||
$exif = exif_read_data(drupal_realpath($image->source));
|
||||
if (isset($exif['Orientation'])) {
|
||||
switch ($exif['Orientation']) {
|
||||
case 1:
|
||||
// Normal orientation: no need to rotate or to change the dimensions.
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
// 90 or 270 degrees rotation (+ optional mirror): swap dimensions.
|
||||
$image->ops[] = '-auto-orient';
|
||||
$tmp = $image->info['width'];
|
||||
$image->info['width'] = $image->info['height'];
|
||||
$image->info['height'] = $tmp;
|
||||
break;
|
||||
default:
|
||||
// All other orientations: pass the arguments, but the dimensions
|
||||
// remain the same.
|
||||
$image->ops[] = '-auto-orient';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// We do add the auto-orient argument to IM. IM will determine itself
|
||||
// whether to rotate or not.
|
||||
$image->ops[] = '-auto-orient';
|
||||
// However we cannot keep track of the dimensions anymore.
|
||||
$image->info['width'] = $image->info['height'] = NULL;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Image dimensions callback for this image effect.
|
||||
*
|
||||
* @param array $dimensions
|
||||
* An array with the dimensions (in pixels) to be modified.
|
||||
* param array $data
|
||||
* An associative array containing the effect data.
|
||||
*/
|
||||
function imagecache_autorotate_dimensions(array &$dimensions/*, array $data*/) {
|
||||
// We can only know the resulting dimensions if both dimensions are equal.
|
||||
// Otherwise we need to inspect the image itself, which is not passed in here.
|
||||
// (this callback was introduced to enhance performance by NOT accessing the
|
||||
// image file when rendering the width and height attributes of the html img
|
||||
// tag).
|
||||
if ($dimensions['width'] !== $dimensions['height']) {
|
||||
$dimensions['width'] = $dimensions['height'] = NULL;
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 155 KiB |
@@ -0,0 +1,14 @@
|
||||
name = Imagecache Canvas Actions
|
||||
description = Provides image effects for manipulating image canvases: define canvas, image mask, watermark, underlay background image, rounded corners, composite source to image and resize by percent effect. Also provides an aspect switcher (portrait/landscape).
|
||||
package = Media
|
||||
core = 7.x
|
||||
|
||||
dependencies[] = imagecache_actions
|
||||
dependencies[] = image
|
||||
|
||||
; Information added by Drupal.org packaging script on 2016-02-19
|
||||
version = "7.x-1.7"
|
||||
core = "7.x"
|
||||
project = "imagecache_actions"
|
||||
datestamp = "1455872655"
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file A collection of canvas (layer) type manipulations for imagecache -
|
||||
* including "Watermark"
|
||||
*
|
||||
* Based on first draft of the code by Dimm (imagecache.module 5--1)
|
||||
* https://drupal.org/node/184816
|
||||
*
|
||||
* Rewritten and ported to Imagecache actions API (imagecache.module 5--2) by
|
||||
* dman http://coders.co.nz/
|
||||
*
|
||||
*
|
||||
* Notes about imagecache action extensions. For each action:
|
||||
*
|
||||
* 1: Implement imagecache_HOOK_form($formdata) to define the config form.
|
||||
*
|
||||
* 1a: Implement theme_imagecache_HOOK_form if needed - optional
|
||||
*
|
||||
* 2: Implement imagecache_HOOK_image($image, $data) to DO the process
|
||||
*
|
||||
* 3: Implement theme_imagecache_HOOK($element) to return a text description of
|
||||
* the setting
|
||||
*
|
||||
* 4: Declare the action in HOOK_imagecache_actions()
|
||||
*
|
||||
*
|
||||
* API ref for hook_image()
|
||||
*
|
||||
* @param $image array defining an image file, including :
|
||||
*
|
||||
* $image- >source as the filename,
|
||||
*
|
||||
* $image->info array
|
||||
*
|
||||
* $image->resource handle on the image object
|
||||
*
|
||||
* @param $action array of settings as defined in your form.
|
||||
*
|
||||
*/
|
||||
|
||||
if (! function_exists('imagecache_actions_calculate_relative_position') ) {
|
||||
module_load_include('inc', 'imagecache_actions', 'utility');
|
||||
}
|
||||
|
||||
// @todo There doesn't seem to be a way to specify a file in hook_image_effect_info
|
||||
// so placing this here for the time being.
|
||||
module_load_include('inc', 'imagecache_canvasactions', 'canvasactions');
|
||||
module_load_include('inc', 'imagecache_canvasactions', 'rounded_corners');
|
||||
|
||||
/**
|
||||
* Implements hook_image_effect_info().
|
||||
*
|
||||
* Defines information about the supported effects.
|
||||
*/
|
||||
function imagecache_canvasactions_image_effect_info() {
|
||||
$effects = array();
|
||||
|
||||
$effects['canvasactions_definecanvas'] = array(
|
||||
'label' => t('Define canvas'),
|
||||
'help' => t('Define the size of the working canvas and background color, this controls the dimensions of the output image.'),
|
||||
'effect callback' => 'canvasactions_definecanvas_effect',
|
||||
'dimensions callback' => 'canvasactions_definecanvas_dimensions',
|
||||
'form callback' => 'canvasactions_definecanvas_form',
|
||||
'summary theme' => 'canvasactions_definecanvas_summary',
|
||||
);
|
||||
|
||||
$effects['canvasactions_imagemask'] = array(
|
||||
'label' => t('Image mask'),
|
||||
'help' => t(' Choose the file image you wish to use as a mask, and apply it to the canvas.'),
|
||||
'dimensions passthrough' => TRUE,
|
||||
'effect callback' => 'canvasactions_imagemask_effect',
|
||||
'form callback' => 'canvasactions_imagemask_form',
|
||||
'summary theme' => 'canvasactions_imagemask_summary',
|
||||
);
|
||||
|
||||
$effects['canvasactions_file2canvas'] = array(
|
||||
'label' => t('Overlay (watermark)'),
|
||||
'help' => t('Choose the file image you wish to use as an overlay, and position it in a layer on top of the canvas.'),
|
||||
'dimensions passthrough' => TRUE,
|
||||
'effect callback' => 'canvasactions_file2canvas_effect',
|
||||
'form callback' => 'canvasactions_file2canvas_form',
|
||||
'summary theme' => 'canvasactions_file2canvas_summary',
|
||||
);
|
||||
|
||||
$effects['canvasactions_canvas2file'] = array(
|
||||
'label' => t('Underlay (background)'),
|
||||
'help' => t('Choose the file image you wish to use as an background, and position the processed image on it.'),
|
||||
'effect callback' => 'canvasactions_canvas2file_effect',
|
||||
'dimensions callback' => 'canvasactions_canvas2file_dimensions',
|
||||
'form callback' => 'canvasactions_canvas2file_form',
|
||||
'summary theme' => 'canvasactions_canvas2file_summary',
|
||||
);
|
||||
|
||||
$effects['canvasactions_source2canvas'] = array(
|
||||
'label' => t('Overlay: source image to canvas'),
|
||||
'help' => t('Places the source image onto the canvas for compositing.'),
|
||||
'dimensions passthrough' => TRUE,
|
||||
'effect callback' => 'canvasactions_source2canvas_effect',
|
||||
'form callback' => 'canvasactions_source2canvas_form',
|
||||
'summary theme' => 'canvasactions_source2canvas_summary',
|
||||
);
|
||||
|
||||
$effects['canvasactions_roundedcorners'] = array(
|
||||
'label' => t('Rounded Corners'),
|
||||
'help' => t('This is true cropping, not overlays, so the result <em>can</em> be transparent.'),
|
||||
'dimensions passthrough' => TRUE,
|
||||
'effect callback' => 'canvasactions_roundedcorners_effect',
|
||||
'form callback' => 'canvasactions_roundedcorners_form',
|
||||
'summary theme' => 'canvasactions_roundedcorners_summary',
|
||||
);
|
||||
|
||||
$effects['canvasactions_aspect'] = array(
|
||||
'label' => t('Aspect switcher'),
|
||||
'help' => t('Use different effects depending on whether the image is landscape of portrait shaped. This re-uses other preset definitions, and just chooses between them based on the rule.'),
|
||||
'effect callback' => 'canvasactions_aspect_effect',
|
||||
'dimensions callback' => 'canvasactions_aspect_dimensions',
|
||||
'form callback' => 'canvasactions_aspect_form',
|
||||
'summary theme' => 'canvasactions_aspect_summary',
|
||||
);
|
||||
|
||||
$effects['canvasactions_resizepercent'] = array(
|
||||
'label' => t('Resize (percent)'),
|
||||
'help' => t('Resize the image based on percent. If only a single dimension is specified, the other dimension will be calculated.'),
|
||||
'effect callback' => 'canvasactions_resizepercent_effect',
|
||||
'dimensions callback' => 'canvasactions_resizepercent_dimensions',
|
||||
'form callback' => 'canvasactions_resizepercent_form',
|
||||
'summary theme' => 'canvasactions_resizepercent_summary',
|
||||
);
|
||||
|
||||
$effects['canvasactions_blur'] = array(
|
||||
'label' => t('Blur'),
|
||||
'help' => t('Make the image become unclear.'),
|
||||
'effect callback' => 'canvasactions_blur_effect',
|
||||
'dimensions passthrough' => TRUE,
|
||||
'form callback' => 'canvasactions_blur_form',
|
||||
'summary theme' => 'canvasactions_blur_summary',
|
||||
);
|
||||
|
||||
$effects['canvasactions_interlace'] = array(
|
||||
'label' => t('Interlace / Progressive'),
|
||||
'help' => t('Create interlaced PNG/GIF or progressive JPG.'),
|
||||
'effect callback' => 'canvasactions_interlace_effect',
|
||||
'dimensions passthrough' => TRUE,
|
||||
'form callback' => 'canvasactions_interlace_form',
|
||||
);
|
||||
|
||||
return $effects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_theme().
|
||||
*
|
||||
* Registers theme functions for the effect summaries.
|
||||
*/
|
||||
function imagecache_canvasactions_theme() {
|
||||
return array(
|
||||
'canvasactions_definecanvas_summary' => array(
|
||||
'variables' => array('data' => NULL),
|
||||
'file' => 'canvasactions.inc',
|
||||
),
|
||||
'canvasactions_imagemask_summary' => array(
|
||||
'arguments' => array('element' => NULL),
|
||||
'file' => 'canvasactions.inc',
|
||||
),
|
||||
'canvasactions_file2canvas_summary' => array(
|
||||
'variables' => array('data' => NULL),
|
||||
'file' => 'canvasactions.inc',
|
||||
),
|
||||
'canvasactions_source2canvas_summary' => array(
|
||||
'variables' => array('data' => NULL),
|
||||
'file' => 'canvasactions.inc',
|
||||
),
|
||||
'canvasactions_canvas2file_summary' => array(
|
||||
'variables' => array('data' => NULL),
|
||||
'file' => 'canvasactions.inc',
|
||||
),
|
||||
'canvasactions_roundedcorners_summary' => array(
|
||||
'variables' => array('data' => NULL),
|
||||
'file' => 'canvasactions.inc',
|
||||
),
|
||||
'canvasactions_aspect_summary' => array(
|
||||
'variables' => array('data' => NULL),
|
||||
'file' => 'canvasactions.inc',
|
||||
),
|
||||
'canvasactions_resizepercent_summary' => array(
|
||||
'variables' => array('data' => NULL),
|
||||
'file' => 'canvasactions.inc',
|
||||
),
|
||||
'canvasactions_blur_summary' => array(
|
||||
'variables' => array('data' => NULL),
|
||||
'file' => 'canvasactions.inc',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_image_style_flush().
|
||||
*
|
||||
* This hook checks if the image style that is being flushed is used in an
|
||||
* aspect switcher effect. If so, the style that contains the aspect switcher
|
||||
* effect, should be flushed as well as the flushed style was probably changed.
|
||||
*
|
||||
* @param array $flushed_style
|
||||
* The image style that is being flushed.
|
||||
*/
|
||||
function imagecache_canvasactions_image_style_flush(/*array*/ $flushed_style) {
|
||||
$styles = image_styles();
|
||||
foreach ($styles as $style) {
|
||||
if ($style['name'] !== $flushed_style['name']) {
|
||||
foreach ($style['effects'] as $effect) {
|
||||
if ($effect['name'] === 'canvasactions_aspect') {
|
||||
if ( (isset($effect['data']['portrait']) && $effect['data']['portrait'] === $flushed_style['name'])
|
||||
|| (isset($effect['data']['landscape']) && $effect['data']['landscape'] === $flushed_style['name'])) {
|
||||
image_style_flush($style);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,329 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file Routines for rounded corners
|
||||
*/
|
||||
|
||||
/**
|
||||
* Set radius for corner rounding
|
||||
*
|
||||
* Implementation of imagecache_hook_form()
|
||||
*
|
||||
* @param $action array of settings for this action
|
||||
* @return a form definition
|
||||
*/
|
||||
function canvasactions_roundedcorners_form($action) {
|
||||
if (image_get_toolkit() != 'gd') {
|
||||
drupal_set_message('Rounded corners are not currently supported on all versions of imagemagick. This effect works best with GD image toolkit only.', 'warning');
|
||||
}
|
||||
drupal_add_js(drupal_get_path('module', 'imagecache_actions') . '/imagecache_actions.jquery.js');
|
||||
$defaults = array(
|
||||
'radius' => '16',
|
||||
#'antialias' => TRUE,
|
||||
'independent_corners_set' => array(
|
||||
'independent_corners' => FALSE,
|
||||
'radii' => array(
|
||||
'tl' => 0,
|
||||
'tr' => 0,
|
||||
'bl' => 0,
|
||||
'br' => 0,
|
||||
),
|
||||
),
|
||||
);
|
||||
$action = array_merge($defaults, (array) $action);
|
||||
|
||||
$form['radius'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('radius'),
|
||||
'#default_value' => $action['radius'],
|
||||
'#size' => 2,
|
||||
);
|
||||
|
||||
$form['independent_corners_set'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Individual Corner Values'),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => (! $action['independent_corners_set']['independent_corners']),
|
||||
);
|
||||
$form['independent_corners_set']['independent_corners'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Set Corners Independently'),
|
||||
'#default_value' => $action['independent_corners_set']['independent_corners'],
|
||||
);
|
||||
$corners = array(
|
||||
'tl' => t("Top Left Radius"),
|
||||
'tr' => t("Top Right Radius"),
|
||||
'bl' => t("Bottom Left Radius"),
|
||||
'br' => t("Bottom Right Radius"),
|
||||
);
|
||||
// Loop over the four corners and create field elements for them.
|
||||
$form['independent_corners_set']['radii'] = array(
|
||||
'#type' => 'item',
|
||||
'#id' => 'independent-corners-set',
|
||||
'#states' => array(
|
||||
'visible' => array(
|
||||
':input[name="data[independent_corners_set][independent_corners]"]' => array('checked' => TRUE),
|
||||
),
|
||||
),
|
||||
);
|
||||
foreach ($corners as $attribute => $label) {
|
||||
$form['independent_corners_set']['radii'][$attribute] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $label,
|
||||
'#default_value' => 0 + $action['independent_corners_set']['radii'][$attribute],
|
||||
'#size' => 2,
|
||||
);
|
||||
}
|
||||
/*
|
||||
$form['antialias'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('antialias'),
|
||||
'#return_value' => TRUE,
|
||||
'#default_value' => $action['antialias'],
|
||||
'#description' => t('Attempt antialias smoothing when drawing the corners'),
|
||||
);
|
||||
*/
|
||||
$form['notes'] = array(
|
||||
'#markup' => t('
|
||||
Note: the rounded corners effect uses true alpha transparency masking.
|
||||
This means that this effect <b>will fail to be saved</b> on jpegs
|
||||
<em>unless</em> you either <ul>
|
||||
<li>convert the image to PNG (using the coloractions filter for that),</li>
|
||||
<li>define a canvas underneath it (using canvasactions-define-canvas) or</li>
|
||||
<li>underlay a solid color (using coloractions-alpha-flatten) or</li>
|
||||
<li>underlay a background image (canvasactions-underlay)</li>
|
||||
</ul>
|
||||
as a later part of this imagecache pipeline.
|
||||
<br/>
|
||||
'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
function canvasactions_roundedcorners_effect($image, $action) {
|
||||
$independent_corners = !empty($action['independent_corners_set']['independent_corners']);
|
||||
if (!$independent_corners) {
|
||||
// set the independant corners to all be the same.
|
||||
$corners = array('tl', 'tr', 'bl', 'br');
|
||||
foreach ($corners as $key) {
|
||||
// Use the all-the-same radius setting.
|
||||
$action['independent_corners_set']['radii'][$key] = $action['radius'];
|
||||
}
|
||||
}
|
||||
|
||||
return image_toolkit_invoke('roundedcorners', $image, array($action));
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim rounded corners off an image, using an anti-aliasing algorithm.
|
||||
*
|
||||
* Implementation of hook_image()
|
||||
*
|
||||
* Note, this is not image toolkit-agnostic yet! It just assumes GD.
|
||||
* We can abstract it out once we have something else to abstract to.
|
||||
* In the meantime just don't.
|
||||
*
|
||||
* 'handcoded' rounded corners logic contributed by donquixote 2009-08-31
|
||||
*
|
||||
* @param $image
|
||||
* @param $action
|
||||
*/
|
||||
function image_gd_roundedcorners($image, $action) {
|
||||
// Read settings.
|
||||
$width = $image->info['width'];
|
||||
$height = $image->info['height'];
|
||||
$radius = $action['radius'];
|
||||
$independent_corners = !empty($action['independent_corners_set']['independent_corners']);
|
||||
$corners = array('tl', 'tr', 'bl', 'br');
|
||||
|
||||
$im = &$image->resource;
|
||||
// Prepare drawing on the alpha channel.
|
||||
imagesavealpha($im, TRUE);
|
||||
imagealphablending($im, FALSE);
|
||||
|
||||
foreach ($corners as $key) {
|
||||
if ($independent_corners && isset($action['independent_corners_set']['radii'][$key])) {
|
||||
$r = $action['independent_corners_set']['radii'][$key];
|
||||
}
|
||||
else {
|
||||
// Use the all-the-same radius setting.
|
||||
$r = $radius;
|
||||
}
|
||||
|
||||
// key can be 'tl', 'tr', 'bl', 'br'.
|
||||
$is_bottom = ($key{0} == 'b');
|
||||
$is_right = ($key{1} == 'r');
|
||||
|
||||
// dx and dy are in "continuous coordinates",
|
||||
// and mark the distance of the pixel middle to the image border.
|
||||
for ($dx = .5; $dx < $r; ++$dx) {
|
||||
for ($dy = .5; $dy < $r; ++$dy) {
|
||||
|
||||
// ix and iy are in discrete pixel indices,
|
||||
// counting from the top left
|
||||
$ix = floor($is_right ? $width -$dx : $dx);
|
||||
$iy = floor($is_bottom ? $height -$dy : $dy);
|
||||
|
||||
// Color lookup at ($ix, $iy).
|
||||
$color_ix = imagecolorat($im, $ix, $iy);
|
||||
$color = imagecolorsforindex($im, $color_ix);
|
||||
|
||||
|
||||
// Do not process opacity if transparency is 100%. Just jump...
|
||||
// Opacity is always 0 on a transparent source pixel.
|
||||
if ($color['alpha'] != 127) {
|
||||
$opacity = _canvasactions_roundedcorners_pixel_opacity($dx, $dy, $r);
|
||||
if ($opacity >= 1) {
|
||||
// we can finish this row,
|
||||
// all following pixels will be fully opaque.
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (isset($color['alpha'])) {
|
||||
$color['alpha'] = 127 - round($opacity * (127 - $color['alpha']));
|
||||
}
|
||||
else {
|
||||
$color['alpha'] = 127 - round($opacity * 127);
|
||||
}
|
||||
// Value should not be more than 127, and not less than 0.
|
||||
$color['alpha'] = ($color['alpha'] > 127) ? 127 : (($color['alpha'] < 0) ? 0 : $color['alpha']);
|
||||
}
|
||||
|
||||
$color_ix = imagecolorallocatealpha($im, $color['red'], $color['green'], $color['blue'], $color['alpha']);
|
||||
imagesetpixel($im, $ix, $iy, $color_ix);
|
||||
}
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the transparency value for a rounded corner pixel
|
||||
*
|
||||
* @param $x
|
||||
* distance from pixel center to image border (left or right)
|
||||
* should be an integer + 0.5
|
||||
*
|
||||
* @param $y
|
||||
* distance from pixel center to image border (top or bottom)
|
||||
* should be an integer + 0.5
|
||||
*
|
||||
* @param $r
|
||||
* radius of the rounded corner
|
||||
* should be an integer
|
||||
*
|
||||
* @return float
|
||||
* opacity value between 0 (fully transparent) and 1 (fully opaque).
|
||||
*
|
||||
* OPTIMIZE HERE! This is a really tight loop, potentially getting called
|
||||
* thousands of times
|
||||
*/
|
||||
function _canvasactions_roundedcorners_pixel_opacity($x, $y, $r) {
|
||||
if ($x < 0 || $y < 0) {
|
||||
return 0;
|
||||
}
|
||||
else if ($x > $r || $y > $r) {
|
||||
return 1;
|
||||
}
|
||||
$dist_2 = ($r -$x) * ($r -$x) + ($r -$y) * ($r -$y);
|
||||
$r_2 = $r * $r;
|
||||
if ($dist_2 > ($r + 0.8) * ($r + 0.8)) {
|
||||
return 0;
|
||||
}
|
||||
else if ($dist_2 < ($r -0.8) * ($r -0.8)) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
// this pixel needs special analysis.
|
||||
// thanks to a quite efficient algorithm, we can afford 10x antialiasing :)
|
||||
$opacity = 0.5;
|
||||
if ($x > $y) {
|
||||
// cut the pixel into 10 vertical "stripes"
|
||||
for ($dx = -0.45; $dx < 0.5; $dx += 0.1) {
|
||||
// find out where the rounded corner edge intersects with the stripe
|
||||
// this is plain triangle geometry.
|
||||
$dy = $r - $y - sqrt($r_2 - ($r -$x -$dx) * ($r -$x -$dx));
|
||||
$dy = ($dy > 0.5) ? 0.5 : (($dy < -0.5) ? -0.5 : $dy);
|
||||
// count the opaque part of the stripe.
|
||||
$opacity -= 0.1 * $dy;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// cut the pixel into 10 horizontal "stripes"
|
||||
for ($dy = -0.45; $dy < 0.5; $dy += 0.1) {
|
||||
// this is the math:
|
||||
// ($r-$x-$dx)^2 + ($r-$y-$dy)^2 = $r^2
|
||||
// $dx = $r - $x - sqrt($r^2 - ($r-$y-$dy)^2)
|
||||
$dx = $r - $x - sqrt($r_2 - ($r -$y -$dy) * ($r -$y -$dy));
|
||||
$dx = ($dx > 0.5) ? 0.5 : (($dx < -0.5) ? -0.5 : $dx);
|
||||
$opacity -= 0.1 * $dx;
|
||||
}
|
||||
}
|
||||
return ($opacity < 0) ? 0 : (($opacity > 1) ? 1 : $opacity);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* imageapi_roundedcorners
|
||||
*/
|
||||
function image_imagemagick_roundedcorners($image, $action) {
|
||||
// Based on the imagemagick documentation.
|
||||
// http://www.imagemagick.org/Usage/thumbnails/#rounded
|
||||
// Create arc cut-outs, then mask them.
|
||||
// Draw black triangles and white circles.
|
||||
// draw circle is center: x,y, and a point on the perimeter
|
||||
$corners = array('tl', 'tr', 'bl', 'br');
|
||||
$radii = $action['independent_corners_set']['radii'];
|
||||
$width = $image->info['width'];
|
||||
$height = $image->info['height'];
|
||||
$tl = $radii['tl'];
|
||||
$tr = $radii['tr'];
|
||||
$bl = $radii['bl'];
|
||||
$br = $radii['br'];
|
||||
|
||||
$drawmask = '';
|
||||
if ($tl) {
|
||||
$drawmask .= " fill black polygon 0,0 0,{$tl} {$tl},0";
|
||||
$drawmask .= " fill white circle {$tl},{$tl} {$tl},0";
|
||||
}
|
||||
if ($tr) {
|
||||
$right = $width -$tr;
|
||||
$drawmask .= " fill black polygon {$right},0 {$width},0 {$width},{$tr}";
|
||||
$drawmask .= " fill white circle {$right},{$tr} {$right},0";
|
||||
}
|
||||
if ($bl) {
|
||||
$bottom = $height -$bl;
|
||||
$drawmask .= " fill black polygon 0,{$bottom} 0,{$height} {$bl},{$height}";
|
||||
$drawmask .= " fill white circle {$bl},{$bottom} 0,{$bottom}";
|
||||
}
|
||||
if ($br) {
|
||||
$bottom = $height -$br;
|
||||
$right = $width -$br;
|
||||
$drawmask .= " fill black polygon {$right},{$height} {$width},{$bottom} {$width},{$height}";
|
||||
$drawmask .= " fill white circle {$right},{$bottom} {$width},{$bottom}";
|
||||
}
|
||||
$draw = ' -draw ' . escapeshellarg($drawmask);
|
||||
|
||||
$compose = ' ' . escapeshellcmd('(') . " +clone -threshold -1 $draw " . escapeshellcmd(')') . ' +matte -compose CopyOpacity -composite ';
|
||||
$image->ops[] = $compose;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of theme_hook() for imagecache_ui.module
|
||||
*/
|
||||
function theme_canvasactions_roundedcorners($variables) {
|
||||
$element = $variables['element'];
|
||||
$data = $element['#value'];
|
||||
if (!empty($data['independent_corners_set']['independent_corners'])) {
|
||||
$dimens = join('px | ', $data['independent_corners_set']['radii']) . 'px';
|
||||
}
|
||||
else {
|
||||
$dimens = "Radius: {$data['radius']}px";
|
||||
}
|
||||
return $dimens;
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Test imagecache preset.
|
||||
*
|
||||
* Created on Dec 29, 2009
|
||||
*
|
||||
* @author 'dman' Dan Morrison http://coders.co.nz/
|
||||
*/
|
||||
|
||||
$presets['cheap_dropshadow'] = array (
|
||||
'name' => 'cheap_dropshadow',
|
||||
'#weight' => '3.3',
|
||||
'effects' =>
|
||||
array (
|
||||
-1 => array (
|
||||
'weight' => '-1',
|
||||
'module' => 'imagecache_coloractions',
|
||||
'name' => 'coloractions_convert',
|
||||
'data' => array (
|
||||
'format' => 'image/png',
|
||||
'quality' => '95',
|
||||
),
|
||||
),
|
||||
0 =>
|
||||
array (
|
||||
'weight' => '0',
|
||||
'module' => 'imagecache_canvasactions',
|
||||
'name' => 'canvasactions_definecanvas',
|
||||
'data' =>
|
||||
array (
|
||||
'RGB' =>
|
||||
array (
|
||||
'HEX' => '999999',
|
||||
),
|
||||
'under' => 0,
|
||||
'exact' =>
|
||||
array (
|
||||
'width' => '',
|
||||
'height' => '',
|
||||
'xpos' => 'center',
|
||||
'ypos' => 'center',
|
||||
),
|
||||
'relative' =>
|
||||
array (
|
||||
'leftdiff' => '0',
|
||||
'rightdiff' => '0',
|
||||
'topdiff' => '0',
|
||||
'bottomdiff' => '0',
|
||||
),
|
||||
),
|
||||
),
|
||||
1 =>
|
||||
array (
|
||||
'weight' => '1',
|
||||
'module' => 'imagecache_canvasactions',
|
||||
'name' => 'canvasactions_definecanvas',
|
||||
'data' =>
|
||||
array (
|
||||
'RGB' =>
|
||||
array (
|
||||
'HEX' => '',
|
||||
),
|
||||
'under' => 1,
|
||||
'exact' =>
|
||||
array (
|
||||
'width' => '',
|
||||
'height' => '',
|
||||
'xpos' => 'center',
|
||||
'ypos' => 'center',
|
||||
),
|
||||
'relative' =>
|
||||
array (
|
||||
'leftdiff' => '20',
|
||||
'rightdiff' => '0',
|
||||
'topdiff' => '20',
|
||||
'bottomdiff' => '0',
|
||||
),
|
||||
),
|
||||
),
|
||||
2 =>
|
||||
array (
|
||||
'weight' => '2',
|
||||
'module' => 'imagecache_canvasactions',
|
||||
'name' => 'canvasactions_source2canvas',
|
||||
'data' =>
|
||||
array (
|
||||
'xpos' => 0,
|
||||
'ypos' => 0,
|
||||
'alpha' => '100',
|
||||
),
|
||||
),
|
||||
3 =>
|
||||
array (
|
||||
'weight' => '3',
|
||||
'module' => 'image',
|
||||
'name' => 'image_scale',
|
||||
'data' =>
|
||||
array (
|
||||
'width' => '200',
|
||||
'height' => '100%',
|
||||
'upscale' => 0,
|
||||
),
|
||||
),
|
||||
4 => array (
|
||||
'weight' => '10',
|
||||
'module' => 'imagecache_coloractions',
|
||||
'name' => 'coloractions_convert',
|
||||
'data' => array (
|
||||
'format' => 'image/png',
|
||||
'quality' => '95',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 24 KiB |
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Test imagecache preset.
|
||||
*
|
||||
* Created on Dec 29, 2009
|
||||
*
|
||||
* @author 'dman' Dan Morrison http://coders.co.nz/
|
||||
*/
|
||||
|
||||
$presets['keyword_positioning'] = array (
|
||||
'name' => 'keyword_positioning',
|
||||
'#weight' => 4.2,
|
||||
'effects' => array (
|
||||
array (
|
||||
'weight' => '-1',
|
||||
'module' => 'imagecache_canvasactions',
|
||||
'name' => 'canvasactions_file2canvas',
|
||||
'data' => array (
|
||||
'xpos' => 'right',
|
||||
'ypos' => 'top',
|
||||
'alpha' => '100',
|
||||
'path' => drupal_get_path('module', 'imagecache_testsuite') . "/grid-240x160.png",
|
||||
),
|
||||
),
|
||||
|
||||
array (
|
||||
'weight' => '0',
|
||||
'module' => 'imagecache_canvasactions',
|
||||
'name' => 'canvasactions_file2canvas',
|
||||
'data' => array (
|
||||
'xpos' => '25%',
|
||||
'ypos' => 'bottom-10%',
|
||||
'path' => 'misc/druplicon.png',
|
||||
),
|
||||
),
|
||||
|
||||
array (
|
||||
'weight' => '0',
|
||||
'module' => 'imagecache_canvasactions',
|
||||
'name' => 'canvasactions_file2canvas',
|
||||
'data' => array (
|
||||
'xpos' => '0%',
|
||||
'ypos' => 'top+10%',
|
||||
'path' => 'misc/druplicon.png',
|
||||
),
|
||||
),
|
||||
|
||||
array (
|
||||
'weight' => '0',
|
||||
'module' => 'imagecache_canvasactions',
|
||||
'name' => 'canvasactions_file2canvas',
|
||||
'data' => array (
|
||||
'xpos' => 'right+50',
|
||||
'ypos' => '50%',
|
||||
'path' => 'misc/druplicon.png',
|
||||
),
|
||||
),
|
||||
|
||||
),
|
||||
);
|
||||
|
After Width: | Height: | Size: 9.8 KiB |
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Test imagecache preset.
|
||||
*
|
||||
* Created on Dec 29, 2009
|
||||
*
|
||||
* @author 'dman' Dan Morrison http://coders.co.nz/
|
||||
*/
|
||||
|
||||
$presets['positioned_underlay'] = array (
|
||||
'name' => 'positioned_underlay',
|
||||
'#weight' => 4.4,
|
||||
'effects' => array (
|
||||
0 => array (
|
||||
'module' => 'image',
|
||||
'name' => 'image_scale',
|
||||
'weight' => '0',
|
||||
'data' => array (
|
||||
'width' => '200',
|
||||
'height' => '',
|
||||
'upscale' => 0,
|
||||
),
|
||||
),
|
||||
1 => array (
|
||||
'module' => 'imagecache_canvasactions',
|
||||
'name' => 'canvasactions_canvas2file',
|
||||
'weight' => '1',
|
||||
'data' => array (
|
||||
'xpos' => '50',
|
||||
'ypos' => 'bottom+50',
|
||||
'alpha' => '100',
|
||||
'path' => "$filepath/shiny-bg.png",
|
||||
'dimensions' => 'background',
|
||||
),
|
||||
),
|
||||
4 => array (
|
||||
'weight' => '10',
|
||||
'module' => 'imagecache_coloractions',
|
||||
'name' => 'coloractions_convert',
|
||||
'data' => array (
|
||||
'format' => 'image/png',
|
||||
'quality' => '95',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
After Width: | Height: | Size: 52 KiB |
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Test imagecache preset.
|
||||
*
|
||||
* Created on Dec 29, 2009
|
||||
*
|
||||
* @author 'dman' Dan Morrison http://coders.co.nz/
|
||||
*/
|
||||
|
||||
$presets['rotate_alpha'] = array (
|
||||
'name' => 'rotate_alpha',
|
||||
'#weight' => 1.4,
|
||||
'effects' => array (
|
||||
1 => array (
|
||||
'weight' => '1',
|
||||
'module' => 'image',
|
||||
'name' => 'image_rotate',
|
||||
'data' => array (
|
||||
'degrees' => '15',
|
||||
'random' => 0,
|
||||
'bgcolor' => '',
|
||||
),
|
||||
),
|
||||
3 => array (
|
||||
'weight' => '3',
|
||||
'module' => 'imagecache_coloractions',
|
||||
'name' => 'coloractions_convert',
|
||||
'data' => array (
|
||||
'format' => 'image/png',
|
||||
'quality' => '95',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
After Width: | Height: | Size: 76 KiB |
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Test imagecache preset.
|
||||
*
|
||||
* Created on Dec 29, 2009
|
||||
*
|
||||
* @author 'dman' Dan Morrison http://coders.co.nz/
|
||||
*/
|
||||
|
||||
$presets['rotate_alpha_gif'] = array (
|
||||
'name' => 'rotate_alpha_gif',
|
||||
'#weight' => 1.5,
|
||||
|
||||
'effects' => array (
|
||||
1 => array (
|
||||
'weight' => '1',
|
||||
'module' => 'image',
|
||||
'name' => 'image_rotate',
|
||||
'data' => array (
|
||||
'degrees' => '15',
|
||||
'random' => 0,
|
||||
'bgcolor' => '',
|
||||
),
|
||||
),
|
||||
3 => array (
|
||||
'weight' => '3',
|
||||
'module' => 'imagecache_coloractions',
|
||||
'name' => 'coloractions_convert',
|
||||
'data' => array (
|
||||
'format' => 'image/gif',
|
||||
'quality' => '75',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Test imagecache preset.
|
||||
*
|
||||
* Created on Dec 29, 2009
|
||||
*
|
||||
* @author 'dman' Dan Morrison http://coders.co.nz/
|
||||
*/
|
||||
|
||||
$presets['rotate_scale'] = array (
|
||||
'name' => 'rotate_scale',
|
||||
'#weight' => 1.2,
|
||||
|
||||
'effects' => array (
|
||||
1 => array (
|
||||
'weight' => '1',
|
||||
'module' => 'image',
|
||||
'name' => 'image_rotate',
|
||||
'data' => array (
|
||||
'degrees' => '15',
|
||||
'random' => 0,
|
||||
'bgcolor' => '',
|
||||
),
|
||||
),
|
||||
2 => array (
|
||||
'weight' => '2',
|
||||
'module' => 'image',
|
||||
'name' => 'image_scale',
|
||||
'data' => array (
|
||||
'width' => '',
|
||||
'height' => '150',
|
||||
'upscale' => TRUE,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
After Width: | Height: | Size: 4.8 KiB |
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Test imagecache preset.
|
||||
*
|
||||
* Created on Dec 29, 2009
|
||||
*
|
||||
* @author 'dman' Dan Morrison http://coders.co.nz/
|
||||
*/
|
||||
|
||||
$presets['rotate_scale_alpha'] = array (
|
||||
'name' => 'rotate_scale_alpha',
|
||||
'#weight' => 1.6,
|
||||
|
||||
'effects' => array (
|
||||
1 => array (
|
||||
'weight' => '1',
|
||||
'module' => 'image',
|
||||
'name' => 'image_rotate',
|
||||
'data' => array (
|
||||
'degrees' => '65',
|
||||
'random' => 0,
|
||||
'bgcolor' => '',
|
||||
),
|
||||
),
|
||||
/*
|
||||
* imageapi resize is NOT alpha-safe. This test case proves the bug.
|
||||
* A work-around is to change format before resizing.
|
||||
2 => array (
|
||||
'weight' => '2',
|
||||
'module' => 'imagecache_coloractions',
|
||||
'name' => 'coloractions_convert',
|
||||
'data' => array (
|
||||
'format' => 'image/png',
|
||||
'quality' => '95',
|
||||
),
|
||||
),
|
||||
*/
|
||||
3 => array (
|
||||
'weight' => '3',
|
||||
'module' => 'image',
|
||||
'name' => 'image_scale',
|
||||
'data' => array (
|
||||
'width' => '',
|
||||
'height' => '150',
|
||||
'upscale' => TRUE,
|
||||
),
|
||||
),
|
||||
4 => array (
|
||||
'weight' => '4',
|
||||
'module' => 'imagecache_coloractions',
|
||||
'name' => 'coloractions_convert',
|
||||
'data' => array (
|
||||
'format' => 'image/png',
|
||||
'quality' => '95',
|
||||
),
|
||||
),
|
||||
|
||||
),
|
||||
);
|
||||
|
After Width: | Height: | Size: 28 KiB |
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Test imagecache preset.
|
||||
*
|
||||
* Created on Dec 29, 2009
|
||||
*
|
||||
* @author 'dman' Dan Morrison http://coders.co.nz/
|
||||
*/
|
||||
|
||||
$presets['rounded'] = array (
|
||||
'name' => 'rounded',
|
||||
'#weight' => 3.0,
|
||||
'effects' => array (
|
||||
1 => array (
|
||||
'weight' => '0',
|
||||
'module' => 'imagecache_canvasactions',
|
||||
'name' => 'canvasactions_roundedcorners',
|
||||
'data' => array (
|
||||
'radius' => '25',
|
||||
'antialias' => true,
|
||||
),
|
||||
),
|
||||
2 => array (
|
||||
'weight' => '3',
|
||||
'module' => 'imagecache_coloractions',
|
||||
'name' => 'coloractions_convert',
|
||||
'data' =>array (
|
||||
'format' => 'image/png',
|
||||
'quality' => '95',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
After Width: | Height: | Size: 69 KiB |
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Test imagecache preset.
|
||||
*
|
||||
* Created on Dec 29, 2009
|
||||
*
|
||||
* @author 'dman' Dan Morrison http://coders.co.nz/
|
||||
*/
|
||||
|
||||
$presets['rounded_bl'] = array (
|
||||
'name' => 'rounded_bl',
|
||||
'#weight' => 3.1,
|
||||
'effects' => array (
|
||||
1 => array (
|
||||
'weight' => '0',
|
||||
'module' => 'imagecache_canvasactions',
|
||||
'name' => 'canvasactions_roundedcorners',
|
||||
'data' => array (
|
||||
'radius' => '50',
|
||||
'independent_corners_set' => array (
|
||||
'independent_corners' => 1,
|
||||
'radii' => array (
|
||||
'tl' => '10',
|
||||
'tr' => '0',
|
||||
'bl' => '50',
|
||||
'br' => '10',
|
||||
),
|
||||
),
|
||||
'antialias' => true,
|
||||
),
|
||||
),
|
||||
2 => array (
|
||||
'weight' => '3',
|
||||
'module' => 'imagecache_coloractions',
|
||||
'name' => 'coloractions_convert',
|
||||
'data' =>array (
|
||||
'format' => 'image/png',
|
||||
'quality' => '95',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
After Width: | Height: | Size: 69 KiB |
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Test imagecache preset.
|
||||
*
|
||||
* Created on Dec 29, 2009
|
||||
*
|
||||
* @author 'dman' Dan Morrison http://coders.co.nz/
|
||||
*/
|
||||
|
||||
$presets['rounded_flattened'] = array (
|
||||
'name' => 'rounded_flattened',
|
||||
'#weight' => 3.3,
|
||||
|
||||
'effects' => array (
|
||||
1 => array (
|
||||
'weight' => '0',
|
||||
'module' => 'imagecache_canvasactions',
|
||||
'name' => 'canvasactions_roundedcorners',
|
||||
'data' => array (
|
||||
'radius' => '50',
|
||||
'independent_corners_set' => array (
|
||||
'independent_corners' => 1,
|
||||
'radii' => array (
|
||||
'tr' => '100',
|
||||
'br' => '0',
|
||||
'tl' => '0',
|
||||
'bl' => '0',
|
||||
),
|
||||
),
|
||||
'antialias' => true,
|
||||
),
|
||||
),
|
||||
2 => array (
|
||||
'weight' => '0',
|
||||
'module' => 'imagecache_canvasactions',
|
||||
'name' => 'canvasactions_definecanvas',
|
||||
'data' => array (
|
||||
'RGB' => array (
|
||||
'HEX' => '333333',
|
||||
),
|
||||
'under' => 1,
|
||||
'exact' => array (
|
||||
'width' => '',
|
||||
'height' => '',
|
||||
'xpos' => 'center',
|
||||
'ypos' => 'center',
|
||||
),
|
||||
'relative' => array (
|
||||
'leftdiff' => '2',
|
||||
'rightdiff' => '2',
|
||||
'topdiff' => '2',
|
||||
'bottomdiff' => '2',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Test imagecache preset.
|
||||
*
|
||||
* Created on Dec 29, 2009
|
||||
*
|
||||
* @author 'dman' Dan Morrison http://coders.co.nz/
|
||||
*/
|
||||
|
||||
$presets['watermark_100'] = array (
|
||||
'name' => 'watermark_100',
|
||||
'#weight' => 4.0,
|
||||
'effects' => array (
|
||||
0 => array (
|
||||
'weight' => '0',
|
||||
'module' => 'imagecache_canvasactions',
|
||||
'name' => 'canvasactions_file2canvas',
|
||||
'data' => array (
|
||||
'xpos' => '10',
|
||||
'ypos' => '5',
|
||||
'alpha' => '100',
|
||||
'path' => 'misc/druplicon.png',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
After Width: | Height: | Size: 8.0 KiB |
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Test imagecache preset.
|
||||
*
|
||||
* Created on Dec 29, 2009
|
||||
*
|
||||
* @author 'dman' Dan Morrison http://coders.co.nz/
|
||||
*/
|
||||
|
||||
$presets['watermark_50'] = array (
|
||||
'name' => 'watermark_50',
|
||||
'#weight' => 4.1,
|
||||
'effects' => array (
|
||||
0 => array (
|
||||
'weight' => '0',
|
||||
'module' => 'imagecache_canvasactions',
|
||||
'name' => 'canvasactions_file2canvas',
|
||||
'data' => array (
|
||||
'xpos' => 'right+20',
|
||||
'ypos' => 'bottom',
|
||||
'alpha' => '50',
|
||||
'path' => 'misc/druplicon.png',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
After Width: | Height: | Size: 8.0 KiB |
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
/**
|
||||
* @file Functions to create .htaccess files in public://styles/{image-style}
|
||||
* directories that force the correct Content-Type header.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Checks for all image style if a .htaccess should be created to force a
|
||||
* correct Content-Type header.
|
||||
*/
|
||||
function imagecache_coloractions_create_htaccess_all_styles() {
|
||||
$styles = image_styles();
|
||||
foreach ($styles as $style) {
|
||||
imagecache_coloractions_create_htaccess_for_style($style);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an image style has a convert format image effect and if so, creates
|
||||
* an .htaccess in the folder where the derivatives for this style are stored
|
||||
* to force the correct Content-Type header.
|
||||
*
|
||||
* @param array $style
|
||||
*
|
||||
* @return bool|null
|
||||
* True if .htaccess created successfully, false om error, null if no
|
||||
* .htaccess needed to be created.
|
||||
*/
|
||||
function imagecache_coloractions_create_htaccess_for_style(array $style) {
|
||||
// If we have multiple convert effects in the same style (I found one during
|
||||
// testing) the last determines the mime type.
|
||||
$format = NULL;
|
||||
foreach ($style['effects'] as $effect) {
|
||||
if ($effect['name'] === 'coloractions_convert') {
|
||||
if (!empty($effect['data']['format'])) {
|
||||
$format = $effect['data']['format'];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $format ? imagecache_coloractions_create_htaccess($style['name'], $format) : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an .htaccess file in the folder public://styles/%style_name.
|
||||
*
|
||||
* The folder itself will also be created if necessary.
|
||||
*
|
||||
* @param string $style_name
|
||||
* @param string $mimeType
|
||||
*
|
||||
* @return bool
|
||||
* True on success, false otherwise.
|
||||
*/
|
||||
function imagecache_coloractions_create_htaccess($style_name, $mimeType) {
|
||||
$forceType = "ForceType $mimeType\n";
|
||||
$directory = "public://styles/$style_name";
|
||||
if (!file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
|
||||
watchdog('imagecache_actions', 'Failed to create style directory: %directory', array('%directory' => $directory), WATCHDOG_ERROR);
|
||||
return FALSE;
|
||||
}
|
||||
if (!file_put_contents("$directory/.htaccess", $forceType)) {
|
||||
watchdog('imagecache_actions', 'Failed to create .htaccess in style directory: %directory', array('%directory' => $directory), WATCHDOG_ERROR);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
name = Imagecache Color Actions
|
||||
description = Provides image effects color-shifting, invert colors, brightness, posterize and alpha transparency effects. Also provides a change image format effect.
|
||||
package = Media
|
||||
core = 7.x
|
||||
|
||||
dependencies[] = imagecache_actions
|
||||
dependencies[] = image
|
||||
|
||||
files[] = imagecache_coloractions.module
|
||||
files[] = transparency.inc
|
||||
files[] = tests/green.imagecache_preset.inc
|
||||
|
||||
; Information added by Drupal.org packaging script on 2016-02-19
|
||||
version = "7.x-1.7"
|
||||
core = "7.x"
|
||||
project = "imagecache_actions"
|
||||
datestamp = "1455872655"
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Create an .htaccess file in image style directories that have a change format
|
||||
* image effect to enforce the correct Content-Type header for the derivative
|
||||
* images.
|
||||
*/
|
||||
function imagecache_coloractions_update_7101(&$sandbox) {
|
||||
module_load_include('module', 'image');
|
||||
include_once dirname(__FILE__) . '/imagecache_coloractions.htaccess_creator.inc';
|
||||
imagecache_coloractions_create_htaccess_all_styles();
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
<?php
|
||||
/**
|
||||
* @file Helper functions for the alpha effect.
|
||||
*
|
||||
* @author dan http://coders.co.nz
|
||||
*/
|
||||
|
||||
/**
|
||||
* Image effect form callback for the alpha effect.
|
||||
*
|
||||
* @param array $data
|
||||
* The current configuration for this image effect.
|
||||
*
|
||||
* @return array
|
||||
* The form definition for this effect.
|
||||
*/
|
||||
function coloractions_alpha_form(array $data) {
|
||||
$defaults = array(
|
||||
'flatten' => FALSE,
|
||||
'RGB' => array('HEX' => '#000000'),
|
||||
'opacity' => 0.5,
|
||||
);
|
||||
$data = array_merge($defaults, (array) $data);
|
||||
|
||||
$form = array();
|
||||
$form['help'] = array(
|
||||
'#markup' => t("
|
||||
<p>You can <em>either</em> set the alpha values of the image to a fixed
|
||||
amount by defining opacity, <em>or</em> choose a color and let the
|
||||
darkness of the image pixels define an opacity.
|
||||
These are different effects. Don't do both
|
||||
or you will just get a plain block of color of a certain opacity.
|
||||
")
|
||||
);
|
||||
|
||||
$form['opacity'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Opacity'),
|
||||
'#default_value' => $data['opacity'],
|
||||
'#size' => 3,
|
||||
'#description' => t("
|
||||
A decimal between 0 and 1.
|
||||
You can define the amount of transparency to apply, eg 0.8 (80%) opacity
|
||||
will make the image slightly transparent.
|
||||
Use this with <em>no</em> fill color defined for normal results.
|
||||
If you follow up by flattening the image onto white or grey,
|
||||
this will have the effect of partial desaturation.
|
||||
"),
|
||||
);
|
||||
|
||||
$form['description'] = array(
|
||||
'#value' => t(
|
||||
"<p>Alpha toning is an advanced method of greyscaling or colorizing.
|
||||
It works using transparency, not colour matching.
|
||||
The results of this filter are excellent for using as watermarks,
|
||||
and for 'sepia' type imprints on coloured or textured backgrounds.
|
||||
It converts dark areas of the image to opaque, light to transparent.</p>
|
||||
<p>Note that if you are working with JPEGs, this alpha effect will not last into the final image
|
||||
<em>unless</em> you either <strong>flatten</strong> this image against a background color
|
||||
or image in a later process or <strong>convert</strong> it to a PNG before saving
|
||||
using available imagecache actions.</p>"
|
||||
)
|
||||
);
|
||||
|
||||
$form['RGB'] = imagecache_rgb_form($data['RGB']);
|
||||
$form['RGB']['#type'] = 'fieldset';
|
||||
$form['RGB']['#title'] = t('Fill Color');
|
||||
$form['RGB']['HEX']['#description'] = t("
|
||||
Although this image will end up as an alpha transparency mask,
|
||||
it still has to have some colour to be visible.
|
||||
Black is safe. Dark Sepia #704214 is good too.
|
||||
Set it to nothing to not perform any color shift.
|
||||
");
|
||||
|
||||
$form['flatten'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Flatten Transparency'),
|
||||
'#default_value' => $data['flatten'],
|
||||
'#return_value' => TRUE,
|
||||
'#description' => t("The opposite of adding alpha transparency, 'flatten' will place the given colour solidly behind the image. Use this if you can't trust IE, or you really do want the image filled in with a solid colour."),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements theme_hook() for the alpha effect summary.
|
||||
*
|
||||
* @param array $variables
|
||||
* An associative array containing:
|
||||
* - data: The current configuration for this image effect.
|
||||
*
|
||||
* @return string
|
||||
* The HTML for the summary of this image effect.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_coloractions_alpha_summary(array $variables) {
|
||||
$data = $variables['data'];
|
||||
return ($data['flatten'] ? t("Flatten") : t("Transparent"))
|
||||
. ($data['opacity'] ? " : " . ($data['opacity'] * 100) . '%' : '')
|
||||
. " : " . theme_imagecacheactions_rgb($data['RGB']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Image effect callback for the alpha effect.
|
||||
*
|
||||
* Either convert light parts of an image to see-through, or place a solid
|
||||
* colour behind areas that would otherwise be see-though
|
||||
*
|
||||
* To save a partially transparent image, the image resource must be switched to
|
||||
* PNG. REMEMBER TO SWITCH IT BACK if needed.
|
||||
*
|
||||
* @param stdClass $image
|
||||
* @param array $data
|
||||
*
|
||||
* @return bool
|
||||
* true on success, false otherwise.
|
||||
*/
|
||||
function coloractions_alpha_effect(stdClass $image, array $data) {
|
||||
// @todo: Extract to GD specific function.
|
||||
if (!$data['flatten']) {
|
||||
// Given an image, convert dark areas to opaque, light to transparent.
|
||||
return png_color2alpha($image, $data['RGB']['HEX'], $data['opacity']);
|
||||
}
|
||||
else {
|
||||
// Do the opposite, flatten the transparency ONTO the given color.
|
||||
$info = $image->info;
|
||||
|
||||
if (!$info) {
|
||||
watchdog('imagecache_actions', "Problem converting image to fill behind. Source image returned no info");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$base_image = imagecreatetruecolor($info['width'], $info['height']);
|
||||
imagesavealpha($base_image, TRUE);
|
||||
imagealphablending($base_image, FALSE);
|
||||
|
||||
// Start with a solid color.
|
||||
$background_rgb = imagecache_actions_hex2rgba($data['RGB']['HEX']);
|
||||
|
||||
// Setting the background color here solid is what flattens the image.
|
||||
// But what I really want to do is set it colored rgb AND 100% transparent,
|
||||
// in the hope that a failure to render transparency would instead render
|
||||
// THAT colour.
|
||||
$background_color = @imagecolorallocatealpha($base_image, $background_rgb['red'], $background_rgb['green'], $background_rgb['blue'], 0);
|
||||
// But that still doesn't work. Yet somehow I've seen transparent images
|
||||
// that fallback to white, not silver.
|
||||
|
||||
imagefill($base_image, 0, 0, $background_color);
|
||||
|
||||
// And set the overlay behavior back again.
|
||||
imagealphablending($base_image, TRUE);
|
||||
|
||||
// Place the current image over it.
|
||||
if ($result = imagecopy($base_image, $image->resource, 0, 0, 0, 0, $info['width'], $info['height'])) {
|
||||
imagedestroy($image->resource);
|
||||
$image->resource = $base_image;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This achieves a tonal effect by converting the images combined tone and
|
||||
* existing transparency into one shade value. This is then used as the ALPHA
|
||||
* transparency for that pixel, while the whole thing is coloured the same
|
||||
* shade. Images 'grey toned' in this manner should sit smoothly on any
|
||||
* background.
|
||||
*
|
||||
* With no color set, use the existing hue.
|
||||
*
|
||||
* To save a partially transparent image, the image resource must be switched to
|
||||
* PNG. ... or maybe not. Just flatten it yourself, or switch the format
|
||||
* yourself. This hack would produce side effects otherwise.
|
||||
*
|
||||
* This algorithm runs maths per-pixel, and therefore is incredibly much more
|
||||
* inefficient than any native routine. Will kill the server on large images.
|
||||
*
|
||||
* @param stdClass $image
|
||||
* @param string $color
|
||||
* @param float $opacity
|
||||
* between 0 transparent and 1 solid.
|
||||
*
|
||||
* @return bool
|
||||
* true on success, false otherwise.
|
||||
*/
|
||||
function png_color2alpha(stdClass $image, $color, $opacity = NULL) {
|
||||
$info = $image->info;
|
||||
if (!$info) {
|
||||
return FALSE;
|
||||
}
|
||||
$im1 = $image->resource;
|
||||
|
||||
imagesavealpha($im1, TRUE);
|
||||
imagealphablending($im1, FALSE);
|
||||
|
||||
if ($color) {
|
||||
$background = imagecache_actions_hex2rgba($color);
|
||||
}
|
||||
$width = imagesx($im1);
|
||||
$height = imagesy($im1);
|
||||
|
||||
if (($width * $height) > (1200 * 1200)) {
|
||||
watchdog('imagecache_actions', __FUNCTION__ . " on {$image->source}. Image is TOO BIG to run the per-pixel algorithm. Aborting.");
|
||||
return FALSE;
|
||||
}
|
||||
for ($i = 0; $i < $height; $i++) {
|
||||
//this loop traverses each row in the image
|
||||
for ($j = 0; $j < $width; $j++) {
|
||||
//this loop traverses each pixel of each row
|
||||
// Get the color & alpha info of the current pixel.
|
||||
$retrieved_color = imagecolorat($im1, $j, $i); // an index
|
||||
$rgba_array = imagecolorsforindex($im1, $retrieved_color);
|
||||
$alpha = 127;
|
||||
|
||||
// Calculate the total shade value of this pixel.
|
||||
|
||||
// If the rule sets a color, then the darkness of the existing
|
||||
// pixel will define the desired alpha value.
|
||||
if ($color) {
|
||||
$lightness = ($rgba_array['red'] + $rgba_array['green'] + $rgba_array['blue']) / 3;
|
||||
// Need to flip the numbers around before doing maths.
|
||||
//$opacity = 1-($rgba_array['alpha']/127);
|
||||
//$darkness = 1-($lightness/256); // 0 is white, 1 is black
|
||||
//$visibility = $darkness * $opacity;
|
||||
//$alpha = (1-$visibility) * 127;
|
||||
$alpha = (1 - ((1 - ($lightness / 256)) * (1 - ($rgba_array['alpha'] / 127)))) * 127;
|
||||
}
|
||||
// If color is NOT set, then the existing color is passed though, only
|
||||
// made somewhat transparent.
|
||||
if (!$color) {
|
||||
$background = $rgba_array;
|
||||
}
|
||||
if ($opacity) {
|
||||
// It's a user-defined alpha value.
|
||||
$alpha = $alpha * $opacity;
|
||||
}
|
||||
|
||||
// Paint the pixel.
|
||||
/** @noinspection PhpUndefinedVariableInspection */
|
||||
$color_to_paint = imagecolorallocatealpha($image->resource, $background['red'], $background['green'], $background['blue'], $alpha);
|
||||
imagesetpixel($image->resource, $j, $i, $color_to_paint);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
README
|
||||
------
|
||||
README for the custom actions effect module.
|
||||
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
Hard dependencies:
|
||||
- Imagecache actions.
|
||||
- Image (Drupal core).
|
||||
|
||||
Soft dependencies/recommended modules:
|
||||
- Imagemagick (preferred toolkit).
|
||||
- PHP filter (Drupal core).
|
||||
|
||||
|
||||
Which toolkit?
|
||||
--------------
|
||||
Personally, I prefer the imagemagick toolkit:
|
||||
- It is better in anti-aliasing, try to rotate an image using both toolkits and
|
||||
you will see what I mean.
|
||||
- It does not execute in the PHP memory space, so is not restricted by the
|
||||
memory_limit PHP setting.
|
||||
- The GD toolkit will, at least on my Windows configuration, keep font files
|
||||
open after a text operation, so you cannot delete, move or rename it anymore.
|
||||
|
||||
|
||||
Installing
|
||||
----------
|
||||
As usual. After enabling the module you can add custom actions to images.
|
||||
|
||||
|
||||
Custom action PHP snippets
|
||||
--------------------------
|
||||
Given the correct permission, the custom action effect allows you to write your
|
||||
own PHP snippet that does the requested processing on the image. How it can do
|
||||
so, depends on the toolkit.
|
||||
|
||||
For all toolkits, the snippet should return true to indicate success and false
|
||||
to indicate failure.
|
||||
|
||||
GD
|
||||
--
|
||||
The GD image resource is available in $image->resource. You can call the GD
|
||||
functions on this resource. This effect will query the width and height after
|
||||
your processing, so you don't have to change that yourself.
|
||||
|
||||
Imagemagick
|
||||
-----------
|
||||
All real image processing is done at the end, if all effects have added their
|
||||
command line arguments to the $image->ops array. So your custom action should
|
||||
add the imagemagick commands and its parameters by adding new string entries to
|
||||
the end of that array.
|
||||
|
||||
If your commands change the width or height of the resulting image, you should
|
||||
record so by changing $image->info['width'] and/or $image->info['height'].
|
||||
|
||||
General
|
||||
-------
|
||||
To ease your task, this effect makes some information regarding the image being
|
||||
processed available in 2 variables: $image and $image_context. These variables
|
||||
are readily available in your snippet.
|
||||
|
||||
$image is an object containing the following properties:
|
||||
- source: string, the source of the image, e.g. public://photo.jpg
|
||||
- info: array, example data:
|
||||
- width (int) 180
|
||||
- height (int) 180
|
||||
- extension (string) png
|
||||
- mime_type (string) image/png
|
||||
- file_size (int) 4417
|
||||
- toolkit: string, imagemagick or GD
|
||||
- resource: resource. The GD image resource.
|
||||
- ops: array. An array of strings with the ImageMagick commands.
|
||||
|
||||
$image_context is an associative array containing:
|
||||
- effect_data: array, the data of this image effect, example data for the custom
|
||||
action effect:
|
||||
- php (string)
|
||||
- managed_file: object|null. A managed file object containing these properties:
|
||||
- fid (string) 2
|
||||
- uid (string) 1
|
||||
- filename (string) photo.jpg
|
||||
- uri (string) public://photo.jpg
|
||||
- filemime (string) image/jpeg
|
||||
- filesize (string) 445751
|
||||
- status (string) 1
|
||||
- timestamp (string) 1327525851
|
||||
- metatags Array [0]
|
||||
- rdf_mapping Array [0]
|
||||
- referring_entities: array|null. A nested array with (fully loaded) entities
|
||||
referring to the current image. The 1st level of entries is keyed by the field
|
||||
name, the 2nd by entity type, and the 3rd by entity id. Example data:
|
||||
- field_photo Array [1]
|
||||
- node Array [1]
|
||||
- 12 Object of: stdClass
|
||||
- nid (string) 12
|
||||
- vid (string) 12
|
||||
- type (string) page
|
||||
- author ...
|
||||
- timestamp ...
|
||||
- ...
|
||||
- entity: object|null, the 1st entity in referring_entities. This is for easy
|
||||
access to the referring entity if it may be assumed that only 1 entity is
|
||||
referring to the current image.
|
||||
- image_field: array|null, the 1st image field in entity that is referring to
|
||||
the current image. This is for easy access to the image field data if it may
|
||||
be assumed that only 1 image field is referring to the current image. Example
|
||||
data:
|
||||
- fid (int) 2
|
||||
- alt (string) ...
|
||||
- title (string) ...
|
||||
- ...
|
||||
|
||||
Of course there are many other possible useful globals. Think of:
|
||||
- base_url
|
||||
- base_path
|
||||
- base_root
|
||||
- is_https
|
||||
- user
|
||||
- language
|
||||
and of course $_SERVER and $_GET.
|
||||
|
||||
Using these information you can access entity data as follows:
|
||||
|
||||
Specific case (1 entity, of known entity_type, referring to the image):
|
||||
<?php
|
||||
$entity_type = 'node';
|
||||
$field_name = 'my_field';
|
||||
$entity = $image_context['entity'];
|
||||
$field = field_get_items($entity_type, $entity, $field_name);
|
||||
?>
|
||||
|
||||
Or the more general case (not knowing the referring type, or multiple entities
|
||||
that may be referring to the image):
|
||||
<?php
|
||||
$referring_entities = $image_context['referring_entities'];
|
||||
foreach ($referring_entities as $field_name => $field_referring_entities) {
|
||||
foreach ($field_referring_entities as $entity_type => $entities) {
|
||||
foreach ($entities as $entity_id => $entity) {
|
||||
$field = field_get_items($entity_type, $entity, $field_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,14 @@
|
||||
name = Imagecache Custom Actions
|
||||
description = Provides the custom and subroutine image effects.
|
||||
package = Media
|
||||
core = 7.x
|
||||
|
||||
dependencies[] = imagecache_actions
|
||||
dependencies[] = image
|
||||
|
||||
; Information added by Drupal.org packaging script on 2016-02-19
|
||||
version = "7.x-1.7"
|
||||
core = "7.x"
|
||||
project = "imagecache_actions"
|
||||
datestamp = "1455872655"
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
/**
|
||||
* Rename 'text' to 'php' in custom action effect data.
|
||||
*/
|
||||
function imagecache_customactions_update_7100(/*&$sandbox*/) {
|
||||
$effects = db_select('image_effects')
|
||||
->fields('image_effects')
|
||||
->condition('name', 'imagecache_customactions', '=')
|
||||
->execute()
|
||||
->fetchAll();
|
||||
foreach ($effects as $effect) {
|
||||
$data = unserialize($effect->data);
|
||||
if (array_key_exists('text', $data)) {
|
||||
$data['php'] = $data['text'];
|
||||
unset($data['text']);
|
||||
$data = serialize($data);
|
||||
db_update('image_effects')
|
||||
->condition('ieid', $effect->ieid)
|
||||
->fields(array('data' => $data))
|
||||
->execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file Allows advanced users to code their own PHP image manipulation routines
|
||||
* as part of image style processing.
|
||||
*
|
||||
* @author Originally contributed by crea https://drupal.org/node/325103#comment-
|
||||
* 1076011
|
||||
*
|
||||
* @author merged into imagecache_actions by dman http://coders.co.nz
|
||||
*
|
||||
* custom action effect:
|
||||
* @todo: add description field that editors can use to define their own summary?
|
||||
* @todo: add form field asking if dimensions stay the same (or if the new dimensions are known).
|
||||
* subroutine effect:
|
||||
* @todo: use isid to allow for image style renaming, but also use name to allow export and import (features)
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Implements hook_image_effect_info().
|
||||
*
|
||||
* Defines information about the supported effects.
|
||||
*/
|
||||
function imagecache_customactions_image_effect_info() {
|
||||
$effects = array();
|
||||
|
||||
$effects['imagecache_customactions'] = array(
|
||||
'label' => t('Custom action'),
|
||||
'help' => t('Runs custom PHP code.'),
|
||||
'effect callback' => 'imagecache_customactions_effect',
|
||||
'dimensions callback' => 'imagecache_customactions_dimensions',
|
||||
'form callback' => 'imagecache_customactions_form',
|
||||
'summary theme' => 'imagecache_customactions_summary',
|
||||
);
|
||||
|
||||
$effects['imagecache_subroutine'] = array(
|
||||
'label' => t('Subroutine'),
|
||||
'help' => t('Runs another defined preset on the image.'),
|
||||
'effect callback' => 'imagecache_subroutine_effect',
|
||||
'dimensions callback' => 'imagecache_subroutine_dimensions',
|
||||
'form callback' => 'imagecache_subroutine_form',
|
||||
'summary theme' => 'imagecache_subroutine_summary',
|
||||
);
|
||||
|
||||
return $effects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_theme().
|
||||
*
|
||||
* Registers theme functions for the effect summaries.
|
||||
*/
|
||||
function imagecache_customactions_theme() {
|
||||
return array(
|
||||
'imagecache_customactions_summary' => array(
|
||||
'variables' => array('data' => NULL),
|
||||
),
|
||||
'imagecache_subroutine_summary' => array(
|
||||
'variables' => array('data' => NULL),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_image_style_flush().
|
||||
*
|
||||
* This hook checks if the image style that is being flushed is used in a
|
||||
* subroutine effect. If so, the style that contains the subroutine effect
|
||||
* should be flushed as well.
|
||||
*
|
||||
* This may lead to recursive calls to image_style_flush() and thus to this
|
||||
* hook. Without loops in styles that call each other as subroutine, this
|
||||
* recursion will always end.
|
||||
*
|
||||
* @param array $flushed_style
|
||||
* The image style that is being flushed.
|
||||
*/
|
||||
function imagecache_customactions_image_style_flush(/*array*/ $flushed_style) {
|
||||
$styles = image_styles();
|
||||
foreach ($styles as $style) {
|
||||
if ($style['name'] !== $flushed_style['name']) {
|
||||
foreach ($style['effects'] as $effect) {
|
||||
if ($effect['name'] === 'imagecache_subroutine') {
|
||||
if (isset($effect['data']['subroutine_presetname']) && $effect['data']['subroutine_presetname'] === $flushed_style['name']) {
|
||||
image_style_flush($style);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Image effect form callback for the custom action effect.
|
||||
*
|
||||
* Note that this is not a complete form, it only contains the portion of the
|
||||
* form for configuring the effect options. Therefore it does not not need to
|
||||
* include metadata about the effect, nor a submit button.
|
||||
*
|
||||
* @param array $data
|
||||
* The current configuration for this image effect.
|
||||
*
|
||||
* @return array
|
||||
* The form definition for this effect.
|
||||
*/
|
||||
function imagecache_customactions_form(array $data) {
|
||||
// Add defaults.
|
||||
$data += array('php' => 'return TRUE;');
|
||||
|
||||
// Note: we also need to check for the existence of the module: admin has
|
||||
// all rights, so user_acccess(...) returns TRUE even if the module is not
|
||||
// enabled and the permission does not exist.
|
||||
$allow_php = module_exists('php') && user_access('use PHP for settings');
|
||||
|
||||
$form = array(
|
||||
'php' => array(
|
||||
'#type' => 'textarea',
|
||||
'#rows' => 12,
|
||||
'#title' => t('PHP code'),
|
||||
'#default_value' => $data['php'],
|
||||
'#disabled' => !$allow_php,
|
||||
'#description' => t("<p>A piece of PHP code that modifies the image.
|
||||
It should return a boolean indicating success or failure.
|
||||
You will need the '%use_php' permission, defined by the 'PHP filter' module.
|
||||
See the help for an extensive explanation of the possibilities.</p>",
|
||||
array('%use_php' => t('Use PHP for settings'))),
|
||||
'#wysiwyg' => FALSE,
|
||||
),
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements theme_hook() for the custom action effect summary.
|
||||
*
|
||||
* param array $variables
|
||||
* An associative array containing:
|
||||
* - data: The current configuration for this image effect.
|
||||
*
|
||||
* @return string
|
||||
* The HTML for the summary of this image effect.
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_imagecache_customactions_summary(/*array $variables*/) {
|
||||
return 'Custom PHP code';
|
||||
}
|
||||
|
||||
/**
|
||||
* Image effect callback for the custom action effect.
|
||||
*
|
||||
* @param stdClass $image
|
||||
* @param array $data
|
||||
*
|
||||
* @return boolean
|
||||
* true on success, false otherwise.
|
||||
*/
|
||||
function imagecache_customactions_effect(stdClass $image, array $data) {
|
||||
// Check that the PHP filter module is enabled.
|
||||
$result = module_exists('php');
|
||||
if ($result) {
|
||||
// Get context about the image.
|
||||
module_load_include('inc', 'imagecache_actions', 'utility');
|
||||
$GLOBALS['image_context'] = imagecache_actions_get_image_context($image, $data);
|
||||
$GLOBALS['image'] = $image;
|
||||
|
||||
$result = php_eval('<' . '?php global $image, $image_context; ' . $data['php'] . ' ?' . '>');
|
||||
// php_eval returns '1' if the snippet returns true.
|
||||
$result = $result === '1';
|
||||
|
||||
unset($GLOBALS['image']);
|
||||
unset($GLOBALS['image_context']);
|
||||
}
|
||||
|
||||
if ($result && $image->toolkit == 'GD') {
|
||||
$image->info['width'] = imagesx($image->resource);
|
||||
$image->info['height'] = imagesy($image->resource);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Image dimensions callback for the custom action effect.
|
||||
*
|
||||
* @param array $dimensions
|
||||
* Dimensions to be modified - an associative array containing the items
|
||||
* 'width' and 'height' (in pixels).
|
||||
* param array $data
|
||||
* An associative array containing the effect data.
|
||||
*/
|
||||
function imagecache_customactions_dimensions(array &$dimensions/*, array $data*/) {
|
||||
$dimensions['width'] = NULL;
|
||||
$dimensions['height'] = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subroutine - an imagecache action that just calls another one.
|
||||
*
|
||||
* Contributed by Alan D
|
||||
* https://drupal.org/node/618784
|
||||
*
|
||||
* Reworked into customactions by dman 2010-07
|
||||
*/
|
||||
|
||||
/**
|
||||
* Image effect form callback for the subroutine effect.
|
||||
*
|
||||
* @param array $data
|
||||
* The current configuration for this image effect.
|
||||
*
|
||||
* @return array
|
||||
* The form definition for this effect.
|
||||
*/
|
||||
function imagecache_subroutine_form(array $data) {
|
||||
// Add defaults.
|
||||
$data += array('subroutine_presetname' => '');
|
||||
|
||||
// List available image styles.
|
||||
// The PASS_THROUGH parameter is new as of D7.23, and is added here to prevent
|
||||
// image_style_options() from double-encoding the human-readable image style
|
||||
// name, since the form API will already sanitize options in a select list.
|
||||
$styles = image_style_options(TRUE, PASS_THROUGH);
|
||||
//@todo: unset the current style to prevent obvious recursion.
|
||||
|
||||
$form = array();
|
||||
|
||||
$form['subroutine_presetname'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Image style to call'),
|
||||
'#default_value' => $data['subroutine_presetname'],
|
||||
'#options' => $styles,
|
||||
'#required' => TRUE,
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements theme_hook() for the subroutine effect summary.
|
||||
*
|
||||
* @param array $variables
|
||||
* An associative array containing:
|
||||
* - data: The current configuration for this image effect.
|
||||
*
|
||||
* @return string
|
||||
* The HTML for the summary of this image effect.
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_imagecache_subroutine_summary(array $variables) {
|
||||
$data = $variables['data'];
|
||||
|
||||
module_load_include('inc', 'imagecache_actions', 'utility');
|
||||
$label = imagecache_actions_get_style_label($data['subroutine_presetname']);
|
||||
return t('Apply image style %label', array('%label' => $label));
|
||||
}
|
||||
|
||||
/**
|
||||
* Image effect callback for the subroutine effect.
|
||||
*
|
||||
* @param stdClass $image
|
||||
* @param array $data
|
||||
*
|
||||
* @return boolean
|
||||
* true on success, false otherwise.
|
||||
*/
|
||||
function imagecache_subroutine_effect(stdClass $image, array $data) {
|
||||
$result = FALSE;
|
||||
if ($style = image_style_load($data['subroutine_presetname'])) {
|
||||
$result = TRUE;
|
||||
foreach ($style['effects'] as $effect) {
|
||||
$result = $result && image_effect_apply($image, $effect);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Image dimensions callback for the subroutine effect.
|
||||
*
|
||||
* @param array $dimensions
|
||||
* Dimensions to be modified - an array with components width and height, in
|
||||
* pixels.
|
||||
* @param array $data
|
||||
* An array with the effect options.
|
||||
*/
|
||||
function imagecache_subroutine_dimensions(array &$dimensions, array $data) {
|
||||
// Let the subroutine transform the dimensions.
|
||||
image_style_transform_dimensions($data['subroutine_presetname'], $dimensions);
|
||||
}
|
||||
|
After Width: | Height: | Size: 314 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 251 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 63 KiB |
@@ -0,0 +1,146 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>
|
||||
Aspect Switcher
|
||||
</title>
|
||||
</head>
|
||||
<body>
|
||||
<h3>
|
||||
Using aspect switcher to create a 'square' setting.
|
||||
</h3>
|
||||
<p>
|
||||
This is done through "chaining" two switches - "is it quite
|
||||
wide or not?", then "is it quite tall or not?" which leaves
|
||||
us with "must be square then."
|
||||
</p>
|
||||
<p>
|
||||
First we create the three sizes we will be using,
|
||||
small-landscape, small-square, small-portrait. I'll just set
|
||||
those up with scale_and_crop.
|
||||
</p>
|
||||
<p>
|
||||
We want wide images up to a ratio of 1:0.75 to be rendered
|
||||
wide. We want squarish images, with an aspect between 1:0.75
|
||||
and 1:1.25 to be rendered square, and anything taller to be
|
||||
rendered tall.
|
||||
</p>
|
||||
<p>
|
||||
To do this, we chain 2 rules. We need to build them
|
||||
backwards, the smaller sub-rule first, but to understand, I'l
|
||||
list them top down.
|
||||
</p>
|
||||
<p>
|
||||
Rule 1. is the master rule, <strong>3-aspects</strong>
|
||||
</p>
|
||||
<p>
|
||||
if ratio is less than 1:.75, use small-landscape. If greater,
|
||||
<strong>proceed to rule 2</strong>.
|
||||
</p>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Rule 2. <strong>square-or-portrait</strong>
|
||||
</p>
|
||||
<p>
|
||||
if ratio is less than 1:1.25, use small-square. If greater,
|
||||
use small-portrait.
|
||||
</p>
|
||||
<p>
|
||||
To do this, we use the aspect switcher to link to the two
|
||||
sizes, and the <em>ratio adjustment</em> to move
|
||||
the switching point a little. Set the ratio adjustment to
|
||||
1.25
|
||||
</p>
|
||||
<p>
|
||||
With these (5!) rules in place, you can get the desired
|
||||
effect. This is a little trickier than just making a 'square'
|
||||
setting, but it allows for the required fudge factor to
|
||||
handle almost-square images.
|
||||
</p>
|
||||
<p>
|
||||
You can nudge the adjustment factor to be looser or tighter.
|
||||
You can create even more chained rules, and define a
|
||||
'super-wide' size.
|
||||
</p>
|
||||
<table border="1" cellpadding="1" cellspacing="1">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td rowspan="1" colspan="1">
|
||||
small-landscape
|
||||
</td>
|
||||
<td rowspan="1" colspan="1">
|
||||
[Scale And Crop] width: 200, height: 100
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan="1" colspan="1">
|
||||
small-portrait
|
||||
</td>
|
||||
<td rowspan="1" colspan="1">
|
||||
[Scale And Crop] width: 100, height: 200
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan="1" colspan="1">
|
||||
small-square
|
||||
</td>
|
||||
<td rowspan="1" colspan="1">
|
||||
[Scale And Crop] width: 140, height: 140
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan="1" colspan="1">
|
||||
small-square-or-portrait
|
||||
</td>
|
||||
<td rowspan="1" colspan="1">
|
||||
[Aspect Switcher] Portrait
|
||||
size: <strong>small-portrait</strong>. Landscape
|
||||
size: <strong>small-square</strong> (switch
|
||||
at 1:1.25)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan="1" colspan="1">
|
||||
small-3-aspects
|
||||
</td>
|
||||
<td rowspan="1" colspan="1">
|
||||
[Aspect Switcher] Portrait
|
||||
size: <strong>small-square-or-portrait</strong>.
|
||||
Landscape
|
||||
size: <strong>small-landscape</strong> (switch
|
||||
at 1:.75)
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>
|
||||
The illustration shows the result of this set-up on a
|
||||
collection of images. The listed dimensions are those of the
|
||||
source images. You'll see that the mostly-square ones are
|
||||
rendered square.
|
||||
</p>
|
||||
<img src="../docs/aspect-chaining.png" alt="Illustration of several different sized images passing through the above ruleset."/>
|
||||
<p>
|
||||
The rule being applied is: 1 Is it wide?
|
||||
</p>
|
||||
<p>
|
||||
For image 250x300, the aspect is ( 250/300 = 0.83 ) Normally
|
||||
that number (less than 1) would be classified as 'portrait',
|
||||
and with the adjustment (*0.75) that is still true, so the
|
||||
processing passes through to the portrait preset.
|
||||
</p>
|
||||
<p>
|
||||
rule #2 it it tall?
|
||||
</p>
|
||||
<p>
|
||||
This preset however does a different set of maths, and
|
||||
multiplies the aspect by 1.25, producing a result that causes
|
||||
it to trigger to 'landscape' choice. 'landscape' at this
|
||||
point is set to be the 'square' preset. And we get what we
|
||||
wanted.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
Komika font by APOSTROPHIC LABS:
|
||||
http://moorstation.org/typoasis/designers/lab/index.htm.
|
||||
|
||||
Below the license as was packaged with the font download:
|
||||
|
||||
Here is the "Read Me" from the original http://www.apostrophiclab.com website:
|
||||
|
||||
Archived here: http://web.archive.org/web/20030408055445/www.hardcovermedia.com/lab/Pages/info.html
|
||||
|
||||
and here: http://apostrophiclab.pedroreina.net/info.html
|
||||
|
||||
-----------
|
||||
|
||||
Apostrophic Laboratories does not collect or relay any personal information about its visitors.
|
||||
|
||||
Apostrophic Laboratories is not affiliated with the company that provides its web hosting service.
|
||||
|
||||
Apostrophic Laboratories is not affiliated with any third party advertising service. This lab will always be advertisement-free to maintain the spirit and integrity of freedom of information that the world wide web was intended to represent.
|
||||
|
||||
The fonts on this site are freeware and can be used as they are in any context without permission from Apostrophic Laboratories, except to produce material that is racist, criminal and/or illegal in nature. It is prohibited to modify any Apostrophic Laboratories font(s) for repackaging and/or re-release without an express written authorization by the designer(s) of the font(s) or Apostrophic Laboratories. Under no circumstance shall any Apostrophic Laboratories design or font design be sold or purchased. Email info@apostrophiclab.com if you want more information.
|
||||
|
||||
The Apostrophic Laboratories site and its contents are the property of Apostrophic Laboratories and the contents' creators. It is prohibited to use the graphic designs shown on this site or any of the site's elements without obtaining written authorization from the designer(s) and/or developer(s) of the content in question. Email info@apostrophiclab.com if you want more information.
|
||||
|
||||
Read everything written by Kurt Vonnegut.
|
||||
Hear everything written by Mozart.
|
||||
Live every day like it is your first.
|
||||
Smell the flowers.
|
||||
Touch the faces of babies.
|
||||
Run in the rain.
|
||||
Eat pop corn.
|
||||
|
||||
The following constitutes the different methods of contacting Apostrophic Laboratories.
|
||||
Web: http://www.apostrophiclab.com
|
||||
Email: info@apostrophiclab.com
|
||||
For individual designer email addresses, click here.
|
||||
Address: Apostrophic Laboratories, 343 Kingswood Road, Toronto, Ontario, Canada M4E 3N8
|
||||
@@ -0,0 +1,24 @@
|
||||
Blokletters fonts by Lefly Fonts: http://lefly.vepar.nl/ under the following
|
||||
license:
|
||||
|
||||
You are free:
|
||||
|
||||
to Share — to copy, distribute and transmit the work
|
||||
to Remix — to adapt the work
|
||||
|
||||
Under the following conditions:
|
||||
|
||||
Attribution — You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work).
|
||||
|
||||
Share Alike — If you alter, transform, or build upon this work, you may distribute the resulting work only under the same or similar license to this one.
|
||||
|
||||
With the understanding that:
|
||||
|
||||
Waiver — Any of the above conditions can be waived if you get permission from the copyright holder.
|
||||
|
||||
Other Rights — In no way are any of the following rights affected by the license:
|
||||
- Your fair dealing or fair use rights;
|
||||
- The author's moral rights;
|
||||
- Rights other persons may have either in the work itself or in how the work is used, such as publicity or privacy rights.
|
||||
|
||||
Notice — For any reuse or distribution, you must make clear to others the license terms of this work. The best way to do this is with a link to this web page.
|
||||
@@ -0,0 +1,93 @@
|
||||
Copyright (c) 2011, Vernon Adams (vern@newtypography.co.uk),
|
||||
with Reserved Font Name Pacifico.
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
@@ -0,0 +1,274 @@
|
||||
README
|
||||
------
|
||||
README for the Image effect text module.
|
||||
|
||||
Author Erwin Derksen (fietserwin: https://drupal.org/user/750928)
|
||||
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
Hard dependencies:
|
||||
- Imagecache actions.
|
||||
- Image (Drupal core).
|
||||
|
||||
Soft dependencies/recommended modules:
|
||||
- Imagemagick (preferred toolkit, https://drupal.org/project/imagemagick).
|
||||
- PHP filter (Drupal core, if yuo want to use PHP to create the text to render).
|
||||
- System stream wrapper (https://drupal.org/project/system_stream_wrapper)
|
||||
- Remote stream wrapper (https://drupal.org/project/remote_stream_wrapper)
|
||||
The latter 2 provide additional stream wrappers. Especially the system stream
|
||||
wrapper is very handy as it provides, among others, a module:// and theme://
|
||||
wrapper.
|
||||
|
||||
|
||||
Toolkit
|
||||
-------
|
||||
Personally, I prefer the imagemagick toolkit:
|
||||
- It is better in anti-aliasing, try to rotate an image using both toolkits and
|
||||
you will see what I mean.
|
||||
- It does not execute in the PHP memory space, so is not restricted by the
|
||||
memory_limit PHP setting.
|
||||
- The GD toolkit will, at least on my Windows configuration, keep the font file
|
||||
open after a text operation, so you cannot delete, move or rename it anymore.
|
||||
- This module does a better job with Imagemagick (see below).
|
||||
|
||||
|
||||
Installing
|
||||
----------
|
||||
As usual. After enabling the module you can add texts to images. This image
|
||||
effect works with both the GD and imagemagick toolkit, though results differ
|
||||
depending on the toolkit you use.
|
||||
|
||||
|
||||
More information about the effect data options
|
||||
----------------------------------------------
|
||||
|
||||
Font
|
||||
----
|
||||
This module comes with some free fonts so you can easily test this effect.
|
||||
Please read their respective licences.
|
||||
|
||||
For real use, you normally want to use your own font as dictated by the website
|
||||
design. The font types supported depend on the toolkit in use, but at least ttf
|
||||
files will always work. This option accepts either:
|
||||
- 1 of the (enabled) scheme's:
|
||||
* public://
|
||||
* private:// Preferred for site specific masks, overlays, etc, that do not
|
||||
need to be shared publicly.
|
||||
* temporary:// Unlikely to be useful, but supported anyway as all schemes are
|
||||
supported.
|
||||
* module:// Introduced by the system stream wrapper module and preferred for
|
||||
module provided resources.
|
||||
* theme:// idem.
|
||||
* profile:// idem.
|
||||
* library:// idem.
|
||||
- A relative path (relative to the current directory, probably Drupal root).
|
||||
- An absolute path.
|
||||
- A system or toolkit font specification. E.g. on my Windows system 'arial.ttf'
|
||||
worked with both GD and Imagemagick. A warning will be issued but that may be
|
||||
ignored when it works as expected.
|
||||
|
||||
|
||||
Text position
|
||||
-------------
|
||||
The text position defines the point in the image where you want to place (align)
|
||||
your text. It starts at the top left corner of the image with position 0,0 and
|
||||
the positive directions are to the right and down.
|
||||
|
||||
The definition of the vertical position differs per toolkit. For GD it is the
|
||||
position of the font baseline, while for Imagemagick it is the bottom of the
|
||||
bounding box, i.e the descender or beard line in typography terminology.
|
||||
|
||||
|
||||
Text alignment
|
||||
--------------
|
||||
You can align your text with regard to the text position. Possible horizontal
|
||||
alignments are left (default), center and right. Vertical alignments are top,
|
||||
center and bottom (default).
|
||||
|
||||
Note: Given
|
||||
- the way that GD uses the vertical text position (as baseline),
|
||||
- and the way this module implements (vertical) alignment (translating the
|
||||
(vertical) position using the calculated bounding box),
|
||||
vertical alignment with the GD toolkit is a bit off. You will have to compensate
|
||||
for this yourself.
|
||||
|
||||
|
||||
Rotation
|
||||
--------
|
||||
The text can be rotated before being overlaid on the image. The value is in
|
||||
degrees. Positive values are rotated clockwise, So 90 degrees is straight down.
|
||||
negative values counter clockwise.
|
||||
|
||||
In Imagemagick the text is rotated around the text position. Thus centered text
|
||||
is rotated around its own center. GD, on the other hand, always rotates around
|
||||
the left bottom (baseline) position, regardless the text alignment. So using
|
||||
rotation with a non default alignment (left bottom) will give surprising
|
||||
results.
|
||||
|
||||
|
||||
Text source
|
||||
-----------
|
||||
The text to place on the image may come from different sources:
|
||||
- Text (with token replacement): the text to place on the image has to be
|
||||
entered on the image effect form. Use this e.g. for a copyright notice.
|
||||
notes:
|
||||
* Token replacement: you can use all global tokens, the file tokens, and
|
||||
tokens from entities referring to the image via an image field. Example: if
|
||||
you know that the image style is only used for article nodes, you can use
|
||||
[node:field-image:alt] to get the alt text of the image. Note: this specific
|
||||
example requires the entity_token module.
|
||||
* New lines: you can add a new line by adding \n to your text. To get a
|
||||
literal \n, use \\n.
|
||||
- PHP: the text to place on the image comes from a piece of PHP code that should
|
||||
return the text to place on the image. Only users with the 'use PHP for
|
||||
settings' permission are allowed to use this source. This permission and the
|
||||
evaluation of the PHP code come from the PHP filter module which is part of
|
||||
Drupal core and thus needs to be enabled, also during image generation.
|
||||
To add new lines to your text add them literally to the string you return,
|
||||
normally by using "\n" in your PHP code.
|
||||
- Image Alt or Title: to alleviate the need to enable the PHP filter module, 2
|
||||
commonly used sources for dynamic texts are directly available without any
|
||||
coding: the alt and title properties of an image field linked to the image at
|
||||
hand.
|
||||
|
||||
Notes:
|
||||
- When using token replacement or the image alt or title, multiple image fields,
|
||||
possibly in different languages, may be referring to the image that is being
|
||||
processed. This module will take the first image field it finds to extract the
|
||||
alt and title. If the field in itself is multi-lingual, thus not a synced
|
||||
field, the current language will be taken, which is the language of the user
|
||||
that happens to request this image derivative first.
|
||||
- This module will not automatically break text based on available space.
|
||||
- Due to the way that GD text box positioning works it is quite difficult to
|
||||
correctly position multiple lines of text with GD. If you have a working
|
||||
solution please post a patch. (Probably involves exploding the text in
|
||||
separate lines and then positioning each line separately.)
|
||||
|
||||
|
||||
PHP snippets to determine the text
|
||||
----------------------------------
|
||||
Given the correct permission, you can write your own PHP snippet to compute the
|
||||
text to display. To ease this task, this module makes some information regarding
|
||||
the image being processed available in 2 variables: $image and $image_context.
|
||||
These variables are readily available in your snippet.
|
||||
|
||||
$image is an object containing the following properties:
|
||||
- source: string, the source of the image, e.g. public://photo.jpg
|
||||
- info: array, example data:
|
||||
- width (int) 180
|
||||
- height (int) 180
|
||||
- extension (string) png
|
||||
- mime_type (string) image/png
|
||||
- file_size (int) 4417
|
||||
- toolkit: string, imagemagick or GD
|
||||
|
||||
$image_context is an associative array containing:
|
||||
- effect_data: array, the data of this image effect, example data for the text
|
||||
effect:
|
||||
- size (string) 12
|
||||
- xpos (string) center
|
||||
- ypos (string) center
|
||||
- halign (string) left
|
||||
- valign (string) bottom
|
||||
- RGB Array [1]
|
||||
- HEX (string) 000000
|
||||
- alpha (string) 100
|
||||
- angle (string) 0
|
||||
- fontfile (string:46) module://image_effects_text/Komika_display.ttf
|
||||
- text_source (string) text
|
||||
- text (string) Hello World!
|
||||
- php (string) return 'Hello World!'
|
||||
- managed_file: object|null. A managed file object containing these properties:
|
||||
- fid (string) 2
|
||||
- uid (string) 1
|
||||
- filename (string) photo.jpg
|
||||
- uri (string) public://photo.jpg
|
||||
- filemime (string) image/jpeg
|
||||
- filesize (string) 445751
|
||||
- status (string) 1
|
||||
- timestamp (string) 1327525851
|
||||
- metatags Array [0]
|
||||
- rdf_mapping Array [0]
|
||||
- referring_entities: array|null. A nested array with (fully loaded) entities
|
||||
referring to the current image. The 1st level of entries is keyed by the field
|
||||
name, the 2nd by entity type, and the 3rd by entity id. Example data:
|
||||
- field_photo Array [1]
|
||||
- node Array [1]
|
||||
- 12 Object of: stdClass
|
||||
- nid (string) 12
|
||||
- vid (string) 12
|
||||
- type (string) page
|
||||
- author ...
|
||||
- timestamp ...
|
||||
- ...
|
||||
- entity: object|null, the 1st entity in referring_entities. This is for easy
|
||||
access to the referring entity if it may be assumed that only 1 entity is
|
||||
referring to the current image.
|
||||
- image_field: array|null, the 1st image field in entity that is referring to
|
||||
the current image. This is for easy access to the image field data if it may
|
||||
be assumed that only 1 image field is referring to the current image. Example
|
||||
data:
|
||||
- fid (int) 2
|
||||
- alt (string) ...
|
||||
- title (string) ...
|
||||
- ...
|
||||
|
||||
Of course there are many other possible useful globals. Think of:
|
||||
- base_url
|
||||
- base_path
|
||||
- base_root
|
||||
- is_https
|
||||
- user
|
||||
- language
|
||||
and of course $_SERVER and $_GET.
|
||||
|
||||
Using these information you can access entity data as follows:
|
||||
|
||||
Specific case (1 entity, of known entity_type, referring to the image):
|
||||
<?php
|
||||
if (!$image_context['entity']) {
|
||||
return 'No referring entity';
|
||||
}
|
||||
$entity_type = 'node';
|
||||
$field_name = 'my_field';
|
||||
$entity = $image_context['entity'];
|
||||
$field = field_get_items($entity_type, $entity, $field_name);
|
||||
if ($field) {
|
||||
return isset($field[0]['value']) ? $field[0]['value'] : 'No field value';
|
||||
}
|
||||
?>
|
||||
|
||||
Or the more general case (not knowing the referring type, or multiple entities
|
||||
that may be referring to the image):
|
||||
<?php
|
||||
if (!$image_context['referring_entities']) {
|
||||
return 'No referring entities';
|
||||
}
|
||||
$referring_entities = $image_context['referring_entities'];
|
||||
foreach ($referring_entities as $field_name => $field_referring_entities) {
|
||||
foreach ($field_referring_entities as $entity_type => $entities) {
|
||||
foreach ($entities as $entity_id => $entity) {
|
||||
$field = field_get_items($entity_type, $entity, $field_name);
|
||||
// ...
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
TODO
|
||||
----
|
||||
- Vertical alignment: add baseline as vertical alignment and make both toolkits
|
||||
behave the same for any given vertical alignment.
|
||||
- Rotation and alignment. Imagemagick seems to be more correct. Can GD made to
|
||||
do the same?
|
||||
- Language and alt/title: what if the first user to pass by and that generates
|
||||
the image is in a language that has no alt/title?
|
||||
- Check for existence of imagettftext() and fail properly.
|
||||
|
||||
To quote http://www.imagemagick.org/Usage/text/#draw:
|
||||
As of IM version 6.2.4, the "-draw text" operation no longer understands the use
|
||||
of '\n' as meaning newline, or the use of percent '%' image information escapes.
|
||||
(See Drawing a Percent Bug). These abilities, and problems, however remain
|
||||
available in the new IM v6 operator "-annotate". See the Annotate Text Drawing
|
||||
Operator below.
|
||||
@@ -0,0 +1,728 @@
|
||||
<?php
|
||||
/**
|
||||
* Implementation of image_effects_text.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Real implementation of hook_help() called by image_effects_text_help().
|
||||
*
|
||||
* Experimental diagnostic page to assist locating valid fonts on the system.
|
||||
* Only tuned for Ubuntu so far. I've been unable do find ubiquitous tools that
|
||||
* provide useful font listings.'
|
||||
*/
|
||||
function image_effects_text_help_inc(/*$path, $arg*/) {
|
||||
$output = "<p>
|
||||
For text rendering to work on a server, we <em>must</em>
|
||||
know the system path to the font <em>file</em>, not just the name.
|
||||
Font library handling differs too much on different systems and
|
||||
the available PHP toolkits are unable to return good diagnostics.
|
||||
</p><p>
|
||||
On Debian/Ubuntu, you may find your fonts in and under
|
||||
<code>/usr/share/fonts/truetype/</code>
|
||||
eg <code>'/usr/share/fonts/truetype/ttf-bitstream-vera/VeraMono.ttf'</code>
|
||||
</p><p>
|
||||
On OSX, they are probably in <code>/Library/Fonts/</code>
|
||||
eg <code>'/Library/Fonts/Times New Roman Bold Italic.ttf'</code>
|
||||
</p><p>
|
||||
On Windows, they are probably in <code>C:\\WINDOWS\Fonts\</code>
|
||||
eg <code>'C:\\WINDOWS\\Fonts\\comic.ttf'</code>
|
||||
</p><p>
|
||||
Of course, this will change if you deploy to a different server!
|
||||
so the best approach is to place your own TTF font file inside your private
|
||||
or public files directory and use that. Just give the filename with the
|
||||
'private://' or 'public://' scheme prefix and it should be found.
|
||||
</p>
|
||||
";
|
||||
$output .= t("<p>Files directory is !files</p>", array('!files' => variable_get('file_public_path', conf_path() . '/files')));
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Image effect form callback for the text effect.
|
||||
*
|
||||
* Note that this is not a complete form, it only contains the portion of the
|
||||
* form for configuring the effect options. Therefore it does not not need to
|
||||
* include metadata about the effect, nor a submit button.
|
||||
*
|
||||
* @param array $data
|
||||
* The current configuration for this image effect.
|
||||
*
|
||||
* @return array
|
||||
* The form definition for this effect.
|
||||
*/
|
||||
function image_effects_text_form_inc(array $data) {
|
||||
// Use of functions imagecache_file_...() creates a dependency on file utility.inc.
|
||||
module_load_include('inc', 'imagecache_actions', 'utility');
|
||||
// Use of function imagecache_rgb_form() creates a dependency on file utility-color.inc.
|
||||
module_load_include('inc', 'imagecache_actions', 'utility-color');
|
||||
|
||||
// Note: we also need to check for the existence of the module: admin has
|
||||
// all rights, so user_access(...) returns TRUE even if the module is not
|
||||
// enabled and the permission does not exist.
|
||||
// A user without the 'use PHP for settings' permission (defined by the core
|
||||
// PHP filter module) may not:
|
||||
// - Select the 'PHP code' text source option if it is currently not selected.
|
||||
// - Change the 'PHP code' textarea.
|
||||
$allow_php = module_exists('php') && user_access('use PHP for settings');
|
||||
$defaults = array(
|
||||
'size' => 50,
|
||||
'angle' => 0,
|
||||
'xpos' => '0',
|
||||
'ypos' => '0',
|
||||
'halign' => 'left',
|
||||
'valign' => 'top',
|
||||
'RGB' => array('HEX' => '#000000'),
|
||||
'alpha' => 100,
|
||||
'fontfile' => drupal_get_path('module', 'image_effects_text') . '/Komika_display.ttf',
|
||||
'text_source' => 'text',
|
||||
'text' => t('Hello World!'),
|
||||
'php' => 'if (!$image_context[\'entity\']) {
|
||||
return \'' . t('No referring entity') . '\';
|
||||
}
|
||||
$entity_type = \'node\';
|
||||
$field_name = \'my_field\';
|
||||
$entity = $image_context[\'entity\'];
|
||||
$field = field_get_items($entity_type, $entity, $field_name);
|
||||
if ($field) {
|
||||
return isset($field[0][\'value\']) ? $field[0][\'value\'] : \'' . t('No field value') . '\';
|
||||
}
|
||||
',
|
||||
);
|
||||
$data += $defaults;
|
||||
$tokens = token_info();
|
||||
$tokens = array_keys($tokens['types']);
|
||||
$form = array(
|
||||
'size' => array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Font size'),
|
||||
'#default_value' => $data['size'],
|
||||
'#description' => t('The font size in points. Only in GD1 this is in pixels.'),
|
||||
'#size' => 3,
|
||||
),
|
||||
'xpos' => array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('X offset'),
|
||||
'#default_value' => $data['xpos'],
|
||||
'#description' => t('Enter an offset in pixels or use a keyword: <em>left</em>, <em>center</em>, or <em>right</em>. Syntax like <em>right-20</em> is also valid.'),
|
||||
'#size' => 10,
|
||||
),
|
||||
'ypos' => array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Y offset'),
|
||||
'#default_value' => $data['ypos'],
|
||||
'#description' => t('Enter an offset in pixels or use a keyword: <em>top</em>, <em>center</em>, or <em>bottom</em>. Syntax like <em>bottom-20</em> is also valid.'),
|
||||
'#size' => 10,
|
||||
),
|
||||
'halign' => array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Horizontal alignment'),
|
||||
'#default_value' => $data['halign'],
|
||||
'#description' => t('The horizontal alignment of the text around the given %xpos.', array('%xpos' => t('X offset'))),
|
||||
'#options' => array(
|
||||
'left' => t('Left'),
|
||||
'center' => t('Center'),
|
||||
'right' => t('Right')
|
||||
),
|
||||
),
|
||||
'valign' => array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Vertical alignment'),
|
||||
'#default_value' => $data['valign'],
|
||||
'#description' => t('The vertical alignment of the text around the given %ypos.', array('%ypos' => t('Y offset'))),
|
||||
'#options' => array(
|
||||
'top' => t('Top'),
|
||||
'center' => t('Center'),
|
||||
'bottom' => t('Bottom')
|
||||
),
|
||||
),
|
||||
'RGB' => imagecache_rgb_form($data['RGB']),
|
||||
'alpha' => array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Opacity'),
|
||||
'#default_value' => $data['alpha'] ? $data['alpha'] : 100,
|
||||
'#size' => 3,
|
||||
'#description' => t('Opacity: 1-100.'),
|
||||
),
|
||||
'angle' => array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Angle'),
|
||||
'#default_value' => $data['angle'],
|
||||
'#description' => t('Angle: The angle in degrees, with 0 degrees being left-to-right reading text. Higher values represent a counter-clockwise rotation. For example, a value of 90 would result in bottom-to-top reading text.'),
|
||||
'#size' => 3,
|
||||
),
|
||||
'fontfile' => array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Font file name'),
|
||||
'#default_value' => $data['fontfile'],
|
||||
'#description' => imagecache_actions_file_field_description(),
|
||||
'#element_validate' => array('image_effects_text_validate_font'),
|
||||
'#size' => 80,
|
||||
),
|
||||
'text_help' => array(
|
||||
'#type' => 'item',
|
||||
'#title' => t('Text'),
|
||||
'#description' => t('<p>Select the source of the text:</p>
|
||||
<ul>
|
||||
<li><strong>Image alt</strong>: the alt text of an image field referring to this image is taken.</li>
|
||||
<li><strong>Image title</strong>: the title text of an image field referring to this image is taken.</li>
|
||||
<li><strong>Text (with token replacement)</strong>: A text with optional token replacement. Line breaks can be inserted with \n (\\\\n for a literal \n). You can define the text in the text field below the drop down.</li>
|
||||
<li><strong>PHP code</strong>: a piece of PHP code that returns the text to display. You can define the PHP code in the text area below the drop down. You will need the \'%use_php\' permission, defined by the \'PHP filter\' module.</li>
|
||||
</ul>
|
||||
<p>See the help in README.txt for an extensive explanation of the possibilities.</p>',
|
||||
array('%use_php' => t('Use PHP for settings'))),
|
||||
),
|
||||
'text_source' => array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Text source'),
|
||||
'#default_value' => $data['text_source'],
|
||||
'#options' => array(
|
||||
'alt' => t('Image alt'),
|
||||
'title' => t('Image title'),
|
||||
'text' => t('Text (with token replacement)'),
|
||||
'php' => t('PHP code'),
|
||||
),
|
||||
),
|
||||
'text' => array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Text'),
|
||||
'#default_value' => $data['text'],
|
||||
'#states' => array(
|
||||
'visible' => array(':input[name="data[text_source]"]' => array('value' => 'text')),
|
||||
),
|
||||
),
|
||||
'token_help' => array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Token replacement patterns'),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => TRUE,
|
||||
'tree' => array(
|
||||
'#theme' => 'token_tree',
|
||||
'#token_types' => $tokens,
|
||||
),
|
||||
'token_module_notice' => array(
|
||||
'#markup' => !module_exists('token') ? t('You might want to enable the token module to view token replacement patterns.') : '',
|
||||
),
|
||||
'entity_token_module_notice' => array(
|
||||
'#markup' => !module_exists('entity_token') ? t('You might want to enable the entity_token module to get token options for all entities and field properties.') : '',
|
||||
),
|
||||
'#states' => array(
|
||||
'visible' => array(':input[name="data[text_source]"]' => array('value' => 'text')),
|
||||
),
|
||||
),
|
||||
'php' => array(
|
||||
'#type' => 'textarea',
|
||||
'#rows' => 12,
|
||||
'#title' => t('PHP code'),
|
||||
'#default_value' => $data['php'],
|
||||
'#disabled' => !$allow_php,
|
||||
'#states' => array(
|
||||
'visible' => array(':input[name="data[text_source]"]' => array('value' => 'php')),
|
||||
),
|
||||
'#wysiwyg' => FALSE,
|
||||
),
|
||||
);
|
||||
if (!$allow_php && $data['text_source'] !== 'php') {
|
||||
unset($form['text_fieldset']['text_source']['#options']['php']);
|
||||
}
|
||||
|
||||
$form['#element_validate'][] = 'image_effects_text_form_validate';
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Element validation callback for the effect form.
|
||||
* @see http://api.drupal.org/api/drupal/developer--topics--forms_api_reference.html/7#element_validate
|
||||
*/
|
||||
function image_effects_text_form_validate(array $element/*, &$form_state, $form*/) {
|
||||
if (!is_numeric($element['size']['#value']) || $element['size']['#value'] <= 0) {
|
||||
form_error($element['size'], t('%field must be a positive number.', array('%field' => t('Font size'))));
|
||||
}
|
||||
if (!is_numeric($element['alpha']['#value']) || $element['alpha']['#value'] < 0 || $element['alpha']['#value'] > 100) {
|
||||
form_error($element['alpha'], t('%field must be a number between 1 and 100.', array('%field' => t('Opacity'))));
|
||||
}
|
||||
if (!is_numeric($element['angle']['#value'])) {
|
||||
form_error($element['angle'], t('%field must be a number.', array('%field' => t('Angle'))));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that the file as specified in the element exists and is readable.
|
||||
*
|
||||
* This is a Form API #element_validate callback.
|
||||
*
|
||||
* @param array $element
|
||||
*/
|
||||
function image_effects_text_validate_font(array &$element/*, &$form_status*/) {
|
||||
if (!imagecache_actions_find_file($element['#value'])) {
|
||||
drupal_set_message(t("Unable to find the font file '%file'. Please check the path. You can ignore this waning, if the font refers to a system or toolkit font, and the text shows correctly.", array('%file' => $element['#value'])), 'warning');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements theme_hook() for the text effect summary.
|
||||
*
|
||||
* @param array $variables
|
||||
* An associative array containing:
|
||||
* - data: The current configuration for this image effect.
|
||||
*
|
||||
* @return string
|
||||
* The HTML for the summary of this image effect.
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_image_effects_text_summary(array $variables) {
|
||||
$data = $variables['data'];
|
||||
switch ($data['text_source']) {
|
||||
case 'alt':
|
||||
$text = 'image alt';
|
||||
break;
|
||||
case 'title':
|
||||
$text = 'image title';
|
||||
break;
|
||||
case 'text':
|
||||
$text = $data['text'];
|
||||
break;
|
||||
case 'php':
|
||||
$text = 'PHP code';
|
||||
break;
|
||||
default:
|
||||
$text = '';
|
||||
break;
|
||||
}
|
||||
return 'Text: ' . $text . '; Position: ' . $data['xpos'] . ',' . $data['ypos'] . '; Alignment: ' . $data['halign'] . ',' . $data['valign'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Image effect callback for the text effect.
|
||||
*
|
||||
* @param stdClass $image
|
||||
* @param array $data
|
||||
*
|
||||
* @return boolean
|
||||
* true on success, false otherwise.
|
||||
*/
|
||||
function image_effects_text_effect_inc(stdClass $image, array $data) {
|
||||
// Use of imagecache_actions_hex2rgba() ,the imagecache_file_...() functions,
|
||||
// and imagecache_actions_get_image_context() create a dependency on
|
||||
// file utility.inc.
|
||||
module_load_include('inc', 'imagecache_actions', 'utility');
|
||||
|
||||
// Massage the data and pass it on to the toolkit dependent part.
|
||||
// Start with a straight copy.
|
||||
$params = $data;
|
||||
|
||||
// Get the text to overlay.
|
||||
$params['text'] = image_effects_text_get_text($image, $params);
|
||||
if (empty($params['text'])) {
|
||||
// No text to overlay. This is a situation that can be expected with token
|
||||
// replacement, or custom PHP code. Return immediately with success.
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Find out where the font file is located and if it is readable.
|
||||
$params['fontpath'] = imagecache_actions_find_file($data['fontfile']);
|
||||
if ($params['fontpath'] === FALSE) {
|
||||
// Pass the font on and let's hope that the toolkit knows where to find it.
|
||||
// We did warn on the effect form.
|
||||
$params['fontpath'] = $data['fontfile'];
|
||||
}
|
||||
|
||||
// Parse offsets.
|
||||
$params['xpos'] = image_effects_text_get_offset($data['xpos'], $image->info['width'], $image->info['height'], $image->info['width']);
|
||||
$params['ypos'] = image_effects_text_get_offset($data['ypos'], $image->info['width'], $image->info['height'], $image->info['height']);
|
||||
|
||||
// Convert color from hex (as it is stored in the UI).
|
||||
$params['RGB'] = $data['RGB'];
|
||||
if ($params['RGB']['HEX'] && $deduced = imagecache_actions_hex2rgba($params['RGB']['HEX'])) {
|
||||
$params['RGB'] += $deduced;
|
||||
}
|
||||
|
||||
// Make integers of various parameters.
|
||||
$params['size'] = (int) $params['size'];
|
||||
$params['xpos'] = (int) $params['xpos'];
|
||||
$params['ypos'] = (int) $params['ypos'];
|
||||
|
||||
// Hand over to toolkit.
|
||||
return image_toolkit_invoke('image_effects_text', $image, array($params));
|
||||
}
|
||||
|
||||
/**
|
||||
* GD toolkit specific implementation of the text effect.
|
||||
*
|
||||
* @param stdClass $image
|
||||
* @param array $data
|
||||
* The parameters for this effect.
|
||||
*
|
||||
* @return bool
|
||||
* true on success, false otherwise.
|
||||
*/
|
||||
function image_gd_image_effects_text(stdClass $image, array $data) {
|
||||
// Convert color and alpha to GD alpha and color value.
|
||||
// GD alpha value: 0 = opaque, 127 = transparent.
|
||||
$data['alpha'] = (int) ((1 - ($data['alpha'] / 100)) * 127);
|
||||
$color = imagecolorallocatealpha($image->resource, $data['RGB']['red'], $data['RGB']['green'], $data['RGB']['blue'], $data['alpha']);
|
||||
if ($color !== FALSE) {
|
||||
$bounds = NULL;
|
||||
// Adjust Y position for vertical alignment (if different from bottom).
|
||||
if ($data['valign'] !== 'bottom') {
|
||||
// Get bounding box.
|
||||
// PHP Manual: "This function requires both the GD library and the » FreeType library."
|
||||
// So it is not more demanding than imagettftext, which we need anyway.
|
||||
$bounds = imagettfbbox($data['size'], 0, $data['fontpath'], $data['text']);
|
||||
if (!$bounds) {
|
||||
drupal_set_message(t('Failed to calculate text dimensions using GD toolkit. Ignoring the alignment settings.'), 'warning');
|
||||
}
|
||||
else {
|
||||
// Get height of bounding box.
|
||||
$height = $bounds[1] - $bounds[7];
|
||||
// Shift ypos down (full height on bottom, half the height on center).
|
||||
$data['ypos'] += $data['valign'] === 'center' ? (int) ($height / 2) : $height;
|
||||
}
|
||||
}
|
||||
// Adjust X position for horizontal alignment (if different from left).
|
||||
if ($data['halign'] !== 'left') {
|
||||
// Get bounding box. PHP Manual: "This function requires both the GD
|
||||
// library and the » FreeType library.", so it is not more demanding than
|
||||
// imagettftext(), which we need anyway.
|
||||
if ($bounds === NULL) {
|
||||
$bounds = imagettfbbox($data['size'], 0, $data['fontpath'], $data['text']);
|
||||
if (!$bounds) {
|
||||
drupal_set_message(t('Failed to calculate text dimensions using GD toolkit. Ignoring the alignment.'), 'warning');
|
||||
}
|
||||
}
|
||||
if ($bounds !== FALSE) {
|
||||
// Get width of bounding box.
|
||||
$width = $bounds[2] - $bounds[0];
|
||||
// Shift xpos to the left (full width on right, half the width on center).
|
||||
$data['xpos'] -= $data['halign'] === 'center' ? (int) ($width / 2) : $width;
|
||||
}
|
||||
}
|
||||
|
||||
// PHP Manual: "This function requires both the GD library and the » FreeType library."
|
||||
$bounds = imagettftext($image->resource, $data['size'], $data['angle'], $data['xpos'], $data['ypos'], $color, $data['fontpath'], $data['text']);
|
||||
return $bounds !== FALSE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imagemagick toolkit specific implementation of the text effect.
|
||||
*
|
||||
* Text in Imagemagick:
|
||||
* - http://www.imagemagick.org/script/command-line-options.php?#draw
|
||||
* - http://www.imagemagick.org/script/command-line-options.php?#annotate
|
||||
*
|
||||
* UTF-8/non-ascii characters:
|
||||
* To prevent problems with non-ASCII characters, the online manual suggests to
|
||||
* put the text in a file and use the @{file} syntax. This does not work with
|
||||
* the text primitive of the -draw command, so we use -annotate.
|
||||
* We put the text in a temporary file which will be deleted by our hook_exit().
|
||||
* http://www.imagemagick.org/Usage/windows/#character_encoding
|
||||
*
|
||||
* Alignment in Imagemagick:
|
||||
* This is not directly supported, though a justification option has been
|
||||
* proposed: http://www.imagemagick.org/Usage/bugs/future/#justification.
|
||||
*
|
||||
* What we do have is the gravity option:
|
||||
* Gravity is used to position a text, but it also automatically applies a
|
||||
* justification based on that placement. So we use gravity here for alignment,
|
||||
* but will thus have to rebase our positioning.
|
||||
* - http://www.imagemagick.org/Usage/annotating/#gravity
|
||||
*
|
||||
* Gravity |halign|valign |hpos change|vpos change
|
||||
* ------------------------------------------------
|
||||
* NorthWest left top 0 0
|
||||
* North center top -width/2 0
|
||||
* NorthEast right top -width 0
|
||||
* West left center 0 -height/2
|
||||
* Center center center -width/2 -height/2
|
||||
* East right center -width -height/2
|
||||
* SouthWest left bottom 0 -height
|
||||
* South center bottom -width/2 -height
|
||||
* SouthEast right bottom -width -height
|
||||
*
|
||||
* @param stdClass $image
|
||||
* @param array $data
|
||||
* The parameters for this effect.
|
||||
*
|
||||
* @return bool
|
||||
* true on success, false otherwise.
|
||||
|
||||
*/
|
||||
function image_imagemagick_image_effects_text(stdClass $image, array $data) {
|
||||
static $alignments2gravity = array(
|
||||
'left' => array(
|
||||
'top' => array(
|
||||
'gravity' => 'NorthWest',
|
||||
'tx' => 0,
|
||||
'ty' => 0,
|
||||
),
|
||||
'center' => array(
|
||||
'gravity' => 'West',
|
||||
'tx' => 0,
|
||||
'ty' => -0.5,
|
||||
),
|
||||
'bottom' => array(
|
||||
'gravity' => 'SouthWest',
|
||||
'tx' => 0,
|
||||
'ty' => 1, // reversed translation
|
||||
),
|
||||
),
|
||||
'center' => array(
|
||||
'top' => array(
|
||||
'gravity' => 'North',
|
||||
'tx' => -0.5,
|
||||
'ty' => 0,
|
||||
),
|
||||
'center' => array(
|
||||
'gravity' => 'Center',
|
||||
'tx' => -0.5,
|
||||
'ty' => -0.5,
|
||||
),
|
||||
'bottom' => array(
|
||||
'gravity' => 'South',
|
||||
'tx' => -0.5,
|
||||
'ty' => 1, // reversed translation
|
||||
),
|
||||
),
|
||||
'right' => array(
|
||||
'top' => array(
|
||||
'gravity' => 'NorthEast',
|
||||
'tx' => 1, // reversed translation
|
||||
'ty' => 0,
|
||||
),
|
||||
'center' => array(
|
||||
'gravity' => 'East',
|
||||
'tx' => 1, // reversed translation
|
||||
'ty' => -0.5,
|
||||
),
|
||||
'bottom' => array(
|
||||
'gravity' => 'SouthEast',
|
||||
'tx' => 1, // reversed translation
|
||||
'ty' => 1, // reversed translation
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// Convert color and alpha to Imagemagick rgba color argument.
|
||||
$alpha = $data['alpha'] / 100;
|
||||
$color = 'rgba(' . $data['RGB']['red'] . ',' . $data['RGB']['green'] . ',' . $data['RGB']['blue'] . ',' . $alpha . ')';
|
||||
|
||||
// Set gravity for the alignment and calculate the translation to the
|
||||
// requested x and y offset as starting from the gravity point.
|
||||
$alignment_corrections = $alignments2gravity[$data['halign']][$data['valign']];
|
||||
$gravity = $alignment_corrections['gravity'];
|
||||
if ($alignment_corrections['tx'] > 0) {
|
||||
$data['xpos'] = (int) ($alignment_corrections['tx'] * $image->info['width'] - $data['xpos']);
|
||||
}
|
||||
else {
|
||||
$data['xpos'] += (int) ($alignment_corrections['tx'] * $image->info['width']);
|
||||
}
|
||||
if ($alignment_corrections['ty'] > 0) {
|
||||
$data['ypos'] = (int) ($alignment_corrections['ty'] * $image->info['height'] - $data['ypos']);
|
||||
}
|
||||
else {
|
||||
$data['ypos'] += (int) ($alignment_corrections['ty'] * $image->info['height']);
|
||||
}
|
||||
|
||||
// Add signs to translation, also when positive or 0.
|
||||
if ($data['xpos'] >= 0) {
|
||||
$data['xpos'] = '+' . $data['xpos'];
|
||||
}
|
||||
if ($data['ypos'] >= 0) {
|
||||
$data['ypos'] = '+' . $data['ypos'];
|
||||
}
|
||||
|
||||
// Angle must be positive.
|
||||
if ($data['angle'] < 0) {
|
||||
$data['angle'] = $data['angle'] % 360 + 360;
|
||||
}
|
||||
|
||||
// Set font file, size and color. fontpath is the real path, not a wrapper.
|
||||
$image->ops[] = '-font ' . escapeshellarg($data['fontpath']);
|
||||
$image->ops[] = "-pointsize {$data['size']}";
|
||||
$image->ops[] = '-fill ' . escapeshellarg($color);
|
||||
|
||||
// Add text to a temporary file,
|
||||
$tmp_file_name = drupal_tempnam('temporary://', 'image_effects_text');
|
||||
$tmp_file = fopen($tmp_file_name, 'w');
|
||||
if ($tmp_file) {
|
||||
fwrite($tmp_file, $data['text']);
|
||||
fclose($tmp_file);
|
||||
// and inform our hook_exit about it.
|
||||
image_effects_text_exit($tmp_file_name);
|
||||
$tmp_file_name = drupal_realpath($tmp_file_name);
|
||||
$text = "@$tmp_file_name";
|
||||
}
|
||||
else {
|
||||
// Fallback to pass the text via the command line, let's hope there are no
|
||||
// non-ASCII characters or that it works anyway (OS and locale dependent).
|
||||
$text = $data['text'];
|
||||
}
|
||||
|
||||
// Add gravity.
|
||||
$image->ops[] = "-gravity $gravity";
|
||||
// Add text angle, position and text (file) itself.
|
||||
$image->ops[] = "-annotate {$data['angle']}x{$data['angle']}{$data['xpos']}{$data['ypos']} " . escapeshellarg($text);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* UTILITY
|
||||
*/
|
||||
|
||||
/**
|
||||
* Convert a position into an offset in pixels.
|
||||
*
|
||||
* Position may be a number of additions and/or subtractions of:
|
||||
* - An value, positive or negative, in pixels.
|
||||
* - A, positive or negative, percentage (%). The given percentage of the
|
||||
* current dimension will be taken.
|
||||
* - 1 of the keywords:
|
||||
* * top: 0
|
||||
* * bottom: the height of the current image
|
||||
* * left: 0
|
||||
* * right: the width of the current image
|
||||
* * center: 50% (of the current dimension)
|
||||
* Examples:
|
||||
* 0, 20, -20, 90%, 33.3% + 10, right, center - 20, 300 - center, bottom - 50.
|
||||
* Note:
|
||||
* The algorithm will accept many more situations, though the result may be hard
|
||||
* to predict.
|
||||
*
|
||||
* @param string $position
|
||||
* The string defining the position.
|
||||
* @param int $width
|
||||
* The length of the horizontal dimension.
|
||||
* @param int $height
|
||||
* The length of the vertical dimension.
|
||||
* @param int $length
|
||||
* The length of the current dimension (should be either width or height).
|
||||
*
|
||||
* @return number
|
||||
* The computed offset in pixels.
|
||||
*/
|
||||
function image_effects_text_get_offset($position, $width, $height, $length) {
|
||||
$value = 0;
|
||||
|
||||
$tokens = preg_split('/ *(-|\+) */', $position, 0, PREG_SPLIT_DELIM_CAPTURE);
|
||||
$sign = 1;
|
||||
foreach ($tokens as $token) {
|
||||
switch ($token) {
|
||||
case '+';
|
||||
// Ignore, doesn't change the sign
|
||||
break;
|
||||
case '-';
|
||||
// Flip the sign.
|
||||
$sign = -$sign;
|
||||
break;
|
||||
case 'top':
|
||||
case 'left':
|
||||
// Actually, top and left are a no-op.
|
||||
$value += $sign * 0;
|
||||
$sign = 1;
|
||||
break;
|
||||
case 'bottom':
|
||||
// Use height of the image, even if this is for the horizontal position.
|
||||
$value += $sign * $height;
|
||||
$sign = 1;
|
||||
break;
|
||||
case 'right':
|
||||
// Use width of the image, even if this is for the vertical position.
|
||||
$value += $sign * $width;
|
||||
$sign = 1;
|
||||
break;
|
||||
case 'center':
|
||||
// half the current dimension as provided by $length.
|
||||
$value += $sign * $length / 2;
|
||||
$sign = 1;
|
||||
break;
|
||||
default:
|
||||
// Value: absolute or percentage
|
||||
if (substr($token, -strlen('%')) === '%') {
|
||||
$percentage = ((float) substr($token, 0, -strlen('%'))) / 100.0;
|
||||
$value += $sign * ($percentage * $length);
|
||||
}
|
||||
else {
|
||||
$value += $sign * (float) $token;
|
||||
}
|
||||
$sign = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text to use for this image.
|
||||
*
|
||||
* @param stdClass $image
|
||||
* The image the current effect is to be applied to.
|
||||
* @param array $data
|
||||
* An array containing the effect data.
|
||||
*
|
||||
* @return string
|
||||
* Plain text to be placed on the image.
|
||||
*/
|
||||
function image_effects_text_get_text(stdClass $image, array $data) {
|
||||
// Get context about the image.
|
||||
$image_context = imagecache_actions_get_image_context($image, $data);
|
||||
|
||||
if ($data['text_source'] === 'text') {
|
||||
// Replace \n with a newline character, except when preceded by a \.
|
||||
$text = preg_replace('/([^\\\\])\\\\n/', "$1\n", $data['text']);
|
||||
// Replace \\n by \n.
|
||||
$text = preg_replace('/\\\\\\\\n/', '\n', $text);
|
||||
|
||||
// Replace tokens.
|
||||
$token_data = array();
|
||||
foreach ($image_context['referring_entities'] as /*$field_name =>*/ $field_referring_entities) {
|
||||
foreach ($field_referring_entities as $entity_type => $entities) {
|
||||
// We can pass only 1 entity per given type to token_replace(), we take
|
||||
// the first.
|
||||
$token_data[$entity_type] = reset($entities);
|
||||
}
|
||||
}
|
||||
if ($image_context['managed_file']) {
|
||||
$token_data['file'] = $image_context['managed_file'];
|
||||
}
|
||||
// We should not sanitize the text as it will not be rendered in the browser
|
||||
// but is rendered on the image canvas on the server.
|
||||
$text = token_replace($text, $token_data, array('clear' => TRUE, 'sanitize' => FALSE));
|
||||
}
|
||||
else if ($data['text_source'] === 'alt' || $data['text_source'] === 'title') {
|
||||
$text = '';
|
||||
// We have 2 possible sources for the alt or title text:
|
||||
// - Image field.
|
||||
// - Media module (7.x-2.x) with file_entity: the alt and title come as
|
||||
// fields of the file entity, stored in 'managed_file'. The names of the
|
||||
// fields are field_file_image_alt_text resp. field_file_image_title_text.
|
||||
// BTW: these fields are also available in the 'image_field' entry, but as
|
||||
// a managed file may be existing without any image field referring to it,
|
||||
// we do the lookup in the managed_file entry.
|
||||
if (!empty($image_context['image_field'][$data['text_source']])) {
|
||||
$text = $image_context['image_field'][$data['text_source']];
|
||||
}
|
||||
else if (!empty($image_context['managed_file'])) {
|
||||
$field = field_get_items('file', $image_context['managed_file'], "field_file_image_{$data['text_source']}_text");
|
||||
if ($field) {
|
||||
$text = $field[0]['value'];
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // $data['text_source'] === 'php'
|
||||
// Process the php using php_eval (rather than eval), but with GLOBAL
|
||||
// variables, so they can be passed successfully.
|
||||
$GLOBALS['image_context'] = $image_context;
|
||||
$GLOBALS['image'] = $image;
|
||||
// We don't need to check_plain() the resulting text, as the text is not
|
||||
// rendered in a browser but processed on the server.
|
||||
$text = module_exists('php') ? php_eval('<' . '?php global $image, $image_context; ' . $data['php'] . ' ?' . '>') : '';
|
||||
|
||||
unset($GLOBALS['image']);
|
||||
unset($GLOBALS['image_context']);
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
name = Image Effects Text
|
||||
description = Provides an image effect to overlay text captions on images.
|
||||
package = Media
|
||||
core = 7.x
|
||||
|
||||
dependencies[] = image
|
||||
dependencies[] = imagecache_actions
|
||||
|
||||
; Information added by Drupal.org packaging script on 2016-02-19
|
||||
version = "7.x-1.7"
|
||||
core = "7.x"
|
||||
project = "imagecache_actions"
|
||||
datestamp = "1455872655"
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
/**
|
||||
* @file Provide text manipulation effects for image styles.
|
||||
*
|
||||
* Ported by dman
|
||||
* from https://drupal.org/node/264862#comment-865490 by patrickharris
|
||||
*
|
||||
* Ported to D7 by fietserwin
|
||||
* from imagecache_textactions 6.x-1.8.
|
||||
* - The module has been renamed to follow D7 terminology:
|
||||
* * imagecache -> image
|
||||
* * action(s) -> effect(s)
|
||||
* resulting in image_effects_text.
|
||||
* - The .module file is kept as small as possible. The real work is done in the
|
||||
* .inc file.
|
||||
* - Function and parameter naming has been changed to match the image effects
|
||||
* in the core image module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_image_effect_info().
|
||||
*
|
||||
* Defines information about the supported effects.
|
||||
*/
|
||||
function image_effects_text_image_effect_info() {
|
||||
$effects = array();
|
||||
|
||||
$effects['image_effects_text'] = array(
|
||||
'label' => t('Text'),
|
||||
'help' => t('Add static or dynamic (coded) text to an image.'),
|
||||
'dimensions passthrough' => TRUE,
|
||||
'effect callback' => 'image_effects_text_effect',
|
||||
'form callback' => 'image_effects_text_form',
|
||||
'summary theme' => 'image_effects_text_summary',
|
||||
);
|
||||
|
||||
return $effects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_help().
|
||||
*/
|
||||
function image_effects_text_help($path, $arg) {
|
||||
if ($path === 'admin/advanced_help' && count($arg) >= 3 && $arg[2] === 'image_effects_text'
|
||||
|| $path === 'admin/help/image_effects_text') {
|
||||
module_load_include('inc', 'image_effects_text', 'image_effects_text');
|
||||
return image_effects_text_help_inc($path, $arg);
|
||||
}
|
||||
else if ($path === 'admin/help#image_effects_text') {
|
||||
// This path just checks if there is (non-empty) help, so it can place a
|
||||
// link to it.
|
||||
return ' ';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_theme().
|
||||
*
|
||||
* Registers theme functions for the effect summaries.
|
||||
*/
|
||||
function image_effects_text_theme() {
|
||||
return array(
|
||||
'image_effects_text_summary' => array(
|
||||
'variables' => array('data' => NULL),
|
||||
'file' => 'image_effects_text.inc'
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_exit().
|
||||
*
|
||||
* For imagemagick we place the text in a temporary file as this prevents
|
||||
* problems with non-ASCII characters. This hook deletes files created during
|
||||
* execution of the text effect. As a style may contain multiple text effects,
|
||||
* there may be multiple files to delete.
|
||||
*
|
||||
* To keep track of temporary files created by this effect, the image effect
|
||||
* function itself also calls this hook, but passes the filename as a parameter.
|
||||
*
|
||||
* @param string|null $destination
|
||||
*/
|
||||
function image_effects_text_exit($destination = NULL) {
|
||||
static $tmp_file_names = array();
|
||||
|
||||
if (isset($destination)) {
|
||||
if (substr($destination, 0 , strlen('temporary://')) === 'temporary://') {
|
||||
// Called by the effect function. Add to our static list of files ot delete.
|
||||
$tmp_file_names[] = $destination;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Normal invocation as Drupal hook: delete any files we have collected.
|
||||
foreach ($tmp_file_names as $tmp_file_name) {
|
||||
unlink($tmp_file_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the form structure for the overlay text image effect.
|
||||
*/
|
||||
function image_effects_text_form($data) {
|
||||
module_load_include('inc', 'image_effects_text', 'image_effects_text');
|
||||
return image_effects_text_form_inc($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to perform the image effect on the given image.
|
||||
*/
|
||||
function image_effects_text_effect($image, $data) {
|
||||
module_load_include('inc', 'image_effects_text', 'image_effects_text');
|
||||
return image_effects_text_effect_inc($image, $data);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
README
|
||||
------
|
||||
README for the Image effect text test module.
|
||||
|
||||
This module contains several image styles to test text effects. It uses an image
|
||||
containing a grid and a font which are included in the install package as well.
|
||||
The image styles defined by this module start with 'text-test-'.
|
||||
|
||||
Hard Dependencies
|
||||
-----------------
|
||||
Hard dependencies:
|
||||
- Imagecache actions (canvas_actions and image_effects_text).
|
||||
- Image (Drupal core).
|
||||
- System stream wrapper (https://drupal.org/project/system_stream_wrapper)
|
||||
|
||||
Soft Dependencies
|
||||
-----------------
|
||||
- Imagemagick (preferred toolkit, https://drupal.org/project/imagemagick).
|
||||
- GD
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,16 @@
|
||||
name = Image Effects Text test
|
||||
description = Defines image styles that test the text effect.
|
||||
core = 7.x
|
||||
package = Media
|
||||
|
||||
dependencies[] = image
|
||||
dependencies[] = image_effects_text
|
||||
dependencies[] = imagecache_canvasactions
|
||||
dependencies[] = system_stream_wrapper
|
||||
|
||||
; Information added by Drupal.org packaging script on 2016-02-19
|
||||
version = "7.x-1.7"
|
||||
core = "7.x"
|
||||
project = "imagecache_actions"
|
||||
datestamp = "1455872655"
|
||||
|
||||
@@ -0,0 +1,609 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Code for the Image Effects Text test feature.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_image_default_styles().
|
||||
*/
|
||||
function image_effects_text_test_image_default_styles() {
|
||||
$styles = array();
|
||||
|
||||
// Exported image style: text-test-position-orientation.
|
||||
$styles['text-test-position-orientation'] = array(
|
||||
'name' => 'text-test-position-orientation',
|
||||
'effects' => array(
|
||||
115 => array(
|
||||
'label' => 'Overlay (watermark)',
|
||||
'help' => 'Choose the file image you wish to use as an overlay, and position it in a layer on top of the canvas.',
|
||||
'effect callback' => 'canvasactions_file2canvas_image',
|
||||
'dimensions passthrough' => TRUE,
|
||||
'form callback' => 'canvasactions_file2canvas_form',
|
||||
'summary theme' => 'canvasactions_file2canvas_summary',
|
||||
'module' => 'imagecache_canvasactions',
|
||||
'name' => 'canvasactions_file2canvas',
|
||||
'data' => array(
|
||||
'xpos' => 'left',
|
||||
'ypos' => 'top',
|
||||
'alpha' => '100',
|
||||
'path' => 'module://image_effects_text_test/grid800x600.png',
|
||||
),
|
||||
'weight' => '-10',
|
||||
),
|
||||
116 => array(
|
||||
'label' => 'Tekst',
|
||||
'help' => 'Add static or dynamic (coded) text to an image.',
|
||||
'dimensions passthrough' => TRUE,
|
||||
'form callback' => 'image_effects_text_form',
|
||||
'effect callback' => 'image_effects_text_effect',
|
||||
'summary theme' => 'image_effects_text_summary',
|
||||
'module' => 'image_effects_text',
|
||||
'name' => 'image_effects_text',
|
||||
'data' => array(
|
||||
'size' => '18',
|
||||
'xpos' => '100',
|
||||
'ypos' => '200',
|
||||
'halign' => 'left',
|
||||
'valign' => 'top',
|
||||
'RGB' => array(
|
||||
'HEX' => '000000',
|
||||
),
|
||||
'alpha' => '100',
|
||||
'angle' => '0',
|
||||
'fontfile' => 'module://image_effects_text/Komika_display.ttf',
|
||||
'text_source' => 'text',
|
||||
'text' => '100,200 left,top',
|
||||
'php' => 'return \'Hello World!\'',
|
||||
),
|
||||
'weight' => '-8',
|
||||
),
|
||||
117 => array(
|
||||
'label' => 'Tekst',
|
||||
'help' => 'Add static or dynamic (coded) text to an image.',
|
||||
'dimensions passthrough' => TRUE,
|
||||
'form callback' => 'image_effects_text_form',
|
||||
'effect callback' => 'image_effects_text_effect',
|
||||
'summary theme' => 'image_effects_text_summary',
|
||||
'module' => 'image_effects_text',
|
||||
'name' => 'image_effects_text',
|
||||
'data' => array(
|
||||
'size' => '18',
|
||||
'xpos' => 'left+300',
|
||||
'ypos' => 'top+200',
|
||||
'halign' => 'left',
|
||||
'valign' => 'center',
|
||||
'RGB' => array(
|
||||
'HEX' => '000000',
|
||||
),
|
||||
'alpha' => '100',
|
||||
'angle' => '0',
|
||||
'fontfile' => 'module://image_effects_text/Komika_display.ttf',
|
||||
'text_source' => 'text',
|
||||
'text' => 'left+300,top+200 left,center',
|
||||
'php' => 'return \'Hello World!\'',
|
||||
),
|
||||
'weight' => '3',
|
||||
),
|
||||
118 => array(
|
||||
'label' => 'Tekst',
|
||||
'help' => 'Add static or dynamic (coded) text to an image.',
|
||||
'dimensions passthrough' => TRUE,
|
||||
'form callback' => 'image_effects_text_form',
|
||||
'effect callback' => 'image_effects_text_effect',
|
||||
'summary theme' => 'image_effects_text_summary',
|
||||
'module' => 'image_effects_text',
|
||||
'name' => 'image_effects_text',
|
||||
'data' => array(
|
||||
'size' => '18',
|
||||
'xpos' => 'right-300',
|
||||
'ypos' => '200+top',
|
||||
'halign' => 'left',
|
||||
'valign' => 'bottom',
|
||||
'RGB' => array(
|
||||
'HEX' => '000000',
|
||||
),
|
||||
'alpha' => '100',
|
||||
'angle' => '0',
|
||||
'fontfile' => 'module://image_effects_text/Komika_display.ttf',
|
||||
'text_source' => 'text',
|
||||
'text' => 'right-300,200+top left,bottom',
|
||||
'php' => 'return \'Hello World!\'',
|
||||
),
|
||||
'weight' => '4',
|
||||
),
|
||||
119 => array(
|
||||
'label' => 'Tekst',
|
||||
'help' => 'Add static or dynamic (coded) text to an image.',
|
||||
'dimensions passthrough' => TRUE,
|
||||
'form callback' => 'image_effects_text_form',
|
||||
'effect callback' => 'image_effects_text_effect',
|
||||
'summary theme' => 'image_effects_text_summary',
|
||||
'module' => 'image_effects_text',
|
||||
'name' => 'image_effects_text',
|
||||
'data' => array(
|
||||
'size' => '18',
|
||||
'xpos' => 'center-300',
|
||||
'ypos' => '100+center',
|
||||
'halign' => 'center',
|
||||
'valign' => 'top',
|
||||
'RGB' => array(
|
||||
'HEX' => '000000',
|
||||
),
|
||||
'alpha' => '100',
|
||||
'angle' => '0',
|
||||
'fontfile' => 'module://image_effects_text/Komika_display.ttf',
|
||||
'text_source' => 'text',
|
||||
'text' => 'center-300,100+center center,top',
|
||||
'php' => 'return \'Hello World!\'',
|
||||
),
|
||||
'weight' => '5',
|
||||
),
|
||||
120 => array(
|
||||
'label' => 'Tekst',
|
||||
'help' => 'Add static or dynamic (coded) text to an image.',
|
||||
'dimensions passthrough' => TRUE,
|
||||
'form callback' => 'image_effects_text_form',
|
||||
'effect callback' => 'image_effects_text_effect',
|
||||
'summary theme' => 'image_effects_text_summary',
|
||||
'module' => 'image_effects_text',
|
||||
'name' => 'image_effects_text',
|
||||
'data' => array(
|
||||
'size' => '18',
|
||||
'xpos' => '-100+center',
|
||||
'ypos' => 'center+100',
|
||||
'halign' => 'center',
|
||||
'valign' => 'center',
|
||||
'RGB' => array(
|
||||
'HEX' => '000000',
|
||||
),
|
||||
'alpha' => '100',
|
||||
'angle' => '0',
|
||||
'fontfile' => 'module://image_effects_text/Komika_display.ttf',
|
||||
'text_source' => 'text',
|
||||
'text' => '-100+center,center+100 center,center',
|
||||
'php' => 'return \'Hello World!\'',
|
||||
),
|
||||
'weight' => '6',
|
||||
),
|
||||
121 => array(
|
||||
'label' => 'Tekst',
|
||||
'help' => 'Add static or dynamic (coded) text to an image.',
|
||||
'dimensions passthrough' => TRUE,
|
||||
'form callback' => 'image_effects_text_form',
|
||||
'effect callback' => 'image_effects_text_effect',
|
||||
'summary theme' => 'image_effects_text_summary',
|
||||
'module' => 'image_effects_text',
|
||||
'name' => 'image_effects_text',
|
||||
'data' => array(
|
||||
'size' => '18',
|
||||
'xpos' => '-200+right',
|
||||
'ypos' => 'bottom-200',
|
||||
'halign' => 'center',
|
||||
'valign' => 'bottom',
|
||||
'RGB' => array(
|
||||
'HEX' => '000000',
|
||||
),
|
||||
'alpha' => '100',
|
||||
'angle' => '0',
|
||||
'fontfile' => 'module://image_effects_text/Komika_display.ttf',
|
||||
'text_source' => 'text',
|
||||
'text' => '-200+right,bottom-200 center, bottom',
|
||||
'php' => 'return \'Hello World!\'',
|
||||
),
|
||||
'weight' => '7',
|
||||
),
|
||||
122 => array(
|
||||
'label' => 'Tekst',
|
||||
'help' => 'Add static or dynamic (coded) text to an image.',
|
||||
'dimensions passthrough' => TRUE,
|
||||
'form callback' => 'image_effects_text_form',
|
||||
'effect callback' => 'image_effects_text_effect',
|
||||
'summary theme' => 'image_effects_text_summary',
|
||||
'module' => 'image_effects_text',
|
||||
'name' => 'image_effects_text',
|
||||
'data' => array(
|
||||
'size' => '18',
|
||||
'xpos' => '300',
|
||||
'ypos' => '500',
|
||||
'halign' => 'right',
|
||||
'valign' => 'top',
|
||||
'RGB' => array(
|
||||
'HEX' => '000000',
|
||||
),
|
||||
'alpha' => '100',
|
||||
'angle' => '0',
|
||||
'fontfile' => 'module://image_effects_text/Komika_display.ttf',
|
||||
'text_source' => 'text',
|
||||
'text' => '300,500 right,top',
|
||||
'php' => 'return \'Hello World!\'',
|
||||
),
|
||||
'weight' => '8',
|
||||
),
|
||||
123 => array(
|
||||
'label' => 'Tekst',
|
||||
'help' => 'Add static or dynamic (coded) text to an image.',
|
||||
'dimensions passthrough' => TRUE,
|
||||
'form callback' => 'image_effects_text_form',
|
||||
'effect callback' => 'image_effects_text_effect',
|
||||
'summary theme' => 'image_effects_text_summary',
|
||||
'module' => 'image_effects_text',
|
||||
'name' => 'image_effects_text',
|
||||
'data' => array(
|
||||
'size' => '18',
|
||||
'xpos' => 'right-center+100',
|
||||
'ypos' => 'bottom-100',
|
||||
'halign' => 'right',
|
||||
'valign' => 'center',
|
||||
'RGB' => array(
|
||||
'HEX' => '000000',
|
||||
),
|
||||
'alpha' => '100',
|
||||
'angle' => '0',
|
||||
'fontfile' => 'module://image_effects_text/Komika_display.ttf',
|
||||
'text_source' => 'text',
|
||||
'text' => 'right-center+100,bottom-100 right,center',
|
||||
'php' => 'return \'Hello World!\'',
|
||||
),
|
||||
'weight' => '9',
|
||||
),
|
||||
124 => array(
|
||||
'label' => 'Tekst',
|
||||
'help' => 'Add static or dynamic (coded) text to an image.',
|
||||
'dimensions passthrough' => TRUE,
|
||||
'form callback' => 'image_effects_text_form',
|
||||
'effect callback' => 'image_effects_text_effect',
|
||||
'summary theme' => 'image_effects_text_summary',
|
||||
'module' => 'image_effects_text',
|
||||
'name' => 'image_effects_text',
|
||||
'data' => array(
|
||||
'size' => '18',
|
||||
'xpos' => 'right-100',
|
||||
'ypos' => 'bottom-100',
|
||||
'halign' => 'right',
|
||||
'valign' => 'bottom',
|
||||
'RGB' => array(
|
||||
'HEX' => '000000',
|
||||
),
|
||||
'alpha' => '100',
|
||||
'angle' => '0',
|
||||
'fontfile' => 'module://image_effects_text/Komika_display.ttf',
|
||||
'text_source' => 'text',
|
||||
'text' => 'right-100,bottom-100 right,bottom',
|
||||
'php' => 'return \'Hello World!\'',
|
||||
),
|
||||
'weight' => '10',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// Exported image style: text-test-rotate-wrt-alignment.
|
||||
$styles['text-test-rotate-wrt-alignment'] = array(
|
||||
'name' => 'text-test-rotate-wrt-alignment',
|
||||
'effects' => array(
|
||||
125 => array(
|
||||
'label' => 'Schalen',
|
||||
'help' => 'Door te schalen worden de originele verhoudingen behouden. Als één van de dimensies wordt ingevuld zal de andere worden berekend.',
|
||||
'effect callback' => 'image_scale_effect',
|
||||
'dimensions callback' => 'image_scale_dimensions',
|
||||
'form callback' => 'image_scale_form',
|
||||
'summary theme' => 'image_scale_summary',
|
||||
'module' => 'image',
|
||||
'name' => 'image_scale',
|
||||
'data' => array(
|
||||
'width' => '800',
|
||||
'height' => '',
|
||||
'upscale' => 0,
|
||||
),
|
||||
'weight' => '1',
|
||||
),
|
||||
126 => array(
|
||||
'label' => 'Overlay (watermark)',
|
||||
'help' => 'Choose the file image you wish to use as an overlay, and position it in a layer on top of the canvas.',
|
||||
'effect callback' => 'canvasactions_file2canvas_image',
|
||||
'dimensions passthrough' => TRUE,
|
||||
'form callback' => 'canvasactions_file2canvas_form',
|
||||
'summary theme' => 'canvasactions_file2canvas_summary',
|
||||
'module' => 'imagecache_canvasactions',
|
||||
'name' => 'canvasactions_file2canvas',
|
||||
'data' => array(
|
||||
'xpos' => 0,
|
||||
'ypos' => 0,
|
||||
'alpha' => '100',
|
||||
'path' => 'module://image_effects_text_test/grid800x600.png',
|
||||
),
|
||||
'weight' => '2',
|
||||
),
|
||||
127 => array(
|
||||
'label' => 'Tekst',
|
||||
'help' => 'Add static or dynamic (coded) text to an image.',
|
||||
'dimensions passthrough' => TRUE,
|
||||
'form callback' => 'image_effects_text_form',
|
||||
'effect callback' => 'image_effects_text_effect',
|
||||
'summary theme' => 'image_effects_text_summary',
|
||||
'module' => 'image_effects_text',
|
||||
'name' => 'image_effects_text',
|
||||
'data' => array(
|
||||
'size' => '18',
|
||||
'xpos' => '100',
|
||||
'ypos' => '200',
|
||||
'halign' => 'left',
|
||||
'valign' => 'bottom',
|
||||
'RGB' => array(
|
||||
'HEX' => '000000',
|
||||
),
|
||||
'alpha' => '100',
|
||||
'angle' => '45',
|
||||
'fontfile' => 'module://image_effects_text/Komika_display.ttf',
|
||||
'text_source' => 'text',
|
||||
'text' => '100,200 45 left,bottom',
|
||||
'php' => 'return \'Hello World!\'',
|
||||
),
|
||||
'weight' => '3',
|
||||
),
|
||||
128 => array(
|
||||
'label' => 'Tekst',
|
||||
'help' => 'Add static or dynamic (coded) text to an image.',
|
||||
'dimensions passthrough' => TRUE,
|
||||
'form callback' => 'image_effects_text_form',
|
||||
'effect callback' => 'image_effects_text_effect',
|
||||
'summary theme' => 'image_effects_text_summary',
|
||||
'module' => 'image_effects_text',
|
||||
'name' => 'image_effects_text',
|
||||
'data' => array(
|
||||
'size' => '18',
|
||||
'xpos' => '300',
|
||||
'ypos' => '200',
|
||||
'halign' => 'center',
|
||||
'valign' => 'center',
|
||||
'RGB' => array(
|
||||
'HEX' => '000000',
|
||||
),
|
||||
'alpha' => '100',
|
||||
'angle' => '66.67',
|
||||
'fontfile' => 'module://image_effects_text/Komika_display.ttf',
|
||||
'text_source' => 'text',
|
||||
'text' => '300,200 66.67 center,center',
|
||||
'php' => 'return \'Hello World!\'',
|
||||
),
|
||||
'weight' => '4',
|
||||
),
|
||||
129 => array(
|
||||
'label' => 'Tekst',
|
||||
'help' => 'Add static or dynamic (coded) text to an image.',
|
||||
'dimensions passthrough' => TRUE,
|
||||
'form callback' => 'image_effects_text_form',
|
||||
'effect callback' => 'image_effects_text_effect',
|
||||
'summary theme' => 'image_effects_text_summary',
|
||||
'module' => 'image_effects_text',
|
||||
'name' => 'image_effects_text',
|
||||
'data' => array(
|
||||
'size' => '18',
|
||||
'xpos' => '500',
|
||||
'ypos' => '200',
|
||||
'halign' => 'right',
|
||||
'valign' => 'top',
|
||||
'RGB' => array(
|
||||
'HEX' => '000000',
|
||||
),
|
||||
'alpha' => '100',
|
||||
'angle' => '90',
|
||||
'fontfile' => 'module://image_effects_text/Komika_display.ttf',
|
||||
'text_source' => 'text',
|
||||
'text' => '500,200 45 right,top',
|
||||
'php' => 'return \'Hello World!\'',
|
||||
),
|
||||
'weight' => '5',
|
||||
),
|
||||
130 => array(
|
||||
'label' => 'Tekst',
|
||||
'help' => 'Add static or dynamic (coded) text to an image.',
|
||||
'dimensions passthrough' => TRUE,
|
||||
'form callback' => 'image_effects_text_form',
|
||||
'effect callback' => 'image_effects_text_effect',
|
||||
'summary theme' => 'image_effects_text_summary',
|
||||
'module' => 'image_effects_text',
|
||||
'name' => 'image_effects_text',
|
||||
'data' => array(
|
||||
'size' => '18',
|
||||
'xpos' => '100',
|
||||
'ypos' => '500',
|
||||
'halign' => 'left',
|
||||
'valign' => 'bottom',
|
||||
'RGB' => array(
|
||||
'HEX' => '000000',
|
||||
),
|
||||
'alpha' => '100',
|
||||
'angle' => '-30',
|
||||
'fontfile' => 'module://image_effects_text/Komika_display.ttf',
|
||||
'text_source' => 'text',
|
||||
'text' => '100,500 -30 left,bottom',
|
||||
'php' => 'return \'Hello World!\'',
|
||||
),
|
||||
'weight' => '7',
|
||||
),
|
||||
131 => array(
|
||||
'label' => 'Tekst',
|
||||
'help' => 'Add static or dynamic (coded) text to an image.',
|
||||
'dimensions passthrough' => TRUE,
|
||||
'form callback' => 'image_effects_text_form',
|
||||
'effect callback' => 'image_effects_text_effect',
|
||||
'summary theme' => 'image_effects_text_summary',
|
||||
'module' => 'image_effects_text',
|
||||
'name' => 'image_effects_text',
|
||||
'data' => array(
|
||||
'size' => '18',
|
||||
'xpos' => '300',
|
||||
'ypos' => '500',
|
||||
'halign' => 'center',
|
||||
'valign' => 'center',
|
||||
'RGB' => array(
|
||||
'HEX' => '000000',
|
||||
),
|
||||
'alpha' => '100',
|
||||
'angle' => '-45',
|
||||
'fontfile' => 'module://image_effects_text/Komika_display.ttf',
|
||||
'text_source' => 'text',
|
||||
'text' => '300,500 -45 center,center',
|
||||
'php' => 'return \'Hello World!\'',
|
||||
),
|
||||
'weight' => '8',
|
||||
),
|
||||
132 => array(
|
||||
'label' => 'Tekst',
|
||||
'help' => 'Add static or dynamic (coded) text to an image.',
|
||||
'dimensions passthrough' => TRUE,
|
||||
'form callback' => 'image_effects_text_form',
|
||||
'effect callback' => 'image_effects_text_effect',
|
||||
'summary theme' => 'image_effects_text_summary',
|
||||
'module' => 'image_effects_text',
|
||||
'name' => 'image_effects_text',
|
||||
'data' => array(
|
||||
'size' => '18',
|
||||
'xpos' => '600',
|
||||
'ypos' => '400',
|
||||
'halign' => 'right',
|
||||
'valign' => 'top',
|
||||
'RGB' => array(
|
||||
'HEX' => '000000',
|
||||
),
|
||||
'alpha' => '100',
|
||||
'angle' => '-90',
|
||||
'fontfile' => 'module://image_effects_text/Komika_display.ttf',
|
||||
'text_source' => 'text',
|
||||
'text' => '600,400 -90 right,top',
|
||||
'php' => 'return \'Hello World!\'',
|
||||
),
|
||||
'weight' => '9',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// Exported image style: text-test-utf8-multi-line-color-transparency.
|
||||
$styles['text-test-utf8-multi-line-color-transparency'] = array(
|
||||
'name' => 'text-test-utf8-multi-line-color-transparency',
|
||||
'effects' => array(
|
||||
133 => array(
|
||||
'label' => 'Overlay (watermark)',
|
||||
'help' => 'Choose the file image you wish to use as an overlay, and position it in a layer on top of the canvas.',
|
||||
'effect callback' => 'canvasactions_file2canvas_image',
|
||||
'dimensions passthrough' => TRUE,
|
||||
'form callback' => 'canvasactions_file2canvas_form',
|
||||
'summary theme' => 'canvasactions_file2canvas_summary',
|
||||
'module' => 'imagecache_canvasactions',
|
||||
'name' => 'canvasactions_file2canvas',
|
||||
'data' => array(
|
||||
'xpos' => 'left',
|
||||
'ypos' => 'top',
|
||||
'alpha' => '100',
|
||||
'path' => 'module://image_effects_text_test/grid800x600.png',
|
||||
),
|
||||
'weight' => '-10',
|
||||
),
|
||||
114 => array(
|
||||
'label' => 'Tekst',
|
||||
'help' => 'Add static or dynamic (coded) text to an image.',
|
||||
'dimensions passthrough' => TRUE,
|
||||
'form callback' => 'image_effects_text_form',
|
||||
'effect callback' => 'image_effects_text_effect',
|
||||
'summary theme' => 'image_effects_text_summary',
|
||||
'module' => 'image_effects_text',
|
||||
'name' => 'image_effects_text',
|
||||
'data' => array(
|
||||
'size' => '20',
|
||||
'xpos' => '100',
|
||||
'ypos' => '100',
|
||||
'halign' => 'left',
|
||||
'valign' => 'top',
|
||||
'RGB' => array(
|
||||
'HEX' => 'FF0000',
|
||||
),
|
||||
'alpha' => '100',
|
||||
'angle' => '0',
|
||||
'fontfile' => 'sites/all/modules/imagecache_actions/image_effects_text/Komika_display.ttf',
|
||||
'text_source' => 'text',
|
||||
'text' => 'top+100,left+100: é è à ù ç Ö ÿ ‘ ’ “ ” ° ² ³ € x ÷',
|
||||
'php' => 'if (!$image_context[\'entity\']) {
|
||||
return \'No referring entity\';
|
||||
}
|
||||
$entity_type = \'node\';
|
||||
$field_name = \'my_field\';
|
||||
$entity = $image_context[\'entity\'];
|
||||
$field = field_get_items($entity_type, $entity, $field_name);
|
||||
if ($field) {
|
||||
return isset($field[0][\'value\']) ? $field[0][\'value\'] : \'No field value\';
|
||||
}
|
||||
',
|
||||
),
|
||||
'weight' => '-9',
|
||||
),
|
||||
135 => array(
|
||||
'label' => 'Tekst',
|
||||
'help' => 'Add static or dynamic (coded) text to an image.',
|
||||
'dimensions passthrough' => TRUE,
|
||||
'form callback' => 'image_effects_text_form',
|
||||
'effect callback' => 'image_effects_text_effect',
|
||||
'summary theme' => 'image_effects_text_summary',
|
||||
'module' => 'image_effects_text',
|
||||
'name' => 'image_effects_text',
|
||||
'data' => array(
|
||||
'size' => '50',
|
||||
'xpos' => '100',
|
||||
'ypos' => '200',
|
||||
'halign' => 'left',
|
||||
'valign' => 'top',
|
||||
'RGB' => array(
|
||||
'HEX' => '0000FF',
|
||||
),
|
||||
'alpha' => '90',
|
||||
'angle' => '0',
|
||||
'fontfile' => 'sites/all/modules/imagecache_actions/image_effects_text/Komika_display.ttf',
|
||||
'text_source' => 'text',
|
||||
'text' => 'Hello World!\\nOlá, mundo\\\\nHej världen',
|
||||
'php' => 'if (!$image_context[\'entity\']) {
|
||||
return \'No referring entity\';
|
||||
}
|
||||
$entity_type = \'node\';
|
||||
$field_name = \'my_field\';
|
||||
$entity = $image_context[\'entity\'];
|
||||
$field = field_get_items($entity_type, $entity, $field_name);
|
||||
if ($field) {
|
||||
return isset($field[0][\'value\']) ? $field[0][\'value\'] : \'No field value\';
|
||||
}
|
||||
',
|
||||
),
|
||||
'weight' => '-8',
|
||||
),
|
||||
134 => array(
|
||||
'label' => 'Tekst',
|
||||
'help' => 'Add static or dynamic (coded) text to an image.',
|
||||
'dimensions passthrough' => TRUE,
|
||||
'form callback' => 'image_effects_text_form',
|
||||
'effect callback' => 'image_effects_text_effect',
|
||||
'summary theme' => 'image_effects_text_summary',
|
||||
'module' => 'image_effects_text',
|
||||
'name' => 'image_effects_text',
|
||||
'data' => array(
|
||||
'size' => '50',
|
||||
'xpos' => '400',
|
||||
'ypos' => 'bottom-100',
|
||||
'halign' => 'center',
|
||||
'valign' => 'bottom',
|
||||
'RGB' => array(
|
||||
'HEX' => 'FFFFFF',
|
||||
),
|
||||
'alpha' => '50',
|
||||
'angle' => '0',
|
||||
'fontfile' => 'arial.ttf',
|
||||
'text_source' => 'php',
|
||||
'text' => 'Hello World!',
|
||||
'php' => 'return "Hello World!\\nOlá, mundo\\\\nHej världen";
|
||||
',
|
||||
),
|
||||
'weight' => '-7',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return $styles;
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file extension to imageapi, provide an overlay action for blending two
|
||||
* layers, preserving transparency.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Places one image over another.
|
||||
*
|
||||
* @param stdClass $image
|
||||
* A valid image object.
|
||||
* @param stdClass $layer
|
||||
* A valid image object to be placed over or under the $image image.
|
||||
* @param int $x
|
||||
* Position of the overlay.
|
||||
* @param int $y
|
||||
* Position of the overlay.
|
||||
* @param int $alpha
|
||||
* Transparency of the overlay from 0-100. 0 is totally transparent. 100
|
||||
* (default) is totally opaque.
|
||||
* @param boolean $reverse
|
||||
* Flag to indicate the 'overlay' actually goes under the image.
|
||||
*
|
||||
* @return boolean
|
||||
* true on success, false otherwise.
|
||||
*/
|
||||
function image_overlay(stdClass $image, stdClass $layer, $x, $y, $alpha = 100, $reverse = FALSE) {
|
||||
if ($reverse) {
|
||||
$x = imagecache_actions_keyword_filter($x, $layer->info['width'], $image->info['width']);
|
||||
$y = imagecache_actions_keyword_filter($y, $layer->info['height'], $image->info['height']);
|
||||
}
|
||||
else {
|
||||
$x = imagecache_actions_keyword_filter($x, $image->info['width'], $layer->info['width']);
|
||||
$y = imagecache_actions_keyword_filter($y, $image->info['height'], $layer->info['height']);
|
||||
}
|
||||
return image_toolkit_invoke('overlay', $image, array($layer, $x, $y, $alpha, $reverse));
|
||||
}
|
||||
|
||||
/**
|
||||
* GD toolkit specific implementation of the image overlay effect.
|
||||
*
|
||||
* NOTE that the PHP libraries are not great at merging images SO we include a
|
||||
* library that does it pixel-by-pixel which is INCREDIBLY inefficient. If this
|
||||
* can be improved, in a way that supports all transparency, please let us know!
|
||||
*
|
||||
* A watermark is layer onto image, return the image. An underlay is image onto
|
||||
* layer, return the layer. Almost identical, but seeing as we work with
|
||||
* resource handles, the handle needs to be swapped before returning.
|
||||
*
|
||||
* @param stdClass $image
|
||||
* An image object.
|
||||
* @param stdClass $layer
|
||||
* Image object to be placed over or under the $image image.
|
||||
* @param int $x
|
||||
* Position of the overlay.
|
||||
* @param int $y
|
||||
* Position of the overlay.
|
||||
* @param int $alpha
|
||||
* Transparency of the overlay from 0-100. 0 is totally transparent. 100
|
||||
* (default) is totally opaque.
|
||||
* @param boolean $reverse
|
||||
* Flag to indicate that the 'overlay' actually goes under the image.
|
||||
*
|
||||
* @return boolean
|
||||
* true on success, false otherwise.
|
||||
*/
|
||||
function image_gd_overlay(stdClass $image, stdClass $layer, $x, $y, $alpha = 100, $reverse = FALSE) {
|
||||
// If the given alpha is 100%, we can use imagecopy - which actually works,
|
||||
// is more efficient, and seems to retain the overlays partial transparency.
|
||||
// Still does not work great for indexed gifs though?
|
||||
if ($reverse) {
|
||||
$upper = &$image;
|
||||
$lower = &$layer;
|
||||
}
|
||||
else {
|
||||
$upper = &$layer;
|
||||
$lower = &$image;
|
||||
}
|
||||
if ($alpha == 100 && ($upper->info['mime_type'] != 'image/gif')) {
|
||||
imagealphablending($lower->resource, TRUE);
|
||||
imagesavealpha($lower->resource, TRUE);
|
||||
imagealphablending($upper->resource, TRUE);
|
||||
imagesavealpha($upper->resource, TRUE);
|
||||
imagecopy($lower->resource, $upper->resource, $x, $y, 0, 0, $upper->info['width'], $upper->info['height']);
|
||||
imagedestroy($upper->resource);
|
||||
$image->resource = $lower->resource;
|
||||
$image->info = $lower->info;
|
||||
}
|
||||
else {
|
||||
// imagecopy() cannot be used and we have to use the slow library.
|
||||
module_load_include('inc', 'imagecache_actions', 'watermark');
|
||||
$watermark = new watermark();
|
||||
$result_img = $watermark->create_watermark($lower->resource, $upper->resource, $x, $y, $alpha);
|
||||
// Watermark creates a new image resource, so clean up both old images.
|
||||
imagedestroy($lower->resource);
|
||||
imagedestroy($upper->resource);
|
||||
$image->resource = $result_img;
|
||||
$image->info = $lower->info;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imagemagick toolkit specific implementation of the image overlay effect.
|
||||
*
|
||||
* An underlay should can be created like:
|
||||
* -background None -extent 300x250-50-50 under.jpg -compose dst-over -composite
|
||||
*
|
||||
* Explanation:
|
||||
* - first enlarge the canvas, making any new part fully transparent.
|
||||
* - placing the "original" image on its requested position
|
||||
* - define the "source" image to IM
|
||||
* - compose the images placing the original over the source
|
||||
*
|
||||
* An overlay can be created like:
|
||||
* overlay.png -geometry 50x50+100+75 -compose src-over -composite
|
||||
*
|
||||
* Explanation:
|
||||
* - define the overlay image to IM
|
||||
* - and define its size and position on the current image
|
||||
* - compose the images placing the original over the source
|
||||
*
|
||||
* Please be aware of the limitations of imagemagick libraries out there - the
|
||||
* versions distributed on hosted servers (if any) are often several years
|
||||
* behind. Using the latest imagemagick release features will make this function
|
||||
* unusable in real deployments.
|
||||
*
|
||||
* @param stdClass $image
|
||||
* An image object.
|
||||
* @param stdClass $layer
|
||||
* Image object to be placed over or under the $image image.
|
||||
* @param int $x
|
||||
* Position of the overlay.
|
||||
* @param int $y
|
||||
* Position of the overlay.
|
||||
* @param int $alpha
|
||||
* Transparency of the overlay from 0-100. 0 is totally transparent. 100
|
||||
* (default) is totally opaque.
|
||||
* @param boolean $reverse
|
||||
* Flag to indicate that the 'overlay' actually goes under the image.
|
||||
*
|
||||
* @return boolean
|
||||
* true on success, false otherwise.
|
||||
*/
|
||||
function image_imagemagick_overlay(stdClass $image, stdClass $layer, $x = 0, $y = 0, $alpha = 100, $reverse = FALSE) {
|
||||
$realPath = imagecache_actions_find_file($layer->source);
|
||||
if (!$realPath) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Reset any gravity settings from earlier effects.
|
||||
$image->ops[] = '-gravity None';
|
||||
|
||||
// In imagemagick terms:
|
||||
// - $image is the destination (the image being constructed)
|
||||
// - $layer is the source (the source of the current operation)
|
||||
// Add the layer image to the imagemagick command line.
|
||||
|
||||
// Set the dimensions of the overlay. Use of the scale option means that we
|
||||
// need to change the dimensions: always set them, they don't harm when the
|
||||
// scale option is not used.
|
||||
$sign = $reverse ? -1 : 1;
|
||||
$geometry = sprintf('%ux%u%+d%+d', $layer->info['width'], $layer->info['height'], $sign * $x, $sign * $y);
|
||||
|
||||
$compose_operator = $reverse ? 'dst-over' : 'src-over';
|
||||
|
||||
// And compose it with the destination.
|
||||
if ($alpha == 100) {
|
||||
// Lay one image over the other. The transparency channel of the upper
|
||||
// image and/or its dimensions (being smaller than the lower image) will
|
||||
// determine what remains visible of the lower image).
|
||||
//
|
||||
// Note: In explicitly setting a -compose operator we reset/overwrite any
|
||||
// previously set one (former versions could produce erroneous results
|
||||
// in combination with other effects before this one).
|
||||
if ($reverse) {
|
||||
// Underlay.
|
||||
$image->ops[] = '-background';
|
||||
$image->ops[] = escapeshellarg('rgba(0,0,0,0)');
|
||||
$image->ops[] = "-extent $geometry";
|
||||
$image->ops[] = escapeshellarg($realPath);
|
||||
}
|
||||
else {
|
||||
$image->ops[] = escapeshellarg($realPath);
|
||||
$image->ops[] = "-geometry $geometry";
|
||||
}
|
||||
$image->ops[] = "-compose $compose_operator -composite";
|
||||
}
|
||||
else {
|
||||
// Alpha is not 100, so this image effect turns into a blend operation.
|
||||
// The alpha determines what percentage of the upper image pixel will be
|
||||
// taken. From the lower image pixel, 100 - alpha percent will be taken.
|
||||
//
|
||||
// Note 1: I'm not sure if and how transparency of one or both images is
|
||||
// used in or after the blend operation.
|
||||
// Note 2: As of IM v6.5.3-4 (around june 2009) we can use:
|
||||
// -compose blend -define compose:args=30[,70]
|
||||
$image->ops[] = escapeshellarg($realPath);
|
||||
$image->ops[] = "-geometry $geometry";
|
||||
$image->ops[] = "-compose blend -define compose:args=$alpha -composite";
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
README for the Image styleds admin Drupal module
|
||||
------------------------------------------------
|
||||
|
||||
Project page: https://drupal.org/project/imagecache_actions
|
||||
|
||||
Current and past maintainers for Image styles admin:
|
||||
- fietserwin (https://drupal.org/user/750928)
|
||||
|
||||
|
||||
Release notes for 7.x-1.x-dev
|
||||
-----------------------------
|
||||
- Clear the (menu) cache after installing or updating.
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
The Image style admin module extends the administrative interface for image
|
||||
styles by providing additional features.
|
||||
|
||||
Currently a duplicate, import and export image style feature are implemented.
|
||||
More features may be added in the future. These features typically allow you to
|
||||
more easily handle image styles. It allows us to more easily set up
|
||||
a test/showcase sute of styles. Finally, it allows everybody to test D8 image
|
||||
module features in real life.
|
||||
|
||||
This module is not a replacement for the features module
|
||||
(https://drupal.org/project/features). If you are serious about configuration
|
||||
management and want to distribute styles to other systems, use features.
|
||||
|
||||
Use this module for 1 time export/imports between different sites, "copy &
|
||||
paste" reuse within a site, and when reporting issues to the imagecache_actions
|
||||
issue queue.
|
||||
|
||||
|
||||
TODO
|
||||
----
|
||||
Solving errors in the core image handling?
|
||||
- [#1554074]: scale does not work with imagemagick when dimensions are unknown?
|
||||
@@ -0,0 +1,52 @@
|
||||
table#image-styles {
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
#image-styles th.style-name {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
#image-styles th.effects {
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
#image-styles th.settings {
|
||||
width: 15%;
|
||||
}
|
||||
|
||||
#image-styles td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
#image-styles .expand.inner {
|
||||
background: transparent url(/misc/menu-collapsed.png) left 0.6em no-repeat;
|
||||
margin-left: -12px;
|
||||
padding-left: 12px;
|
||||
}
|
||||
|
||||
#image-styles .expanded.expand.inner {
|
||||
background: transparent url(/misc/menu-expanded.png) left 0.6em no-repeat;
|
||||
}
|
||||
|
||||
#image-styles .description {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#image-styles .description .inner {
|
||||
overflow: hidden; /* truncates descriptions if too long */
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#image-styles .description .expanded.inner {
|
||||
overflow: visible;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
#image-styles .description .expanded .details {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#image-styles .description .expanded .separator {
|
||||
display: none;
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file Include file for image_styles_admin routines that do not need to be
|
||||
* loaded on each request.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Menu callback: Duplicates an image style and redirects to the image styles
|
||||
* overview page.
|
||||
*
|
||||
* @param array $style
|
||||
* An image style array.
|
||||
*
|
||||
* @see image_style_name_validate()
|
||||
*/
|
||||
function image_styles_admin_duplicate_page_callback($style) {
|
||||
$duplicate_style = image_styles_admin_duplicate($style);
|
||||
drupal_set_message(t('Style %name has been duplicated to %new_name.', array(
|
||||
'%name' => isset($style['label']) ? $style['label'] : $style['name'],
|
||||
'%new_name' => isset($duplicate_style['label']) ? $duplicate_style['label'] : $duplicate_style['name'])));
|
||||
drupal_goto('admin/config/media/image-styles');
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicates an image style and saves it.
|
||||
*
|
||||
* @param array $style
|
||||
* An image style array.
|
||||
* @param string|null $new_style_name
|
||||
* The preferred name for the new style. If left empty, the new name will be
|
||||
* based on the name of the style to duplicate. In both cases and when
|
||||
* necessary, the new name will be made unique by adding some suffix to it.
|
||||
* @param string|null $new_style_label
|
||||
* The preferred label for the new style. If left empty, the new label will be
|
||||
* based on the label of the style to duplicate. If that one is also empty,
|
||||
* no label will be defined for the new style, so Drupal (>=7.23) will create
|
||||
* one.
|
||||
*
|
||||
* @return array
|
||||
* An image style array with the newly created copy of the given style.
|
||||
*
|
||||
* @see image_style_name_validate()
|
||||
*/
|
||||
function image_styles_admin_duplicate($style, $new_style_name = NULL, $new_style_label = NULL) {
|
||||
// Find a unique name for the copy.
|
||||
// Step 1: Find the base: name without things like '-copy' or '-copy-1'
|
||||
$style_name_base = empty($new_style_name) ? $style['name'] : $new_style_name;
|
||||
if (preg_match('/-copy(-\d+)?$/', $style_name_base)) {
|
||||
$style_name_base = substr($style_name_base, 0, strpos($style_name_base, '-copy'));
|
||||
}
|
||||
|
||||
// Step 2: Add -copy to it (if the name comes from the current style).
|
||||
if (empty($new_style_name)) {
|
||||
$style_name_base .= '-copy';
|
||||
}
|
||||
|
||||
// Step 3: Ensure the new name will be unique.
|
||||
$i = 0;
|
||||
$style_name = $style_name_base;
|
||||
$styles = image_styles();
|
||||
while (isset($styles[$style_name])) {
|
||||
$i++;
|
||||
$style_name = $style_name_base . '-' . $i;
|
||||
}
|
||||
$style['name'] = $style_name;
|
||||
|
||||
// Step 4: Find a new label for the copy.
|
||||
if (isset($new_style_label) || isset($style['label'])) {
|
||||
$style_label = empty($new_style_label) ? $style['label'] : $new_style_label;
|
||||
$copy = t('copy');
|
||||
if (preg_match("/ $copy( \d+)?$/", $style_label)) {
|
||||
$style_label = substr($style_label, 0, strpos($style_label, " $copy"));
|
||||
}
|
||||
|
||||
// Step 4a: Add " copy" to it (if the name comes from the current style).
|
||||
if (empty($new_style_label)) {
|
||||
$style_label .= " $copy";
|
||||
}
|
||||
|
||||
// Step 4b: Make "unique" (based on the number added to the name)
|
||||
if ($i > 0) {
|
||||
$style['label'] .= " $i";
|
||||
}
|
||||
}
|
||||
|
||||
// Unset isid to save it as a new style.
|
||||
unset($style['isid']);
|
||||
$style = image_style_save($style);
|
||||
|
||||
// Save copies of each effect with the new image style ID (isid).
|
||||
foreach ($style['effects'] as &$effect) {
|
||||
// Unset ieid to save it as a new effect.
|
||||
unset($effect['ieid']);
|
||||
$effect['isid'] = $style['isid'];
|
||||
$effect = image_effect_save($effect);
|
||||
}
|
||||
|
||||
return $style;
|
||||
}
|
||||
|
||||
/**
|
||||
* drupal_get_form callback: form to export an image style.
|
||||
*
|
||||
* @param array $form
|
||||
* @param array $form_state
|
||||
* @param array $style
|
||||
* An image style array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function image_styles_admin_export_form($form, $form_state, $style) {
|
||||
drupal_set_title(format_string('%page_name @style_name',
|
||||
array('%page_name' => t('Export image style'), '@style_name' => isset($style['label']) ? $style['label'] : $style['name'])),
|
||||
PASS_THROUGH);
|
||||
$form['serialized_style'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#rows' => 5,
|
||||
'#title' => t('Image style export data'),
|
||||
'#default_value' => image_styles_admin_export_serialize($style),
|
||||
'#attributes' => array('readonly' =>'readonly'),
|
||||
'#description' => t('Copy the contents of this field to the clipboard and, on another site, paste it in the textarea of an %page_title page.',
|
||||
array('%page_title' => t('Import image style'))),
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* drupal_get_form callback: form to import an image style.
|
||||
*/
|
||||
function image_styles_admin_import_form($form/*, $form_state*/) {
|
||||
$form['serialized_style'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#rows' => 5,
|
||||
'#title' => t('Image style import data'),
|
||||
'#default_value' => '',
|
||||
'#required' => TRUE,
|
||||
'#description' => t('Paste the contents of the textarea of an %page_title page into this field.', array('%page_title' => t('Export image style'))),
|
||||
);
|
||||
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Import'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to validate the import style form.
|
||||
*/
|
||||
function image_styles_admin_import_form_validate($form, &$form_state) {
|
||||
$import = image_styles_admin_unify_newlines($form_state['values']['serialized_style']);
|
||||
if (image_styles_admin_import_extract_style($import) === FALSE) {
|
||||
form_set_error('serialized_style', t('The %field cannot be imported as an image style.', array('%field' => t('Image style import data'))));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to process form submission of the import style form.
|
||||
*/
|
||||
function image_styles_admin_import_form_submit($form, &$form_state) {
|
||||
$import = image_styles_admin_unify_newlines($form_state['values']['serialized_style']);
|
||||
$style = image_styles_admin_import_extract_style($import);
|
||||
// Import the style by "duplicating" it, but prevent adding the -copy suffix
|
||||
// by passing the requested name and label as 2nd and 3rd parameter.
|
||||
$new_style = image_styles_admin_duplicate($style, $style['name'], isset($style['label']) ? $style['label'] : NULL);
|
||||
if ($new_style['name'] === $style['name']) {
|
||||
drupal_set_message(t('Style %name has been imported.', array('%name' => $style['name'])));
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('Style %name has been imported as %new_name.', array(
|
||||
'%name' => isset($style['label']) ? $style['label'] : $style['name'],
|
||||
'%new_name' => isset($new_style['label']) ? $new_style['label'] : $new_style['name'])));
|
||||
}
|
||||
drupal_goto('admin/config/media/image-styles');
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes image style data so it can be exported.
|
||||
*
|
||||
* @param array $style
|
||||
* An image style array.
|
||||
*
|
||||
* @return string
|
||||
* The serialized image style. Keys that are not needed for import are not
|
||||
* serialized.
|
||||
*/
|
||||
function image_styles_admin_export_serialize($style) {
|
||||
$style = array_intersect_key($style, array('name' => 0, 'label' => 0, 'effects' => 0));
|
||||
foreach ($style['effects'] as &$effect) {
|
||||
$effect = array_intersect_key($effect, array('weight' => 0, 'name' => 0, 'data' => 0));
|
||||
}
|
||||
|
||||
array_walk_recursive($style, function(&$value) {
|
||||
if (is_string($value)) {
|
||||
$value = image_styles_admin_unify_newlines($value);
|
||||
}
|
||||
});
|
||||
return serialize($style);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unifies newlines in the string to the Unix newline standard.
|
||||
*
|
||||
* #2636314: textareas may convert newlines to the underlying OS style: convert
|
||||
* all new lines to Unix style before unserializing. As string length is in the
|
||||
* serialized data, we must ensure that we also do this on each array value
|
||||
* before serializing.
|
||||
*
|
||||
* @param string $str
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function image_styles_admin_unify_newlines($str) {
|
||||
$str = str_replace("\r\n", "\n", $str);
|
||||
$str = str_replace("\r", "\n", $str);
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unserializes and validates a string into image style data.
|
||||
*
|
||||
* @param string $import
|
||||
* The string representation of a @see serialize()'d image style array.
|
||||
*
|
||||
* @return array|false
|
||||
* An image style array or false if the string could not be unserialized into
|
||||
* image style data.
|
||||
*/
|
||||
function image_styles_admin_import_extract_style($import) {
|
||||
$style = unserialize($import);
|
||||
|
||||
// Check if the contents of the textarea could be unserialized into an array.
|
||||
if (!is_array($style)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Filter out keys that we do not process.
|
||||
$style = array_intersect_key($style, array('name' => 0, 'label' => 0, 'effects' => 0));
|
||||
|
||||
// 'name' is required and must be "machine name" string.
|
||||
if (!isset($style['name']) || !is_string($style['name']) || preg_match('/[0-9a-z_\-]+/', $style['name']) !== 1) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Optional 'label' must be a string.
|
||||
if (isset($style['label']) && !is_string($style['label'])) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// 'effects' is required and must be an array.
|
||||
if (!isset($style['effects']) || !is_array($style['effects'])) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Check effects elements
|
||||
foreach ($style['effects'] as &$effect) {
|
||||
// an effect must be an array.
|
||||
if (!is_array($effect)) {
|
||||
return FALSE;
|
||||
}
|
||||
// Check if the required keys are available, we will ignore the other.
|
||||
$effect = array_intersect_key($effect, array('weight' => 0, 'name' => 0, 'data' => 0));
|
||||
if (count($effect) !== 3) {
|
||||
return FALSE;
|
||||
}
|
||||
// effect weight must be an integer (data type in table is int, not float).
|
||||
if (!is_int($effect['weight']) && $effect['weight'] !== (string) (int) $effect['weight']) {
|
||||
return FALSE;
|
||||
}
|
||||
// effect name must be a string
|
||||
if (!is_string($effect['name'])) {
|
||||
return FALSE;
|
||||
}
|
||||
// Check whether the effect data is an array.
|
||||
if (!is_array($effect['data'])) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// @todo: are there any security implications for creating styles like this?
|
||||
// - Unserialize() is save in itself: it only creates data (except possibly
|
||||
// for__wakeup(), but that can only be in already existing code: safe
|
||||
// - Not expected array entries are removed (array_intersect_key): safe
|
||||
// - Basic types are checked: safe
|
||||
// - Effect data array is not checked. Possibly unsafe?! The effect data array
|
||||
// contains the effect parameters. Normally these are entered and validated
|
||||
// via a form and subsequently saved in the database (serialized as here).
|
||||
// The form validation is not executed on import and thus the data may
|
||||
// contain invalid values. This is acceptable as it can also be done by
|
||||
// operating directly on the database. In Drupal this is not normally
|
||||
// checked for during processing: error messages will make clear that the
|
||||
// data has been played with. Can incorrect data be abused? It may contain:
|
||||
// - incorrect types: we do not know the data structure of the various
|
||||
// effects, so we cannot check that and have to accept it as it comes.
|
||||
// Effects should check_plain in summary theme and convert to int/float
|
||||
// whenever possible before using it in commands.
|
||||
// - PHP code, but that may be valid content for the text or custom effects:
|
||||
// Effects should check_plain in summary theme and convert to int/float
|
||||
// whenever possible before using it in commands.
|
||||
// @todo: if the style contains an effect that contains PHP code, the user
|
||||
// should need the 'use PHP for settings' permission.
|
||||
// - HTML and or JS code: when used as parameter, this normally won't hurt.
|
||||
// When showing on the screen (summary theme), proper escaping should
|
||||
// suffice and is needed anyway: responsibility of effect.
|
||||
return $style;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
name = Image styles admin
|
||||
description = Provides additional administrative functionality to duplicate, export or import image styles.
|
||||
package = Media
|
||||
core = 7.x
|
||||
|
||||
dependencies[] = image
|
||||
|
||||
; Information added by Drupal.org packaging script on 2016-02-19
|
||||
version = "7.x-1.7"
|
||||
core = "7.x"
|
||||
project = "imagecache_actions"
|
||||
datestamp = "1455872655"
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
(function($) {
|
||||
"use strict";
|
||||
|
||||
Drupal.behaviors.imageStylesAdmin = {
|
||||
attach: function(context) {
|
||||
$('#image-styles').find('th.expand-all').once('expand-all', function() {
|
||||
$(this).click(function() {
|
||||
$('#image-styles').find('td.description .inner.expand').addClass('expanded');
|
||||
});
|
||||
});
|
||||
$('#image-styles').find('td.description').once('description', function() {
|
||||
$('.inner.expand', $(this)).click(function() {
|
||||
$(this).toggleClass('expanded');
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,156 @@
|
||||
<?php
|
||||
/**
|
||||
* @file Hook and callback implementations that must be available at all times.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*/
|
||||
function image_styles_admin_menu() {
|
||||
$items = array();
|
||||
$items['admin/config/media/image-styles/duplicate/%image_style'] = array(
|
||||
'title' => 'Duplicate style',
|
||||
'description' => 'Make a copy of an image style.',
|
||||
'page callback' => 'image_styles_admin_duplicate_page_callback',
|
||||
'page arguments' => array(5),
|
||||
'access arguments' => array('administer image styles'),
|
||||
'file' => 'image_styles_admin.inc',
|
||||
);
|
||||
$items['admin/config/media/image-styles/export/%image_style'] = array(
|
||||
'title' => 'Export style',
|
||||
'description' => 'Export an image style.',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('image_styles_admin_export_form', 5),
|
||||
'access arguments' => array('administer image styles'),
|
||||
'file' => 'image_styles_admin.inc',
|
||||
);
|
||||
$items['admin/config/media/image-styles/import'] = array(
|
||||
'title' => 'Import style',
|
||||
'description' => 'Import an image style.',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('image_styles_admin_import_form'),
|
||||
'access arguments' => array('administer image styles'),
|
||||
'type' => MENU_LOCAL_ACTION,
|
||||
'weight' => 3,
|
||||
'file' => 'image_styles_admin.inc',
|
||||
);
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_preprocess_HOOK for theme image_style_list.
|
||||
*/
|
||||
function image_styles_admin_preprocess_image_style_list(&$variables) {
|
||||
// Tell imagecache_actions_preprocess_table to preprocess the next call to
|
||||
// theme_table()
|
||||
$image_styles = array_values($variables['styles']);
|
||||
image_styles_admin_preprocess_table($image_styles);
|
||||
|
||||
// Add CSS and JS files.
|
||||
drupal_add_css(drupal_get_path('module', 'image_styles_admin') . '/image_styles_admin.css');
|
||||
if (base_path() !== '/') {
|
||||
$base_path = base_path();
|
||||
drupal_add_css("
|
||||
#image-styles .expand.inner { background-image: url($base_path/misc/menu-collapsed.png) }
|
||||
#image-styles .expanded.expand.inner { background-image: url($base_path/misc/menu-expanded.png) }",
|
||||
array('type' => 'inline'));
|
||||
}
|
||||
drupal_add_js(drupal_get_path('module', 'image_styles_admin') . '/image_styles_admin.js');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_preprocess_HOOK for theme table.
|
||||
*/
|
||||
function image_styles_admin_preprocess_table(&$variables) {
|
||||
static $image_styles = NULL;
|
||||
|
||||
// If called from image_styles_admin_preprocess_image_style_list(), the
|
||||
// parameter will be a sequential array.
|
||||
if (key($variables) === 0) {
|
||||
$image_styles = $variables;
|
||||
}
|
||||
else if (!empty($image_styles)) {
|
||||
// Normal preprocess hook call: we only process if theme('table', ...) has
|
||||
// been called via theme_image_style_list() and we have a non empty list of
|
||||
// styles;
|
||||
|
||||
// Set an ID on the table so it can be targeted by our CSS.
|
||||
$variables['attributes']['id'] = 'image-styles';
|
||||
|
||||
// Add a class to the Style name and Settings columns for styling.
|
||||
foreach ($variables['header'] as &$cell) {
|
||||
$temp_cell = is_string($cell) ? array('data' => $cell) : $cell;
|
||||
$class_names = array(
|
||||
'style-name' => t('Style name'),
|
||||
'settings' => t('Settings'),
|
||||
);
|
||||
foreach ($class_names as $class => $name) {
|
||||
if ($temp_cell['data'] == $name) {
|
||||
$temp_cell['class'][] = $class;
|
||||
$cell = $temp_cell;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the effects column header.
|
||||
array_splice($variables['header'], 1, 0, array(array(
|
||||
'data' => t('Effects') . ' <span class="description expand" role="button">(' . t('expand all') . ')</span>',
|
||||
'class' => array('effects expand-all')
|
||||
)));
|
||||
|
||||
// Add a column with a summary of all effects to each row.
|
||||
foreach ($variables['rows'] as $i => &$row) {
|
||||
$style = $image_styles[$i];
|
||||
$effects_list = array();
|
||||
foreach ($style['effects'] as $key => $effect) {
|
||||
$definition = image_effect_definition_load($effect['name']);
|
||||
$effect = array_merge($definition, $effect);
|
||||
$style['effects'][$key] = $effect;
|
||||
$effect_details = isset($effect['summary theme']) ? theme($effect['summary theme'], array('data' => $effect['data'])) : '';
|
||||
$effects_list[] = '<span class="details">' . $effect['label'] . ' ' . $effect_details . '</span>';
|
||||
}
|
||||
// Add the effects summary column to the row.
|
||||
$effects_summary = array(
|
||||
'data' => '<div class="inner expand" role="button">' . implode('<span class="separator">, </span>', $effects_list) . '</div>',
|
||||
'class' => 'description'
|
||||
);
|
||||
array_splice($row, 1, 0, array($effects_summary));
|
||||
}
|
||||
|
||||
// Find the column with the edit link in it.
|
||||
$i = 0;
|
||||
$first_row = reset($variables['rows']);
|
||||
foreach ($first_row as $i => &$cell) {
|
||||
$cell_data = is_array($cell) ? $cell['data'] : $cell;
|
||||
if (strpos($cell_data, '>' . t('edit') . '<') !== FALSE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Increase the colspan for the column with the edit link to include the
|
||||
// duplicate and export links as well. This *should* be 2, but Drupal core
|
||||
// specifies 1 more than should be there.
|
||||
$variables['header'][$i]['colspan'] += 1;
|
||||
|
||||
// Add the 2 links to each row by duplicating the edit link and then
|
||||
// changing the text and the link.
|
||||
$edit_column = $i;
|
||||
foreach ($variables['rows'] as &$row) {
|
||||
$i = $edit_column;
|
||||
// Duplicate the edit link twice.
|
||||
array_splice($row, $i + 1, 0, array($row[$i], $row[$i]));
|
||||
// Replace edit with duplicate in text and href
|
||||
$i++;
|
||||
$row[$i] = str_replace('>' . t('edit') . '<', '>' . t('duplicate') . '<', $row[$i]);
|
||||
$row[$i] = preg_replace('#/admin/config/media/image-styles/edit/#', '/admin/config/media/image-styles/duplicate/', $row[$i]);
|
||||
// Replace edit with export in text and href
|
||||
$i++;
|
||||
$row[$i] = str_replace('>' . t('edit') . '<', '>' . t('export') . '<', $row[$i]);
|
||||
$row[$i] = preg_replace('#/admin/config/media/image-styles/edit/#', '/admin/config/media/image-styles/export/', $row[$i]);
|
||||
}
|
||||
|
||||
// Don't preprocess subsequent calls to theme_table().
|
||||
$image_styles = NULL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
name = Imagecache Actions
|
||||
description = Provides utility code for a number of additional image effects that can be found in the sub modules.
|
||||
package = Media
|
||||
core = 7.x
|
||||
|
||||
dependencies[] = image
|
||||
|
||||
; Information added by Drupal.org packaging script on 2016-02-19
|
||||
version = "7.x-1.7"
|
||||
core = "7.x"
|
||||
project = "imagecache_actions"
|
||||
datestamp = "1455872655"
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
/**
|
||||
* Warn about the soft dependency on system stream wrapper module.
|
||||
*/
|
||||
function imagecache_actions_update_7001(&$sandbox) {
|
||||
drupal_set_message(t("Imagecache Actions: If you use the module:// notation anywhere in an image effect, you must now install the !module module.",
|
||||
array('!module' => l('System Stream Wrapper', 'https://drupal.org/project/system_stream_wrapper', array('external' => TRUE)))), 'warning');
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear image styles cache.
|
||||
*/
|
||||
function imagecache_actions_update_7002(&$sandbox) {
|
||||
// We need to clear this cache as many effect callbacks have been renamed.
|
||||
cache_clear_all('image_styles', 'cache');
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* UI enhancements for the imagecache edit form
|
||||
*/
|
||||
(function($){
|
||||
|
||||
/**
|
||||
* None here at the moment :-)
|
||||
* Conditional form logic was moved to drupal FAPI #states instead.
|
||||
*/
|
||||
|
||||
})(jQuery);
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file Home for the most basic imagecache_action routines.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_theme().
|
||||
*/
|
||||
function imagecache_actions_theme() {
|
||||
return array(
|
||||
'imagecacheactions_rgb' => array(
|
||||
'file' => 'utility-color.inc',
|
||||
'variables' => array('rgb' => NULL),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,292 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file Include this file whenever you have to use imageconvolution.
|
||||
*
|
||||
* You can use in your project, but keep the comment below:
|
||||
* Great for any image manipulation library
|
||||
* Made by Chao Xu(Mgccl) 3/1/07
|
||||
* www.webdevlogs.com
|
||||
* V 1.0
|
||||
*/
|
||||
if (!function_exists('imagefilter')) {
|
||||
/**
|
||||
* Applies a filter to an image.
|
||||
*
|
||||
* @link http://php.net/manual/en/function.imagefilter.php
|
||||
*
|
||||
* @param resource $image
|
||||
* @param int $filtertype
|
||||
* One of the IMG_FILTER_ constants
|
||||
* @param int $arg1
|
||||
* [optional] IMG_FILTER_BRIGHTNESS: Brightness level.
|
||||
* @param int $arg2
|
||||
* [optional] IMG_FILTER_COLORIZE: Value of green component.
|
||||
* @param int $arg3
|
||||
* [optional] IMG_FILTER_COLORIZE: Value of blue component.
|
||||
* param int $arg4
|
||||
* [optional] IMG_FILTER_COLORIZE: Alpha channel, A value between 0 and 127.
|
||||
* 0 indicates completely opaque while 127 indicates completely transparent.
|
||||
* This implementation does not use this parameter.
|
||||
*
|
||||
* @return bool
|
||||
* true on success or false on failure.
|
||||
*/
|
||||
function imagefilter($image, $filtertype, $arg1 = NULL, $arg2 = NULL, $arg3 = NULL) {
|
||||
// define('IMAGE_FILTER_NEGATE', 0);
|
||||
// define('IMAGE_FILTER_GRAYSCALE', 1);
|
||||
// define('IMAGE_FILTER_BRIGHTNESS', 2);
|
||||
// define('IMAGE_FILTER_CONTRAST', 3);
|
||||
// define('IMAGE_FILTER_COLORIZE', 4);
|
||||
// define('IMAGE_FILTER_EDGEDETECT', 5);
|
||||
// define('IMAGE_FILTER_EMBOSS', 6);
|
||||
// define('IMAGE_FILTER_GAUSSIAN_BLUR', 7);
|
||||
// define('IMAGE_FILTER_SELECTIVE_BLUR', 8);
|
||||
// define('IMAGE_FILTER_MEAN_REMOVAL', 9);
|
||||
// define('IMAGE_FILTER_SMOOTH', 10);
|
||||
// define('IMG_FILTER_PIXELATE', 11);
|
||||
$max_y = imagesy($image);
|
||||
$max_x = imagesx($image);
|
||||
switch ($filtertype) {
|
||||
case 0:
|
||||
$y = 0;
|
||||
while ($y < $max_y) {
|
||||
$x = 0;
|
||||
while ($x < $max_x) {
|
||||
$rgb = imagecolorat($image, $x, $y);
|
||||
$r = 255 - (($rgb >> 16) & 0xFF);
|
||||
$g = 255 - (($rgb >> 8) & 0xFF);
|
||||
$b = 255 - ($rgb & 0xFF);
|
||||
$a = $rgb >> 24;
|
||||
$new_pxl = imagecolorallocatealpha($image, $r, $g, $b, $a);
|
||||
if ($new_pxl == FALSE) {
|
||||
$new_pxl = imagecolorclosestalpha($image, $r, $g, $b, $a);
|
||||
}
|
||||
imagesetpixel($image, $x, $y, $new_pxl);
|
||||
++$x;
|
||||
}
|
||||
++$y;
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
case 1:
|
||||
$y = 0;
|
||||
while ($y < $max_y) {
|
||||
$x = 0;
|
||||
while ($x < $max_x) {
|
||||
$rgb = imagecolorat($image, $x, $y);
|
||||
$a = $rgb >> 24;
|
||||
$r = ((($rgb >> 16) & 0xFF) * 0.299) + ((($rgb >> 8) & 0xFF) * 0.587) + (($rgb & 0xFF) * 0.114);
|
||||
$new_pxl = imagecolorallocatealpha($image, $r, $r, $r, $a);
|
||||
if ($new_pxl == FALSE) {
|
||||
$new_pxl = imagecolorclosestalpha($image, $r, $r, $r, $a);
|
||||
}
|
||||
imagesetpixel($image, $x, $y, $new_pxl);
|
||||
++$x;
|
||||
}
|
||||
++$y;
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
case 2:
|
||||
$y = 0;
|
||||
while ($y < $max_y) {
|
||||
$x = 0;
|
||||
while ($x < $max_x) {
|
||||
$rgb = imagecolorat($image, $x, $y);
|
||||
$r = (($rgb >> 16) & 0xFF) + $arg1;
|
||||
$g = (($rgb >> 8) & 0xFF) + $arg1;
|
||||
$b = ($rgb & 0xFF) + $arg1;
|
||||
$a = $rgb >> 24;
|
||||
$r = ($r > 255) ? 255 : (($r < 0) ? 0 : $r);
|
||||
$g = ($g > 255) ? 255 : (($g < 0) ? 0 : $g);
|
||||
$b = ($b > 255) ? 255 : (($b < 0) ? 0 : $b);
|
||||
$new_pxl = imagecolorallocatealpha($image, $r, $g, $b, $a);
|
||||
if ($new_pxl == FALSE) {
|
||||
$new_pxl = imagecolorclosestalpha($image, $r, $g, $b, $a);
|
||||
}
|
||||
imagesetpixel($image, $x, $y, $new_pxl);
|
||||
++$x;
|
||||
}
|
||||
++$y;
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
case 3:
|
||||
$contrast = pow((100 - $arg1) / 100, 2);
|
||||
$y = 0;
|
||||
while ($y < $max_y) {
|
||||
$x = 0;
|
||||
while ($x < $max_x) {
|
||||
$rgb = imagecolorat($image, $x, $y);
|
||||
$a = $rgb >> 24;
|
||||
$r = (((((($rgb >> 16) & 0xFF) / 255) - 0.5) * $contrast) + 0.5) * 255;
|
||||
$g = (((((($rgb >> 8) & 0xFF) / 255) - 0.5) * $contrast) + 0.5) * 255;
|
||||
$b = ((((($rgb & 0xFF) / 255) - 0.5) * $contrast) + 0.5) * 255;
|
||||
$r = ($r > 255) ? 255 : (($r < 0) ? 0 : $r);
|
||||
$g = ($g > 255) ? 255 : (($g < 0) ? 0 : $g);
|
||||
$b = ($b > 255) ? 255 : (($b < 0) ? 0 : $b);
|
||||
$new_pxl = imagecolorallocatealpha($image, $r, $g, $b, $a);
|
||||
if ($new_pxl == FALSE) {
|
||||
$new_pxl = imagecolorclosestalpha($image, $r, $g, $b, $a);
|
||||
}
|
||||
imagesetpixel($image, $x, $y, $new_pxl);
|
||||
++$x;
|
||||
}
|
||||
++$y;
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
case 4:
|
||||
$x = 0;
|
||||
while ($x < $max_x) {
|
||||
$y = 0;
|
||||
while ($y < $max_y) {
|
||||
$rgb = imagecolorat($image, $x, $y);
|
||||
$r = (($rgb >> 16) & 0xFF) + $arg1;
|
||||
$g = (($rgb >> 8) & 0xFF) + $arg2;
|
||||
$b = ($rgb & 0xFF) + $arg3;
|
||||
$a = $rgb >> 24;
|
||||
$r = ($r > 255) ? 255 : (($r < 0) ? 0 : $r);
|
||||
$g = ($g > 255) ? 255 : (($g < 0) ? 0 : $g);
|
||||
$b = ($b > 255) ? 255 : (($b < 0) ? 0 : $b);
|
||||
$new_pxl = imagecolorallocatealpha($image, $r, $g, $b, $a);
|
||||
if ($new_pxl == FALSE) {
|
||||
$new_pxl = imagecolorclosestalpha($image, $r, $g, $b, $a);
|
||||
}
|
||||
imagesetpixel($image, $x, $y, $new_pxl);
|
||||
++$y;
|
||||
}
|
||||
++$x;
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
case 5:
|
||||
return imageconvolution($image, array(
|
||||
array(-1, 0, -1),
|
||||
array(0, 4, 0),
|
||||
array(-1, 0, -1),
|
||||
), 1, 127);
|
||||
|
||||
case 6:
|
||||
return imageconvolution($image, array(
|
||||
array(1.5, 0, 0),
|
||||
array(0, 0, 0),
|
||||
array(0, 0, -1.5),
|
||||
), 1, 127);
|
||||
|
||||
case 7:
|
||||
return imageconvolution($image, array(
|
||||
array(1, 2, 1),
|
||||
array(2, 4, 2),
|
||||
array(1, 2, 1),
|
||||
), 16, 0);
|
||||
|
||||
case 8:
|
||||
for ($y = 0; $y < $max_y; $y++) {
|
||||
for ($x = 0; $x < $max_x; $x++) {
|
||||
$flt_r_sum = $flt_g_sum = $flt_b_sum = 0;
|
||||
$cpxl = imagecolorat($image, $x, $y);
|
||||
for ($j = 0; $j < 3; $j++) {
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
if (($j == 1) && ($i == 1)) {
|
||||
$flt_r[1][1] = $flt_g[1][1] = $flt_b[1][1] = 0.5;
|
||||
}
|
||||
else {
|
||||
$pxl = imagecolorat($image, $x - (3 >> 1) + $i, $y - (3 >> 1) + $j);
|
||||
|
||||
$new_a = $pxl >> 24;
|
||||
// $r = (($pxl >> 16) & 0xFF);
|
||||
// $g = (($pxl >> 8) & 0xFF);
|
||||
// $b = ($pxl & 0xFF);
|
||||
$new_r = abs((($cpxl >> 16) & 0xFF) - (($pxl >> 16) & 0xFF));
|
||||
if ($new_r != 0) {
|
||||
$flt_r[$j][$i] = 1 / $new_r;
|
||||
}
|
||||
else {
|
||||
$flt_r[$j][$i] = 1;
|
||||
}
|
||||
|
||||
$new_g = abs((($cpxl >> 8) & 0xFF) - (($pxl >> 8) & 0xFF));
|
||||
if ($new_g != 0) {
|
||||
$flt_g[$j][$i] = 1 / $new_g;
|
||||
}
|
||||
else {
|
||||
$flt_g[$j][$i] = 1;
|
||||
}
|
||||
|
||||
$new_b = abs(($cpxl & 0xFF) - ($pxl & 0xFF));
|
||||
if ($new_b != 0) {
|
||||
$flt_b[$j][$i] = 1 / $new_b;
|
||||
}
|
||||
else {
|
||||
$flt_b[$j][$i] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
$flt_r_sum += $flt_r[$j][$i];
|
||||
$flt_g_sum += $flt_g[$j][$i];
|
||||
$flt_b_sum += $flt_b[$j][$i];
|
||||
}
|
||||
}
|
||||
|
||||
for ($j = 0; $j < 3; $j++) {
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
if ($flt_r_sum != 0) {
|
||||
$flt_r[$j][$i] /= $flt_r_sum;
|
||||
}
|
||||
if ($flt_g_sum != 0) {
|
||||
$flt_g[$j][$i] /= $flt_g_sum;
|
||||
}
|
||||
if ($flt_b_sum != 0) {
|
||||
$flt_b[$j][$i] /= $flt_b_sum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$new_r = $new_g = $new_b = 0;
|
||||
|
||||
for ($j = 0; $j < 3; $j++) {
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
$pxl = imagecolorat($image, $x - (3 >> 1) + $i, $y - (3 >> 1) + $j);
|
||||
$new_r += (($pxl >> 16) & 0xFF) * $flt_r[$j][$i];
|
||||
$new_g += (($pxl >> 8) & 0xFF) * $flt_g[$j][$i];
|
||||
$new_b += ($pxl & 0xFF) * $flt_b[$j][$i];
|
||||
}
|
||||
}
|
||||
|
||||
$new_r = ($new_r > 255) ? 255 : (($new_r < 0) ? 0 : $new_r);
|
||||
$new_g = ($new_g > 255) ? 255 : (($new_g < 0) ? 0 : $new_g);
|
||||
$new_b = ($new_b > 255) ? 255 : (($new_b < 0) ? 0 : $new_b);
|
||||
$new_pxl = imagecolorallocatealpha($image, (int) $new_r, (int) $new_g, (int) $new_b, $new_a);
|
||||
if ($new_pxl == FALSE) {
|
||||
$new_pxl = imagecolorclosestalpha($image, (int) $new_r, (int) $new_g, (int) $new_b, $new_a);
|
||||
}
|
||||
imagesetpixel($image, $x, $y, $new_pxl);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
case 9:
|
||||
return imageconvolution($image, array(
|
||||
array(-1, -1, -1),
|
||||
array(-1, 9, -1),
|
||||
array(-1, -1, -1),
|
||||
), 1, 0);
|
||||
|
||||
case 10:
|
||||
return imageconvolution($image, array(
|
||||
array(1, 1, 1),
|
||||
array(1, $arg1, 1),
|
||||
array(1, 1, 1),
|
||||
), $arg1 + 8, 0);
|
||||
|
||||
case 11:
|
||||
default:
|
||||
watchdog('imagecache_actions', 'Image filter failed: unknown filter type: %filtertype',
|
||||
array('%filtertype' => $filtertype),
|
||||
WATCHDOG_ERROR);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 23 KiB |
@@ -0,0 +1,9 @@
|
||||
This module provides an overview of all the imagecache presets in use on this
|
||||
site, as well as a number of samples used to test if everything is working as
|
||||
expected.
|
||||
|
||||
Sample images are provided to illustrate a number of the sample presets.
|
||||
Each image shown should match the one next to it.
|
||||
Where they don't match illustrates a current weakness in the system or the code
|
||||
coverage.
|
||||
|
||||