Compare commits
105 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
daf39105fb | ||
|
026e01b2cd | ||
|
0f0d954e61 | ||
|
58d83ba494 | ||
|
4f8fb82baf | ||
|
1bd8965535 | ||
|
081601ebbb | ||
|
401478c839 | ||
|
f0ab9479d6 | ||
|
9ff7a61ca9 | ||
|
3170beb832 | ||
|
8001f72a1a | ||
|
0f9e0220f1 | ||
|
e59ef91991 | ||
|
2337dbe94c | ||
|
c5de59a754 | ||
|
7ab19d39d6 | ||
|
9f6cba9292 | ||
|
21e53887b8 | ||
|
66c5a07767 | ||
|
bbfd895c4c | ||
|
b5de49d601 | ||
|
7677fc772f | ||
|
3d0b25abe0 | ||
|
1e5de9d225 | ||
|
43cb5b79b2 | ||
|
8e10e9ba5c | ||
|
1738680301 | ||
|
9b110037b4 | ||
|
9a912e7f01 | ||
|
689865a8b2 | ||
|
493ed45311 | ||
|
72c04632b8 | ||
|
b1d0cb1506 | ||
|
c637fa23ef | ||
|
6cccf5497d | ||
|
0dd562aa61 | ||
|
9a0a9429db | ||
|
6118f298ff | ||
|
547259cd11 | ||
|
fbaf05d0d4 | ||
|
3d2c74e9df | ||
|
74428f066c | ||
|
00ab2d7ca6 | ||
|
32a23894d1 | ||
|
d5546b669b | ||
|
53fb8da987 | ||
|
226f8adbeb | ||
|
cde8bab6e7 | ||
|
5edbfc9b54 | ||
|
9e9c44c935 | ||
|
9088647d3a | ||
|
8ad324b4f5 | ||
|
3b16b4b79d | ||
|
4e940164f9 | ||
|
1943d6606b | ||
|
5eebaa66ce | ||
|
c5cc0314c2 | ||
|
71816261f2 | ||
|
a62d7cb6c2 | ||
|
29d18c4b3c | ||
|
d697809a69 | ||
|
8667a9ec79 | ||
|
ccbd08949f | ||
|
6467fcc748 | ||
|
14d22a18e5 | ||
|
ca6118b355 | ||
|
6d3687d838 | ||
|
cf2fc3de4f | ||
|
ad8f6c12ee | ||
|
ad4930c3ae | ||
|
276f46fce2 | ||
|
0f3c1b4bde | ||
|
f250f7dff9 | ||
|
05c11ca9fc | ||
|
b069e322e9 | ||
|
6e0c775ede | ||
|
179469334a | ||
|
0b2723feee | ||
|
c009f423a2 | ||
|
79a7fd17d8 | ||
|
f2153e27a8 | ||
|
3271d165ff | ||
|
7e5937d7ec | ||
|
3c77a63fbc | ||
|
13da8b0573 | ||
|
1dc04e7c53 | ||
|
376a40e538 | ||
|
29743b75ec | ||
|
902c0aaef8 | ||
|
6c487c6f34 | ||
|
a1d811a318 | ||
|
a205d65ad5 | ||
|
52ce33d928 | ||
|
5a09c38f5d | ||
|
679714422d | ||
|
ec72246e9c | ||
|
389c3c48ee | ||
|
fcedac6e62 | ||
|
3daa8549ab | ||
|
6a93f843be | ||
|
f9b149eb5d | ||
|
e41e23c007 | ||
|
5673ce4f55 | ||
|
9bf94e9cf6 |
13
.gitignore
vendored
@@ -1,10 +1,17 @@
|
||||
# Cache files
|
||||
cache/*
|
||||
|
||||
# Test
|
||||
# Test & build
|
||||
build/
|
||||
coverage/
|
||||
coverage.clover
|
||||
|
||||
# Composer
|
||||
composer.lock
|
||||
vendor
|
||||
#vendor/
|
||||
|
||||
# Build and test
|
||||
build/
|
||||
/.bin
|
||||
|
||||
# Mac OS
|
||||
.DS_Store
|
||||
|
@@ -2,12 +2,12 @@
|
||||
<ruleset name="PHPCS rule set">
|
||||
<description>Custom rule set.</description>
|
||||
|
||||
<file>.</file>
|
||||
<file>src</file>
|
||||
<file>test</file>
|
||||
<file>autoload.php</file>
|
||||
|
||||
<exclude-pattern>docs/*</exclude-pattern>
|
||||
<exclude-pattern>coverage/*</exclude-pattern>
|
||||
<exclude-pattern>build/*</exclude-pattern>
|
||||
<exclude-pattern>test/config.php</exclude-pattern>
|
||||
<exclude-pattern>webroot/imgs.php</exclude-pattern>
|
||||
<exclude-pattern>webroot/imgp.php</exclude-pattern>
|
||||
<exclude-pattern>webroot/imgd.php</exclude-pattern>
|
26
.phpunit.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<phpunit
|
||||
bootstrap="test/config.php">
|
||||
|
||||
<testsuites>
|
||||
<testsuite name="all">
|
||||
<directory>test</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<filter>
|
||||
<whitelist processUncoveredFilesFromWhitelist="true">
|
||||
<directory suffix=".php">src/</directory>
|
||||
<exclude>
|
||||
<directory suffix=".php">test</directory>
|
||||
<directory suffix=".php">webroot</directory>
|
||||
</exclude>
|
||||
</whitelist>
|
||||
</filter>
|
||||
|
||||
<logging>
|
||||
<log type="coverage-html" target="build/coverage" charset="UTF-8" highlight="true" lowUpperBound="35" highLowerBound="70" />
|
||||
<log type="coverage-clover" target="build/coverage.clover" />
|
||||
</logging>
|
||||
|
||||
</phpunit>
|
@@ -10,37 +10,45 @@ filter:
|
||||
- webroot/imgs.php
|
||||
- webroot/test/
|
||||
|
||||
checks:
|
||||
php:
|
||||
code_rating: true
|
||||
duplication: true
|
||||
#checks:
|
||||
# php:
|
||||
# code_rating: true
|
||||
# duplication: true
|
||||
|
||||
tools:
|
||||
#tools:
|
||||
# Copy/Paste Detector
|
||||
php_cpd: true
|
||||
#php_cpd: true
|
||||
|
||||
# Metrics
|
||||
php_pdepend: true
|
||||
#php_pdepend: true
|
||||
|
||||
# Some Metrics + Bug Detection/Auto-Fixes
|
||||
php_analyzer: true
|
||||
#php_analyzer: true
|
||||
|
||||
php_code_sniffer:
|
||||
config:
|
||||
standard: "PSR2"
|
||||
#php_code_sniffer:
|
||||
# config:
|
||||
# standard: "PSR2"
|
||||
|
||||
php_sim:
|
||||
min_mass: 16 # Defaults to 16
|
||||
#php_sim:
|
||||
# min_mass: 16 # Defaults to 16
|
||||
|
||||
php_mess_detector:
|
||||
#php_mess_detector:
|
||||
#config:
|
||||
# ruleset: ../your-phpmd-ruleset/ruleset.xml
|
||||
|
||||
|
||||
|
||||
build:
|
||||
|
||||
dependencies:
|
||||
before:
|
||||
-
|
||||
command: 'mkdir build'
|
||||
|
||||
tests:
|
||||
override:
|
||||
-
|
||||
command: 'phpunit'
|
||||
command: 'phpunit --configuration .phpunit.xml'
|
||||
coverage:
|
||||
file: 'coverage.clover'
|
||||
file: 'build/coverage.clover'
|
||||
format: 'php-clover'
|
||||
|
45
.travis.yml
@@ -4,9 +4,10 @@ php:
|
||||
- 5.4
|
||||
- 5.5
|
||||
- 5.6
|
||||
- "7.0"
|
||||
- "7.1"
|
||||
- hhvm
|
||||
- nightly
|
||||
- "7.0"
|
||||
|
||||
|
||||
|
||||
@@ -35,49 +36,13 @@ matrix:
|
||||
|
||||
|
||||
before_script:
|
||||
|
||||
# Create a build directory for output
|
||||
# Store all files in your own bin
|
||||
#- install --directory build/bin
|
||||
#- export PATH=$PATH:$PWD/build/bin/
|
||||
|
||||
|
||||
# Install validation tools
|
||||
#- npm install -g htmlhint csslint jshint jscs jsonlint js-yaml html-minifier@0.8.0 clean-css uglify-js
|
||||
|
||||
# Install phpcs
|
||||
#- curl -OL https://squizlabs.github.io/PHP_CodeSniffer/phpcs.phar
|
||||
#- install --mode 0755 phpcs.phar $PWD/build/bin/phpcs
|
||||
|
||||
# Install phpmd
|
||||
#- wget -c http://static.phpmd.org/php/latest/phpmd.phar
|
||||
#- install --mode 0755 phpmd.phar $PWD/build/bin/phpmd
|
||||
- make install
|
||||
- make check
|
||||
|
||||
|
||||
|
||||
script:
|
||||
# Check versions of validation tools
|
||||
#- node --version
|
||||
#- npm --version
|
||||
|
||||
#- htmlhint --version
|
||||
#- csslint --version
|
||||
#- jscs --version
|
||||
#- jshint --version
|
||||
#- phpcs --version
|
||||
#- phpmd --version
|
||||
#- jsonlint --version
|
||||
#- js-yaml --version
|
||||
#- shellcheck --version
|
||||
|
||||
#- html-minifier --version
|
||||
#- cleancss --version
|
||||
#- uglifyjs --version
|
||||
|
||||
# Run validation & publish
|
||||
#- make phpunit
|
||||
- phpunit
|
||||
#- make phpcs
|
||||
- make test
|
||||
|
||||
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2012 - 2014 Mikael Roos, me@mikaelroos.se
|
||||
Copyright (c) 2012 - 2016 Mikael Roos, https://mikaelroos.se, mos@dbwebb.se
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
THE SOFTWARE.
|
||||
|
227
Makefile
Normal file
@@ -0,0 +1,227 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
# Detect OS
|
||||
OS = $(shell uname -s)
|
||||
|
||||
# Defaults
|
||||
ECHO = echo
|
||||
|
||||
# Make adjustments based on OS
|
||||
# http://stackoverflow.com/questions/3466166/how-to-check-if-running-in-cygwin-mac-or-linux/27776822#27776822
|
||||
ifneq (, $(findstring CYGWIN, $(OS)))
|
||||
ECHO = /bin/echo -e
|
||||
endif
|
||||
|
||||
# Colors and helptext
|
||||
NO_COLOR = \033[0m
|
||||
ACTION = \033[32;01m
|
||||
OK_COLOR = \033[32;01m
|
||||
ERROR_COLOR = \033[31;01m
|
||||
WARN_COLOR = \033[33;01m
|
||||
|
||||
# Which makefile am I in?
|
||||
WHERE-AM-I = $(CURDIR)/$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
|
||||
THIS_MAKEFILE := $(call WHERE-AM-I)
|
||||
|
||||
# Echo some nice helptext based on the target comment
|
||||
HELPTEXT = $(ECHO) "$(ACTION)--->" `egrep "^\# target: $(1) " $(THIS_MAKEFILE) | sed "s/\# target: $(1)[ ]*-[ ]* / /g"` "$(NO_COLOR)"
|
||||
|
||||
# Add local bin path for test tools
|
||||
#PATH := "./.bin:./vendor/bin:./node_modules/.bin:$(PATH)"
|
||||
#SHELL := env PATH=$(PATH) $(SHELL)
|
||||
PHPUNIT := .bin/phpunit
|
||||
PHPLOC := .bin/phploc
|
||||
PHPCS := .bin/phpcs
|
||||
PHPCBF := .bin/phpcbf
|
||||
PHPMD := .bin/phpmd
|
||||
PHPDOC := .bin/phpdoc
|
||||
BEHAT := .bin/behat
|
||||
|
||||
|
||||
|
||||
# target: help - Displays help.
|
||||
.PHONY: help
|
||||
help:
|
||||
@$(call HELPTEXT,$@)
|
||||
@$(ECHO) "Usage:"
|
||||
@$(ECHO) " make [target] ..."
|
||||
@$(ECHO) "target:"
|
||||
@egrep "^# target:" $(THIS_MAKEFILE) | sed 's/# target: / /g'
|
||||
|
||||
|
||||
|
||||
# target: prepare - Prepare for tests and build
|
||||
.PHONY: prepare
|
||||
prepare:
|
||||
@$(call HELPTEXT,$@)
|
||||
[ -d .bin ] || mkdir .bin
|
||||
[ -d build ] || mkdir build
|
||||
rm -rf build/*
|
||||
|
||||
|
||||
|
||||
# target: clean - Removes generated files and directories.
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@$(call HELPTEXT,$@)
|
||||
rm -rf build
|
||||
|
||||
|
||||
|
||||
# target: clean-all - Removes generated files and directories.
|
||||
.PHONY: clean-all
|
||||
clean-all:
|
||||
@$(call HELPTEXT,$@)
|
||||
rm -rf .bin build vendor composer.lock
|
||||
|
||||
|
||||
|
||||
# target: check - Check version of installed tools.
|
||||
.PHONY: check
|
||||
check: check-tools-php
|
||||
@$(call HELPTEXT,$@)
|
||||
|
||||
|
||||
|
||||
# target: test - Run all tests.
|
||||
.PHONY: test
|
||||
test: phpunit phpcs phpmd phploc behat
|
||||
@$(call HELPTEXT,$@)
|
||||
composer validate
|
||||
|
||||
|
||||
|
||||
# target: doc - Generate documentation.
|
||||
.PHONY: doc
|
||||
doc: phpdoc
|
||||
@$(call HELPTEXT,$@)
|
||||
|
||||
|
||||
|
||||
# target: build - Do all build
|
||||
.PHONY: build
|
||||
build: test doc #less-compile less-minify js-minify
|
||||
@$(call HELPTEXT,$@)
|
||||
|
||||
|
||||
|
||||
# target: install - Install all tools
|
||||
.PHONY: install
|
||||
install: prepare install-tools-php
|
||||
@$(call HELPTEXT,$@)
|
||||
|
||||
|
||||
|
||||
# target: update - Update the codebase and tools.
|
||||
.PHONY: update
|
||||
update:
|
||||
@$(call HELPTEXT,$@)
|
||||
git pull
|
||||
composer update
|
||||
|
||||
|
||||
|
||||
# target: tag-prepare - Prepare to tag new version.
|
||||
.PHONY: tag-prepare
|
||||
tag-prepare:
|
||||
@$(call HELPTEXT,$@)
|
||||
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
#
|
||||
# PHP
|
||||
#
|
||||
|
||||
# target: install-tools-php - Install PHP development tools.
|
||||
.PHONY: install-tools-php
|
||||
install-tools-php:
|
||||
@$(call HELPTEXT,$@)
|
||||
curl -Lso $(PHPDOC) https://www.phpdoc.org/phpDocumentor.phar && chmod 755 $(PHPDOC)
|
||||
|
||||
curl -Lso $(PHPCS) https://squizlabs.github.io/PHP_CodeSniffer/phpcs.phar && chmod 755 $(PHPCS)
|
||||
|
||||
curl -Lso $(PHPCBF) https://squizlabs.github.io/PHP_CodeSniffer/phpcbf.phar && chmod 755 $(PHPCBF)
|
||||
|
||||
curl -Lso $(PHPMD) http://static.phpmd.org/php/latest/phpmd.phar && chmod 755 $(PHPMD)
|
||||
|
||||
curl -Lso $(PHPUNIT) https://phar.phpunit.de/phpunit-5.7.9.phar && chmod 755 $(PHPUNIT)
|
||||
|
||||
curl -Lso $(PHPLOC) https://phar.phpunit.de/phploc.phar && chmod 755 $(PHPLOC)
|
||||
|
||||
curl -Lso $(BEHAT) https://github.com/Behat/Behat/releases/download/v3.3.0/behat.phar && chmod 755 $(BEHAT)
|
||||
|
||||
composer install
|
||||
|
||||
|
||||
|
||||
|
||||
# target: check-tools-php - Check versions of PHP tools.
|
||||
.PHONY: check-tools-php
|
||||
check-tools-php:
|
||||
@$(call HELPTEXT,$@)
|
||||
which $(PHPUNIT) && $(PHPUNIT) --version
|
||||
which $(PHPLOC) && $(PHPLOC) --version
|
||||
which $(PHPCS) && $(PHPCS) --version && echo
|
||||
which $(PHPMD) && $(PHPMD) --version && echo
|
||||
which $(PHPCBF) && $(PHPCBF) --version && echo
|
||||
which $(PHPDOC) && $(PHPDOC) --version && echo
|
||||
which $(BEHAT) && $(BEHAT) --version && echo
|
||||
|
||||
|
||||
|
||||
# target: phpunit - Run unit tests for PHP.
|
||||
.PHONY: phpunit
|
||||
phpunit: prepare
|
||||
@$(call HELPTEXT,$@)
|
||||
$(PHPUNIT) --configuration .phpunit.xml
|
||||
|
||||
|
||||
|
||||
# target: phpcs - Codestyle for PHP.
|
||||
.PHONY: phpcs
|
||||
phpcs: prepare
|
||||
@$(call HELPTEXT,$@)
|
||||
$(PHPCS) --standard=.phpcs.xml | tee build/phpcs
|
||||
|
||||
|
||||
|
||||
# target: phpcbf - Fix codestyle for PHP.
|
||||
.PHONY: phpcbf
|
||||
phpcbf:
|
||||
@$(call HELPTEXT,$@)
|
||||
$(PHPCBF) --standard=.phpcs.xml
|
||||
|
||||
|
||||
|
||||
# target: phpmd - Mess detector for PHP.
|
||||
.PHONY: phpmd
|
||||
phpmd: prepare
|
||||
@$(call HELPTEXT,$@)
|
||||
- $(PHPMD) . text .phpmd.xml | tee build/phpmd
|
||||
|
||||
|
||||
|
||||
# target: phploc - Code statistics for PHP.
|
||||
.PHONY: phploc
|
||||
phploc: prepare
|
||||
@$(call HELPTEXT,$@)
|
||||
$(PHPLOC) src > build/phploc
|
||||
|
||||
|
||||
|
||||
# target: phpdoc - Create documentation for PHP.
|
||||
.PHONY: phpdoc
|
||||
phpdoc:
|
||||
@$(call HELPTEXT,$@)
|
||||
$(PHPDOC) --config=.phpdoc.xml
|
||||
|
||||
|
||||
|
||||
# target: behat - Run behat for feature tests.
|
||||
.PHONY: behat
|
||||
behat:
|
||||
@$(call HELPTEXT,$@)
|
||||
$(BEHAT)
|
47
README.md
@@ -2,13 +2,19 @@ Image conversion on the fly using PHP
|
||||
=====================================
|
||||
|
||||
[](https://gitter.im/mosbth/cimage?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://travis-ci.org/mosbth/cimage)
|
||||
[](https://scrutinizer-ci.com/g/mosbth/cimage/build-status/master)
|
||||
[](https://travis-ci.org/mosbth/cimage)
|
||||
[](https://circleci.com/gh/mosbth/cimage)
|
||||
[](https://scrutinizer-ci.com/g/mosbth/cimage/build-status/resize)
|
||||
[](https://scrutinizer-ci.com/g/mosbth/cimage/?branch=resize)
|
||||
[](https://scrutinizer-ci.com/g/mosbth/cimage/?branch=resize)
|
||||
[](https://insight.sensiolabs.com/projects/ebc10d27-449d-42ca-b380-ba5ecb7813ba)
|
||||
|
||||
|
||||
|
||||
About
|
||||
-------------------------------------
|
||||
|
||||
<img src="http://dbwebb.se/kod-exempel/cimage/webroot/img.php?src=kodim07.png&w=200&c=140,140,520,340&sharpen"/>
|
||||
<img src="https://cimage.se/cimage/imgd.php?src=example/kodim07.png&w=200&c=140,140,520,340&sharpen"/>
|
||||
|
||||
`CImage` is a PHP class enabling resizing of images through scaling, cropping and filtering effects -- using PHP GD. The script `img.php` uses `CImage` to enable server-side image processing utilizing caching and optimization of the processed images.
|
||||
|
||||
@@ -22,7 +28,10 @@ Documentation
|
||||
--------------------------------------
|
||||
|
||||
Read full documentation at:
|
||||
http://dbwebb.se/opensource/cimage
|
||||
<strike>http://dbwebb.se/opensource/cimage</strike>
|
||||
|
||||
New website is being setup at [cimage.se](https://cimage.se), to improve documentation (work is ongoing).
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -46,14 +55,14 @@ There are several ways of installing. You either install the whole project which
|
||||
|
||||
The [sourcode is available on GitHub](https://github.com/mosbth/cimage). Clone, fork or [download as zip](https://github.com/mosbth/cimage/archive/master.zip).
|
||||
|
||||
**Latest stable version is v0.7.7 released 2015-10-21.**
|
||||
**Latest stable version is v0.7.18 released 2016-08-09.**
|
||||
|
||||
I prefer cloning like this. Do switch to the latest stable version.
|
||||
|
||||
```bash
|
||||
git clone git://github.com/mosbth/cimage.git
|
||||
cd cimage
|
||||
git checkout v0.7.7
|
||||
git checkout v0.7.18
|
||||
```
|
||||
|
||||
Make the cache-directory writable by the webserver.
|
||||
@@ -76,7 +85,7 @@ There are some all-included bundles of `img.php` that can be downloaded and used
|
||||
Dowload the version of your choice like this.
|
||||
|
||||
```bash
|
||||
wget https://raw.githubusercontent.com/mosbth/cimage/v0.7.7/webroot/imgp.php
|
||||
wget https://raw.githubusercontent.com/mosbth/cimage/v0.7.18/webroot/imgp.php
|
||||
```
|
||||
|
||||
Open up the file in your editor and edit the array `$config`. Ensure that the paths to the image directory and the cache directory matches your environment, or create an own config-file for the script.
|
||||
@@ -98,7 +107,7 @@ Lets take some use cases to let you know when and how `img.php` might be useful.
|
||||
|
||||
### Make a thumbnail
|
||||
|
||||
<img src="http://dbwebb.se/kod-exempel/cimage/webroot/img.php?src=kodim04.png&w=80&h=80&cf">
|
||||
<img src="https://cimage.se/cimage/imgd.php?src=example/kodim04.png&w=80&h=80&cf">
|
||||
|
||||
Lets say you have a larger image and you want to make a smaller thumbnail of it with a size of 80x80 pixels. You simply take the image and add constraints on `width`, `height` and you use the resize strategy `crop-to-fit` to crops out the parts of the image that does not fit.
|
||||
|
||||
@@ -112,7 +121,7 @@ To produce such a thumbnail, create a link like this:
|
||||
|
||||
Perhaps you got an image from a friend. The image was taken with the iPhone and thus rotated.
|
||||
|
||||
<img src="http://dbwebb.se/kod-exempel/cimage/webroot/img.php?src=issue36/me-270.jpg&w=250">
|
||||
<img src="https://cimage.se/cimage/imgd.php?src=example/issue36/me-270.jpg&w=250">
|
||||
|
||||
The original image is looking like this one, scaled down to a width of 250 pixels.
|
||||
|
||||
@@ -125,7 +134,7 @@ Lets call this *the URL-Photoshopper*. This is how the magic looks like.
|
||||
> `img.php?src=issue36/me-270.jpg&w=100&h=100&cf&aro`
|
||||
> `&rb=-25&a=8,30,30,38&f=grayscale&convolve=sharpen-alt`
|
||||
|
||||
<img src="http://dbwebb.se/kod-exempel/cimage/webroot/img.php?src=issue36/me-270.jpg&w=100&h=100&cf&aro&rb=-25&a=8,30,30,38&f=grayscale&convolve=sharpen-alt">
|
||||
<img src="https://cimage.se/cimage/imgd.php?src=example/issue36/me-270.jpg&w=100&h=100&cf&aro&rb=-25&a=8,30,30,38&f=grayscale&convolve=sharpen-alt">
|
||||
|
||||
For myself, I use `img.php` to put up all images on my website, it gives me the power of affecting the resulting images - without opening up a photo-editing application.
|
||||
|
||||
@@ -144,7 +153,7 @@ Try it out by pointing your browser to the test file `webroot/test/test.php`. It
|
||||
|
||||
###Process your first image
|
||||
|
||||
<img src="http://dbwebb.se/kod-exempel/cimage/webroot/img.php?src=kodim04.png&w=w2&a=40,0,50,0" alt=''>
|
||||
<img src="https://cimage.se/cimage/imgd.php?src=example/kodim04.png&w=w2&a=40,0,50,0" alt=''>
|
||||
|
||||
Try it yourself by opening up an image in your browser. Start with
|
||||
|
||||
@@ -198,7 +207,7 @@ Open an image through `img.php` by using its `src` attribute.
|
||||
|
||||
It looks like this.
|
||||
|
||||
<img src="http://dbwebb.se/kod-exempel/cimage/webroot/img.php?src=kodim13.png&w=w1&save-as=jpg">
|
||||
<img src="https://cimage.se/cimage/imgd.php?src=example/kodim13.png&w=w1&save-as=jpg">
|
||||
|
||||
All images are stored in a directory structure and you access them as:
|
||||
|
||||
@@ -212,7 +221,7 @@ Create a thumbnail of the image by applying constraints on width and height, or
|
||||
|
||||
| `&width=150` | `&height=150` | `&w=150&h=150` |
|
||||
|---------------------|---------------------|---------------------|
|
||||
| <img src=http://dbwebb.se/kod-exempel/cimage/webroot/img.php?src=kodim13.png&w=150 alt=''> | <img src=http://dbwebb.se/kod-exempel/cimage/webroot/img.php?src=kodim13.png&h=150 alt=''> | <img src=http://dbwebb.se/kod-exempel/cimage/webroot/img.php?src=kodim13.png&w=150&h=150 alt=''> |
|
||||
| <img src=https://cimage.se/cimage/imgd.php?src=example/kodim13.png&w=150 alt=''> | <img src=https://cimage.se/cimage/imgd.php?src=example/kodim13.png&h=150 alt=''> | <img src=https://cimage.se/cimage/imgd.php?src=example/kodim13.png&w=150&h=150 alt=''> |
|
||||
|
||||
By setting `width`, `height` or both, the image gets resized to be *not larger* than the defined dimensions *and* keeping its original aspect ratio.
|
||||
|
||||
@@ -227,10 +236,10 @@ Creating a thumbnail with a certain dimension of width and height, usually invol
|
||||
|
||||
| What | The image |
|
||||
|---------------------|---------------------|
|
||||
| **Original.** The original image resized with a max width and max height.<br>`?w=300&h=150` | <img src=http://dbwebb.se/kod-exempel/cimage/webroot/img.php?src=kodim13.png&w=300&h=150 alt=''> |
|
||||
| **Stretch.** Stretch the image so that the resulting image has the defined width and height.<br>`?w=300&h=150&stretch` | <img src=http://dbwebb.se/kod-exempel/cimage/webroot/img.php?src=kodim13.png&w=300&h=150&stretch alt=''> |
|
||||
| **Crop to fit.** Keep the aspect ratio and crop out the parts of the image that does not fit.<br>`?w=300&h=150&crop-to-fit` | <img src=http://dbwebb.se/kod-exempel/cimage/webroot/img.php?src=kodim13.png&w=300&h=150&crop-to-fit alt=''> |
|
||||
| **Fill to fit.** Keep the aspect ratio and fill then blank space with a background color.<br>`?w=300&h=150&fill-to-fit=006600` | <img src=http://dbwebb.se/kod-exempel/cimage/webroot/img.php?src=kodim13.png&w=300&h=150&fill-to-fit=006600 alt=''> |
|
||||
| **Original.** The original image resized with a max width and max height.<br>`?w=300&h=150` | <img src=https://cimage.se/cimage/imgd.php?src=example/kodim13.png&w=300&h=150 alt=''> |
|
||||
| **Stretch.** Stretch the image so that the resulting image has the defined width and height.<br>`?w=300&h=150&stretch` | <img src=https://cimage.se/cimage/imgd.php?src=example/kodim13.png&w=300&h=150&stretch alt=''> |
|
||||
| **Crop to fit.** Keep the aspect ratio and crop out the parts of the image that does not fit.<br>`?w=300&h=150&crop-to-fit` | <img src=https://cimage.se/cimage/imgd.php?src=example/kodim13.png&w=300&h=150&crop-to-fit alt=''> |
|
||||
| **Fill to fit.** Keep the aspect ratio and fill then blank space with a background color.<br>`?w=300&h=150&fill-to-fit=006600` | <img src=https://cimage.se/cimage/imgd.php?src=example/kodim13.png&w=300&h=150&fill-to-fit=006600 alt=''> |
|
||||
|
||||
Learn to crop your images, creative cropping can make wonderful images from appearingly useless originals.
|
||||
|
||||
@@ -247,7 +256,7 @@ Fill to fit is useful when you have some image that must fit in a certain dimens
|
||||
> `img.php?src=kodim13.png&w=600&aspect-ratio=4`
|
||||
> `&crop-to-fit&sharpen&save-as=jpg&q=30`
|
||||
|
||||
<img src=http://dbwebb.se/kod-exempel/cimage/webroot/img.php?src=kodim13.png&w=600&aspect-ratio=4&crop-to-fit&sharpen&save-as=jpg&q=30 alt=''>
|
||||
<img src=https://cimage.se/cimage/imgd.php?src=example/kodim13.png&w=600&aspect-ratio=4&crop-to-fit&sharpen&save-as=jpg&q=30 alt=''>
|
||||
|
||||
Here is a list of all parameters that you can use together with `img.php`, grouped by its basic intent of usage.
|
||||
|
||||
@@ -430,7 +439,7 @@ For example, the following image is created like this:
|
||||
|
||||
> `&w=300&save-as=jpg`
|
||||
|
||||
<img src="http://dbwebb.se/kod-exempel/cimage/webroot/img.php?src=kodim24.png&w=300&save-as=jpg" alt=''>
|
||||
<img src="https://cimage.se/cimage/imgd.php?src=example/kodim24.png&w=300&save-as=jpg" alt=''>
|
||||
|
||||
Its JSON-representation is retrieved like this:
|
||||
|
||||
|
100
REVISION.md
@@ -1,8 +1,104 @@
|
||||
Revision history
|
||||
=====================================
|
||||
|
||||
[](https://travis-ci.org/mosbth/cimage)
|
||||
[](https://scrutinizer-ci.com/g/mosbth/cimage/build-status/master)
|
||||
|
||||
|
||||
v0.8.* (2015-12-05) (branch resize)
|
||||
-------------------------------------
|
||||
|
||||
* Improving build phase using travis and scrutinizer.
|
||||
* Code validating with phpunit and phpcs.
|
||||
* Moved classes to src/, adding namespace and (only) support PSR-4.
|
||||
* Require PHP 5.4.
|
||||
|
||||
|
||||
v0.7.9* (2015-12-07)
|
||||
-------------------------------------
|
||||
|
||||
* Fix strict mode only reporting 404 when failure, #127.
|
||||
|
||||
|
||||
v0.7.19* (2016-08-31)
|
||||
-------------------------------------
|
||||
|
||||
* Correct XSS injection in `check_system.php`.
|
||||
* Composer suggests ext-imagick and ext-curl.
|
||||
|
||||
|
||||
v0.7.18 (2016-08-09)
|
||||
-------------------------------------
|
||||
|
||||
* Made `&lossless` a requirement to not use the original image.
|
||||
|
||||
|
||||
v0.7.17 (2016-08-09)
|
||||
-------------------------------------
|
||||
|
||||
* Made `&lossless` part of the generated cache filename.
|
||||
|
||||
|
||||
v0.7.16 (2016-08-09)
|
||||
-------------------------------------
|
||||
|
||||
* Fix default mode to be production.
|
||||
* Added pngquant as extra postprocessing utility for PNG-images, #154.
|
||||
* Bug `&status` wrong variable name for fast track cache.
|
||||
|
||||
|
||||
v0.7.15 (2016-08-09)
|
||||
-------------------------------------
|
||||
|
||||
* Added the [Lenna/Lena sample image](http://www.cs.cmu.edu/~chuck/lennapg/) as tif and created a png, jpeg and webp version using Imagick convert `convert lena.tif lena.{png,jpg,webp}`, #152.
|
||||
* Limited and basic support for WEBP format, se #132.
|
||||
|
||||
|
||||
v0.7.14 (2016-08-08)
|
||||
-------------------------------------
|
||||
|
||||
* Re-add removed cache directory.
|
||||
* Make fast track cache disabled by default in the config file.
|
||||
|
||||
|
||||
v0.7.13 (2016-08-08)
|
||||
-------------------------------------
|
||||
|
||||
* Moved functions from img.php to `functions.php`.
|
||||
* Added function `trace()` to measure speed and memory consumption, only for development.
|
||||
* Added fast cache #149.
|
||||
* Added `imgf.php` as shortcut to check for fast cache, before loading `img.php` as usual, adding `imgf_config.php` as symlink to `img_config.php`.
|
||||
* Created `defines.php` and moved definition av version there.
|
||||
* Fixed images in README, #148.
|
||||
* Initiated dependency injection to `CImage`, class names can be set in config file and will be injected to `CImage` from `img.php`. Not implemented for all classes. #151.
|
||||
* Enabled debug mode to make it easier to trace what actually happens while processing the image, #150.
|
||||
|
||||
|
||||
v0.7.12 (2016-06-01)
|
||||
-------------------------------------
|
||||
|
||||
* Fixed to correctly display image when using a resize strategy without height or width.
|
||||
* Fixed background color for option `no-upscale`, #144.
|
||||
|
||||
|
||||
v0.7.11 (2016-04-18)
|
||||
-------------------------------------
|
||||
|
||||
* Add option for `skip_original` to config file to always skip original, #118.
|
||||
|
||||
|
||||
v0.7.10 (2016-04-01)
|
||||
-------------------------------------
|
||||
|
||||
* Add backup option for images `src-alt`, #141.
|
||||
* Add require of ext-gd in composer.json, #133.
|
||||
* Fix strict mode only reporting 404 when failure, #127.
|
||||
|
||||
|
||||
v0.7.9 (2015-12-07)
|
||||
-------------------------------------
|
||||
|
||||
* Strict mode only reporting 404 when failure, #127.
|
||||
* Added correct CImage version to remote agent string, #131.
|
||||
* Adding CCache to improve cache handling of caching for dummy, remote and srgb. #130.
|
||||
|
||||
|
||||
v0.7.8 (2015-12-06)
|
||||
|
@@ -34,11 +34,15 @@ fi
|
||||
$ECHO "Creating '$TARGET_D', '$TARGET_P' and '$TARGET_S' by combining the following files:"
|
||||
$ECHO "\n"
|
||||
$ECHO "\n webroot/img_header.php"
|
||||
$ECHO "\n defines.php"
|
||||
$ECHO "\n functions.php"
|
||||
$ECHO "\n CHttpGet.php"
|
||||
$ECHO "\n CRemoteImage.php"
|
||||
$ECHO "\n CWhitelist.php"
|
||||
$ECHO "\n CAsciiArt.php"
|
||||
$ECHO "\n CImage.php"
|
||||
$ECHO "\n CCache.php"
|
||||
$ECHO "\n CFastTrackCache.php"
|
||||
$ECHO "\n webroot/img.php"
|
||||
$ECHO "\n"
|
||||
$ECHO "\n'$TARGET_D' is for development mode."
|
||||
@@ -59,6 +63,12 @@ cat webroot/img_header.php | sed "s|//'mode' => 'production',|'mode'
|
||||
|
||||
$ECHO "$NEWLINES" | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
|
||||
|
||||
tail -n +2 defines.php | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
|
||||
$ECHO "$NEWLINES" | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
|
||||
|
||||
tail -n +2 functions.php | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
|
||||
$ECHO "$NEWLINES" | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
|
||||
|
||||
tail -n +2 CHttpGet.php | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
|
||||
$ECHO "$NEWLINES" | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
|
||||
|
||||
@@ -74,6 +84,12 @@ $ECHO "$NEWLINES" | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
|
||||
tail -n +2 CImage.php | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
|
||||
$ECHO "$NEWLINES" | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
|
||||
|
||||
tail -n +2 CCache.php | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
|
||||
$ECHO "$NEWLINES" | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
|
||||
|
||||
tail -n +2 CFastTrackCache.php | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
|
||||
$ECHO "$NEWLINES" | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
|
||||
|
||||
tail -n +2 webroot/img.php | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
|
||||
$ECHO "$NEWLINES" | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
|
||||
|
||||
|
4
cache/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file
|
||||
!.gitignore
|
0
cache/README.md
vendored
0
cache/dummy/README.md
vendored
13
circle.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
machine:
|
||||
php:
|
||||
#version: 5.6.18
|
||||
|
||||
|
||||
|
||||
test:
|
||||
pre:
|
||||
- make install
|
||||
- make check
|
||||
|
||||
override:
|
||||
- make test
|
@@ -1,32 +1,39 @@
|
||||
{
|
||||
"name": "mos/cimage",
|
||||
"name": "mos/cimage",
|
||||
"type": "library",
|
||||
"description": "Process, scale, resize, crop and filter images.",
|
||||
"keywords": ["image", "imageprocessing", "gd"],
|
||||
"homepage": "http://dbwebb.se/opensource/cimage",
|
||||
"description": "Serverside image processing with PHP GD. Process, scale, resize, crop and filter images.",
|
||||
"keywords": ["image", "imageprocessing", "gd", "crop", "resize"],
|
||||
"homepage": "https://cimage.se/",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Mikael Roos",
|
||||
"email": "me@mikaelroos.se",
|
||||
"email": "mos@dbwebb.se",
|
||||
"homepage": "http://mikaelroos.se",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/mosbth/cimage",
|
||||
"issues": "https://github.com/mosbth/cimage/issues",
|
||||
"docs": "http://dbwebb.se/opensource/cimage"
|
||||
"docs": "https://cimage.se/doc"
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3"
|
||||
"php": ">=5.4",
|
||||
"ext-gd": "*"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-exif": "*",
|
||||
"ext-curl": "*",
|
||||
"ext-imagick": "*"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"CImage.php",
|
||||
"CHttpGet.php",
|
||||
"CRemoteImage.php",
|
||||
"CWhitelist.php",
|
||||
"CAsciiArt.php"
|
||||
"psr-4": {
|
||||
"Mos\\": "src/"
|
||||
},
|
||||
"files": [
|
||||
"src/defines.php",
|
||||
"src/functions.php"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
20
composer.lock
generated
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "336411b967cf65e460236df4df7e340a",
|
||||
"packages": [],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": ">=5.4",
|
||||
"ext-gd": "*"
|
||||
},
|
||||
"platform-dev": []
|
||||
}
|
208
features/bootstrap/FeatureContext.php
Normal file
@@ -0,0 +1,208 @@
|
||||
<?php
|
||||
|
||||
use Behat\Behat\Tester\Exception\PendingException;
|
||||
use Behat\Behat\Context\Context;
|
||||
use Behat\Behat\Context\SnippetAcceptingContext;
|
||||
use Behat\Gherkin\Node\PyStringNode;
|
||||
use Behat\Gherkin\Node\TableNode;
|
||||
|
||||
require __DIR__ . "/assert.php";
|
||||
|
||||
/**
|
||||
* Defines application features from the specific context.
|
||||
*/
|
||||
class FeatureContext implements Context, SnippetAcceptingContext
|
||||
{
|
||||
private $url = null;
|
||||
|
||||
private $headers = [];
|
||||
private $imageString = null;
|
||||
private $image = null;
|
||||
private $imageJSON = null;
|
||||
|
||||
|
||||
/**
|
||||
* Initializes context.
|
||||
*
|
||||
* Every scenario gets its own context instance.
|
||||
* You can also pass arbitrary arguments to the
|
||||
* context constructor through behat.yml.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @Given Set mode :arg1
|
||||
*/
|
||||
public function setMode($arg1 = null)
|
||||
{
|
||||
$this->url = "http://localhost/git/cimage/webroot/";
|
||||
switch ($arg1) {
|
||||
case "development":
|
||||
$this->url .= "imgd.php";
|
||||
break;
|
||||
case "production":
|
||||
$this->url .= "imgp.php";
|
||||
break;
|
||||
case "strict":
|
||||
$this->url .= "imgs.php";
|
||||
break;
|
||||
default:
|
||||
$this->url .= "img.php";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @Given Set src :arg1
|
||||
*/
|
||||
public function setSrc($arg1)
|
||||
{
|
||||
if (is_null($this->url)) {
|
||||
$this->setMode();
|
||||
}
|
||||
|
||||
$this->url .= "?src=$arg1";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @When Get image
|
||||
*/
|
||||
public function getImage()
|
||||
{
|
||||
//echo $this->url;
|
||||
$res = file_get_contents($this->url);
|
||||
assertNotEquals(false, $res);
|
||||
|
||||
$this->imageString = $res;
|
||||
$this->headers = $http_response_header;
|
||||
|
||||
if (is_null($this->imageJSON)) {
|
||||
$this->getImageAsJson();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @When Get image as JSON
|
||||
*/
|
||||
public function getImageAsJson()
|
||||
{
|
||||
$res = file_get_contents($this->url . "&json");
|
||||
assertNotEquals(false, $res);
|
||||
|
||||
$res = json_decode($res, true);
|
||||
assertNotEquals(null, $res);
|
||||
|
||||
$this->imageJSON = $res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @When Get headers for image
|
||||
*/
|
||||
public function getHeadersForImage()
|
||||
{
|
||||
//echo $this->url;
|
||||
$res = get_headers($this->url);
|
||||
assertNotEquals(false, $res);
|
||||
|
||||
$this->headers = $http_response_header;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @Then Returns status code :arg1
|
||||
*/
|
||||
public function returnsStatusCode($arg1)
|
||||
{
|
||||
assertNotEquals(
|
||||
false,
|
||||
strpos($this->headers[0], $arg1)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function compareImageJsonToHeaders()
|
||||
{
|
||||
$contentLength = "Content-Length: " . $this->imageJSON["size"];
|
||||
assertContains(
|
||||
$contentLength,
|
||||
$this->headers
|
||||
);
|
||||
|
||||
$contentType = "Content-Type: " . $this->imageJSON["mimeType"];
|
||||
assertContains(
|
||||
$contentType,
|
||||
$this->headers
|
||||
);
|
||||
|
||||
$lastModified = "Last-Modified: " . $this->imageJSON["cacheGmdate"] . " GMT";
|
||||
assertContains(
|
||||
$lastModified,
|
||||
$this->headers
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function compareImageJsonToSavedJson($file)
|
||||
{
|
||||
$res = file_get_contents("$file.json");
|
||||
assertNotEquals(false, $res);
|
||||
|
||||
$res = json_decode($res, true);
|
||||
assertNotEquals(null, $res);
|
||||
|
||||
$keys = [
|
||||
"mimeType",
|
||||
"width",
|
||||
"height",
|
||||
"size",
|
||||
"colors",
|
||||
"pngType",
|
||||
];
|
||||
foreach ($keys as $key) {
|
||||
if (array_key_exists($key, $res)
|
||||
&& array_key_exists($key, $this->imageJSON)
|
||||
) {
|
||||
assertEquals(
|
||||
$res[$key],
|
||||
$this->imageJSON[$key]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @Then Compares to image :arg1
|
||||
*/
|
||||
public function comparesToImage($arg1)
|
||||
{
|
||||
$base = __DIR__ . "/../img";
|
||||
$res = file_get_contents("$base/$arg1");
|
||||
assertNotEquals(false, $res);
|
||||
|
||||
assertEquals($this->imageString, $res);
|
||||
|
||||
$this->compareImageJsonToHeaders();
|
||||
$this->compareImageJsonToSavedJson("$base/$arg1");
|
||||
}
|
||||
}
|
32
features/bootstrap/assert.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
* Assert functions.
|
||||
*/
|
||||
function assertNotEquals($expected, $actual)
|
||||
{
|
||||
if (!($expected !== $actual)) {
|
||||
throw new Exception("Failed asserting that '$expected' is not equal to '$actual'.");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
function assertEquals($expected, $actual)
|
||||
{
|
||||
if (!($expected === $actual)) {
|
||||
throw new Exception("Failed asserting that '$expected' is equal to '$actual'.");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Check that $needle is an element of $haystack.
|
||||
*/
|
||||
|
||||
function assertContains($needle, $haystack)
|
||||
{
|
||||
if (!in_array($needle, $haystack)) {
|
||||
throw new Exception("Failed asserting that '$needle' is not in haystack.");
|
||||
}
|
||||
}
|
8
features/dummy.feature
Normal file
@@ -0,0 +1,8 @@
|
||||
Feature: dummy
|
||||
Display an dummy image without using an existing image on file.
|
||||
|
||||
Scenario: Set source to be dummy
|
||||
Given Set src "dummy"
|
||||
When Get image
|
||||
Then Returns status code "200"
|
||||
And Compares to image "dummy"
|
BIN
features/img/dummy
Normal file
After Width: | Height: | Size: 334 B |
19
features/img/dummy.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"src": "dummy_100_100_q60_co-1",
|
||||
"srcGmdate": "Fri, 03 Jun 2016 07:38:56",
|
||||
"cache": "_._dummy_100_100_q60_co-1_q60_co-1",
|
||||
"cacheGmdate": "Fri, 03 Jun 2016 07:38:56",
|
||||
"filename": "_._dummy_100_100_q60_co-1_q60_co-1",
|
||||
"mimeType": "image/png",
|
||||
"width": 100,
|
||||
"height": 100,
|
||||
"aspectRatio": 1,
|
||||
"size": 334,
|
||||
"colors": 1,
|
||||
"includedFiles": 6,
|
||||
"memoryPeek": "0.341 MB",
|
||||
"memoryCurrent": "0.316 MB",
|
||||
"memoryLimit": "128M",
|
||||
"loadTime": "0.01s",
|
||||
"pngType": "PNG is type 6, RGB with alpha channel (PNG 32-bit)"
|
||||
}
|
BIN
features/img/test_100x100.png
Normal file
After Width: | Height: | Size: 392 B |
19
features/img/test_100x100.png.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"src": "test_100x100.png",
|
||||
"srcGmdate": "Fri, 03 Jun 2016 08:12:39",
|
||||
"cache": "_._test_100x100.png_q60_co-1",
|
||||
"cacheGmdate": "Fri, 03 Jun 2016 08:19:37",
|
||||
"filename": "_._test_100x100.png_q60_co-1",
|
||||
"mimeType": "image/png",
|
||||
"width": 100,
|
||||
"height": 100,
|
||||
"aspectRatio": 1,
|
||||
"size": 392,
|
||||
"colors": 6,
|
||||
"includedFiles": 6,
|
||||
"memoryPeek": "0.339 MB",
|
||||
"memoryCurrent": "0.316 MB",
|
||||
"memoryLimit": "128M",
|
||||
"loadTime": "0.012s",
|
||||
"pngType": "PNG is type 6, RGB with alpha channel (PNG 32-bit)"
|
||||
}
|
13
features/src.feature
Normal file
@@ -0,0 +1,13 @@
|
||||
Feature: src
|
||||
Display an image by selecting its source.
|
||||
|
||||
Scenario: Source is not a valid image name
|
||||
Given Set src "NO_IMAGE"
|
||||
When Get headers for image
|
||||
Then Returns status code "404"
|
||||
|
||||
Scenario: Get only source image
|
||||
Given Set src "test_100x100.png"
|
||||
When Get image
|
||||
Then Returns status code "200"
|
||||
And Compares to image "test_100x100.png"
|
@@ -3,9 +3,10 @@
|
||||
* Autoloader for CImage and related class files.
|
||||
*
|
||||
*/
|
||||
//include __DIR__ . "/../CHttpGet.php";
|
||||
//include __DIR__ . "/../CRemoteImage.php";
|
||||
//include __DIR__ . "/../CImage.php";
|
||||
require_once __DIR__ . "/defines.php";
|
||||
require_once __DIR__ . "/functions.php";
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Autoloader for classes.
|
||||
@@ -15,8 +16,7 @@
|
||||
* @return void
|
||||
*/
|
||||
spl_autoload_register(function ($class) {
|
||||
//$path = CIMAGE_SOURCE_PATH . "/{$class}.php";
|
||||
$path = __DIR__ . "/{$class}.php";
|
||||
$path = __DIR__ . "/src/CImage/{$class}.php";
|
||||
if (is_file($path)) {
|
||||
require($path);
|
||||
}
|
22
phpunit.xml
@@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<phpunit
|
||||
bootstrap="test/config.php">
|
||||
|
||||
<testsuites>
|
||||
<testsuite name="all">
|
||||
<directory>test</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<logging>
|
||||
<log type="coverage-html" target="coverage" charset="UTF-8" highlight="true" lowUpperBound="35" highLowerBound="70" />
|
||||
<log type="coverage-clover" target="coverage.clover" />
|
||||
</logging>
|
||||
|
||||
<filter>
|
||||
<whitelist processUncoveredFilesFromWhitelist="true">
|
||||
<file>*.php</file>
|
||||
</whitelist>
|
||||
</filter>
|
||||
|
||||
</phpunit>
|
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Mos\CImage;
|
||||
|
||||
/**
|
||||
* Create an ASCII version of an image.
|
||||
*
|
||||
@@ -175,7 +178,7 @@ class CAsciiArt
|
||||
*/
|
||||
public function getLuminance($red, $green, $blue)
|
||||
{
|
||||
switch($this->luminanceStrategy) {
|
||||
switch ($this->luminanceStrategy) {
|
||||
case 1:
|
||||
$luminance = ($red * 0.2126 + $green * 0.7152 + $blue * 0.0722) / 255;
|
||||
break;
|
110
src/CImage/CCache.php
Normal file
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
namespace Mos\CImage;
|
||||
|
||||
/**
|
||||
* Deal with the cache directory and cached items.
|
||||
*
|
||||
*/
|
||||
class CCache
|
||||
{
|
||||
/**
|
||||
* Path to the cache directory.
|
||||
*/
|
||||
private $path;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set the path to the cache dir which must exist.
|
||||
*
|
||||
* @param string path to the cache dir.
|
||||
*
|
||||
* @throws Exception when $path is not a directory.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setDir($path)
|
||||
{
|
||||
if (!is_dir($path)) {
|
||||
throw new Exception("Cachedir is not a directory.");
|
||||
}
|
||||
|
||||
$this->path = $path;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the path to the cache subdir and try to create it if its not there.
|
||||
*
|
||||
* @param string $subdir name of subdir
|
||||
* @param array $create default is to try to create the subdir
|
||||
*
|
||||
* @return string | boolean as real path to the subdir or
|
||||
* false if it does not exists
|
||||
*/
|
||||
public function getPathToSubdir($subdir, $create = true)
|
||||
{
|
||||
$path = realpath($this->path . "/" . $subdir);
|
||||
|
||||
if (is_dir($path)) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
if ($create && is_writable($this->path)) {
|
||||
$path = $this->path . "/" . $subdir;
|
||||
|
||||
if (mkdir($path)) {
|
||||
return realpath($path);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get status of the cache subdir.
|
||||
*
|
||||
* @param string $subdir name of subdir
|
||||
*
|
||||
* @return string with status
|
||||
*/
|
||||
public function getStatusOfSubdir($subdir)
|
||||
{
|
||||
$path = realpath($this->path . "/" . $subdir);
|
||||
|
||||
$exists = is_dir($path);
|
||||
$res = $exists ? "exists" : "does not exist";
|
||||
|
||||
if ($exists) {
|
||||
$res .= is_writable($path) ? ", writable" : ", not writable";
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Remove the cache subdir.
|
||||
*
|
||||
* @param string $subdir name of subdir
|
||||
*
|
||||
* @return null | boolean true if success else false, null if no operation
|
||||
*/
|
||||
public function removeSubdir($subdir)
|
||||
{
|
||||
$path = realpath($this->path . "/" . $subdir);
|
||||
|
||||
if (is_dir($path)) {
|
||||
return rmdir($path);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
241
src/CImage/CFastTrackCache.php
Normal file
@@ -0,0 +1,241 @@
|
||||
<?php
|
||||
|
||||
namespace Mos\CImage;
|
||||
|
||||
/**
|
||||
* Enable a fast track cache with a json representation of the image delivery.
|
||||
*
|
||||
*/
|
||||
class CFastTrackCache
|
||||
{
|
||||
/**
|
||||
* Cache is disabled to start with.
|
||||
*/
|
||||
private $enabled = false;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Path to the cache directory.
|
||||
*/
|
||||
private $path;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Filename of current cache item.
|
||||
*/
|
||||
private $filename;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Container with items to store as cached item.
|
||||
*/
|
||||
private $container;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Enable or disable cache.
|
||||
*
|
||||
* @param boolean $enable set to true to enable, false to disable
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function enable($enabled)
|
||||
{
|
||||
$this->enabled = $enabled;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set the path to the cache dir which must exist.
|
||||
*
|
||||
* @param string $path to the cache dir.
|
||||
*
|
||||
* @throws Exception when $path is not a directory.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setCacheDir($path)
|
||||
{
|
||||
if (!is_dir($path)) {
|
||||
throw new Exception("Cachedir is not a directory.");
|
||||
}
|
||||
|
||||
$this->path = rtrim($path, "/");
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set the filename to store in cache, use the querystring to create that
|
||||
* filename.
|
||||
*
|
||||
* @param array $clear items to clear in $_GET when creating the filename.
|
||||
*
|
||||
* @return string as filename created.
|
||||
*/
|
||||
public function setFilename($clear)
|
||||
{
|
||||
$query = $_GET;
|
||||
|
||||
// Remove parts from querystring that should not be part of filename
|
||||
foreach ($clear as $value) {
|
||||
unset($query[$value]);
|
||||
}
|
||||
|
||||
arsort($query);
|
||||
$queryAsString = http_build_query($query);
|
||||
|
||||
$this->filename = md5($queryAsString);
|
||||
|
||||
if (CIMAGE_DEBUG) {
|
||||
$this->container["query-string"] = $queryAsString;
|
||||
}
|
||||
|
||||
return $this->filename;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Add header items.
|
||||
*
|
||||
* @param string $header add this as header.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addHeader($header)
|
||||
{
|
||||
$this->container["header"][] = $header;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Add header items on output, these are not output when 304.
|
||||
*
|
||||
* @param string $header add this as header.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addHeaderOnOutput($header)
|
||||
{
|
||||
$this->container["header-output"][] = $header;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set path to source image to.
|
||||
*
|
||||
* @param string $source path to source image file.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setSource($source)
|
||||
{
|
||||
$this->container["source"] = $source;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set last modified of source image, use to check for 304.
|
||||
*
|
||||
* @param string $lastModified
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setLastModified($lastModified)
|
||||
{
|
||||
$this->container["last-modified"] = $lastModified;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get filename of cached item.
|
||||
*
|
||||
* @return string as filename.
|
||||
*/
|
||||
public function getFilename()
|
||||
{
|
||||
return $this->path . "/" . $this->filename;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Write current item to cache.
|
||||
*
|
||||
* @return boolean if cache file was written.
|
||||
*/
|
||||
public function writeToCache()
|
||||
{
|
||||
if (!$this->enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_dir($this->path) && is_writable($this->path)) {
|
||||
$filename = $this->getFilename();
|
||||
return file_put_contents($filename, json_encode($this->container)) !== false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Output current item from cache, if available.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function output()
|
||||
{
|
||||
$filename = $this->getFilename();
|
||||
if (!is_readable($filename)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$item = json_decode(file_get_contents($filename), true);
|
||||
|
||||
if (!is_readable($item["source"])) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($item["header"] as $value) {
|
||||
header($value);
|
||||
}
|
||||
|
||||
if (isset($_SERVER["HTTP_IF_MODIFIED_SINCE"])
|
||||
&& strtotime($_SERVER["HTTP_IF_MODIFIED_SINCE"]) == $item["last-modified"]) {
|
||||
header("HTTP/1.0 304 Not Modified");
|
||||
if (CIMAGE_DEBUG) {
|
||||
trace(__CLASS__ . " 304");
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
foreach ($item["header-output"] as $value) {
|
||||
header($value);
|
||||
}
|
||||
|
||||
if (CIMAGE_DEBUG) {
|
||||
trace(__CLASS__ . " 200");
|
||||
}
|
||||
readfile($item["source"]);
|
||||
exit;
|
||||
}
|
||||
}
|
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Mos\CImage;
|
||||
|
||||
/**
|
||||
* Get a image from a remote server using HTTP GET and If-Modified-Since.
|
||||
*
|
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Mos\CImage;
|
||||
|
||||
/**
|
||||
* Resize and crop images on the fly, store generated images in a cache.
|
||||
*
|
||||
@@ -155,6 +158,13 @@ class CImage
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Do lossy output using external postprocessing tools.
|
||||
*/
|
||||
private $lossy = null;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Verbose mode to print out a trace and display the created image
|
||||
*/
|
||||
@@ -190,7 +200,15 @@ class CImage
|
||||
|
||||
|
||||
/**
|
||||
* Path to command for filter optimize, for example optipng or null.
|
||||
* Path to command for lossy optimize, for example pngquant.
|
||||
*/
|
||||
private $pngLossy;
|
||||
private $pngLossyCmd;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Path to command for filter optimize, for example optipng.
|
||||
*/
|
||||
private $pngFilter;
|
||||
private $pngFilterCmd;
|
||||
@@ -198,7 +216,7 @@ class CImage
|
||||
|
||||
|
||||
/**
|
||||
* Path to command for deflate optimize, for example pngout or null.
|
||||
* Path to command for deflate optimize, for example pngout.
|
||||
*/
|
||||
private $pngDeflate;
|
||||
private $pngDeflateCmd;
|
||||
@@ -208,8 +226,8 @@ class CImage
|
||||
/**
|
||||
* Path to command to optimize jpeg images, for example jpegtran or null.
|
||||
*/
|
||||
private $jpegOptimize;
|
||||
private $jpegOptimizeCmd;
|
||||
private $jpegOptimize;
|
||||
private $jpegOptimizeCmd;
|
||||
|
||||
|
||||
|
||||
@@ -339,25 +357,33 @@ class CImage
|
||||
/**
|
||||
* Used with option area to set which parts of the image to use.
|
||||
*/
|
||||
private $area;
|
||||
private $offset;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Calculate target dimension for image when using fill-to-fit resize strategy.
|
||||
*/
|
||||
* Calculate target dimension for image when using fill-to-fit resize strategy.
|
||||
*/
|
||||
private $fillWidth;
|
||||
private $fillHeight;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Allow remote file download, default is to disallow remote file download.
|
||||
*/
|
||||
* Allow remote file download, default is to disallow remote file download.
|
||||
*/
|
||||
private $allowRemote = false;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Path to cache for remote download.
|
||||
*/
|
||||
private $remoteCache;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Pattern to recognize a remote file.
|
||||
*/
|
||||
@@ -372,6 +398,12 @@ class CImage
|
||||
private $useCache = true;
|
||||
|
||||
|
||||
/**
|
||||
* Disable the fasttrackCacke to start with, inject an object to enable it.
|
||||
*/
|
||||
private $fastTrackCache = null;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Set whitelist for valid hostnames from where remote source can be
|
||||
@@ -400,10 +432,15 @@ class CImage
|
||||
*/
|
||||
const RESIZE = 1;
|
||||
const RESAMPLE = 2;
|
||||
private $copyStrategy = NULL;
|
||||
private $copyStrategy = null;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Class for image resizer.
|
||||
*/
|
||||
private $imageResizer = null;
|
||||
|
||||
/**
|
||||
* Properties, the class is mutable and the method setOptions()
|
||||
* decides (partly) what properties are created.
|
||||
@@ -435,6 +472,27 @@ class CImage
|
||||
{
|
||||
$this->setSource($imageSrc, $imageFolder);
|
||||
$this->setTarget($saveFolder, $saveName);
|
||||
$this->imageResizer = new CImageResizer(array($this, 'log'));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Inject object and use it, must be available as member.
|
||||
*
|
||||
* @param string $property to set as object.
|
||||
* @param object $object to set to property.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function injectDependency($property, $object)
|
||||
{
|
||||
if (!property_exists($this, $property)) {
|
||||
$this->raiseError("Injecting unknown property.");
|
||||
}
|
||||
$this->$property = $object;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
@@ -512,13 +570,15 @@ class CImage
|
||||
* Allow or disallow remote image download.
|
||||
*
|
||||
* @param boolean $allow true or false to enable and disable.
|
||||
* @param string $cache path to cache dir.
|
||||
* @param string $pattern to use to detect if its a remote file.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setRemoteDownload($allow, $pattern = null)
|
||||
public function setRemoteDownload($allow, $cache, $pattern = null)
|
||||
{
|
||||
$this->allowRemote = $allow;
|
||||
$this->remoteCache = $cache;
|
||||
$this->remotePattern = is_null($pattern) ? $this->remotePattern : $pattern;
|
||||
|
||||
$this->log(
|
||||
@@ -606,7 +666,7 @@ class CImage
|
||||
*/
|
||||
private function checkFileExtension($extension)
|
||||
{
|
||||
$valid = array('jpg', 'jpeg', 'png', 'gif');
|
||||
$valid = array('jpg', 'jpeg', 'png', 'gif', 'webp');
|
||||
|
||||
in_array(strtolower($extension), $valid)
|
||||
or $this->raiseError('Not a valid file extension.');
|
||||
@@ -629,7 +689,7 @@ class CImage
|
||||
|
||||
if ($extension == 'jpeg') {
|
||||
$extension = 'jpg';
|
||||
}
|
||||
}
|
||||
|
||||
return $extension;
|
||||
}
|
||||
@@ -650,21 +710,12 @@ class CImage
|
||||
}
|
||||
|
||||
$remote = new CRemoteImage();
|
||||
$cache = $this->saveFolder . "/remote/";
|
||||
|
||||
if (!is_dir($cache)) {
|
||||
if (!is_writable($this->saveFolder)) {
|
||||
throw new Exception("Can not create remote cache, cachefolder not writable.");
|
||||
}
|
||||
mkdir($cache);
|
||||
$this->log("The remote cache does not exists, creating it.");
|
||||
}
|
||||
|
||||
if (!is_writable($cache)) {
|
||||
if (!is_writable($this->remoteCache)) {
|
||||
$this->log("The remote cache is not writable.");
|
||||
}
|
||||
|
||||
$remote->setCache($cache);
|
||||
$remote->setCache($this->remoteCache);
|
||||
$remote->useCache($this->useCache);
|
||||
$src = $remote->download($src);
|
||||
|
||||
@@ -802,6 +853,9 @@ class CImage
|
||||
// Output format
|
||||
'outputFormat' => null,
|
||||
'dpr' => 1,
|
||||
|
||||
// Postprocessing using external tools
|
||||
'lossy' => null,
|
||||
);
|
||||
|
||||
// Convert crop settings from string to array
|
||||
@@ -916,17 +970,36 @@ class CImage
|
||||
is_readable($file)
|
||||
or $this->raiseError('Image file does not exist.');
|
||||
|
||||
// Get details on image
|
||||
$info = list($this->width, $this->height, $this->fileType, $this->attr) = getimagesize($file);
|
||||
$info = list($this->width, $this->height, $this->fileType) = getimagesize($file);
|
||||
if (empty($info)) {
|
||||
throw new Exception("The file doesn't seem to be a valid image.");
|
||||
// To support webp
|
||||
$this->fileType = false;
|
||||
if (function_exists("exif_imagetype")) {
|
||||
$this->fileType = exif_imagetype($file);
|
||||
if ($this->fileType === false) {
|
||||
if (function_exists("imagecreatefromwebp")) {
|
||||
$webp = imagecreatefromwebp($file);
|
||||
if ($webp !== false) {
|
||||
$this->width = imagesx($webp);
|
||||
$this->height = imagesy($webp);
|
||||
$this->fileType = IMG_WEBP;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->fileType) {
|
||||
throw new Exception("Loading image details, the file doesn't seem to be a valid image.");
|
||||
}
|
||||
|
||||
$this->imageResizer->setSource($this->width, $this->height);
|
||||
|
||||
if ($this->verbose) {
|
||||
$this->log("Loading image details for: {$file}");
|
||||
$this->log("#Loading image details for: {$file}");
|
||||
$this->log(" Image width x height (type): {$this->width} x {$this->height} ({$this->fileType}).");
|
||||
$this->log(" Image filesize: " . filesize($file) . " bytes.");
|
||||
$this->log(" Image mimetype: " . image_type_to_mime_type($this->fileType));
|
||||
$this->log(" Image mimetype: " . $this->getMimeType());
|
||||
}
|
||||
|
||||
return $this;
|
||||
@@ -935,74 +1008,35 @@ class CImage
|
||||
|
||||
|
||||
/**
|
||||
* Init new width and height and do some sanity checks on constraints, before any
|
||||
* processing can be done.
|
||||
* Get mime type for image type.
|
||||
*
|
||||
* @return $this
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function getMimeType()
|
||||
{
|
||||
if ($this->fileType === IMG_WEBP) {
|
||||
return "image/webp";
|
||||
}
|
||||
|
||||
return image_type_to_mime_type($this->fileType);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Init new width and height and do some sanity checks on constraints,
|
||||
* before anyprocessing can be done.
|
||||
*
|
||||
* @return $this
|
||||
* @throws Exception
|
||||
*/
|
||||
public function initDimensions()
|
||||
{
|
||||
$this->log("Init dimension (before) newWidth x newHeight is {$this->newWidth} x {$this->newHeight}.");
|
||||
|
||||
// width as %
|
||||
if ($this->newWidth[strlen($this->newWidth)-1] == '%') {
|
||||
$this->newWidth = $this->width * substr($this->newWidth, 0, -1) / 100;
|
||||
$this->log("Setting new width based on % to {$this->newWidth}");
|
||||
}
|
||||
|
||||
// height as %
|
||||
if ($this->newHeight[strlen($this->newHeight)-1] == '%') {
|
||||
$this->newHeight = $this->height * substr($this->newHeight, 0, -1) / 100;
|
||||
$this->log("Setting new height based on % to {$this->newHeight}");
|
||||
}
|
||||
|
||||
is_null($this->aspectRatio) or is_numeric($this->aspectRatio) or $this->raiseError('Aspect ratio out of range');
|
||||
|
||||
// width & height from aspect ratio
|
||||
if ($this->aspectRatio && is_null($this->newWidth) && is_null($this->newHeight)) {
|
||||
if ($this->aspectRatio >= 1) {
|
||||
$this->newWidth = $this->width;
|
||||
$this->newHeight = $this->width / $this->aspectRatio;
|
||||
$this->log("Setting new width & height based on width & aspect ratio (>=1) to (w x h) {$this->newWidth} x {$this->newHeight}");
|
||||
|
||||
} else {
|
||||
$this->newHeight = $this->height;
|
||||
$this->newWidth = $this->height * $this->aspectRatio;
|
||||
$this->log("Setting new width & height based on width & aspect ratio (<1) to (w x h) {$this->newWidth} x {$this->newHeight}");
|
||||
}
|
||||
|
||||
} elseif ($this->aspectRatio && is_null($this->newWidth)) {
|
||||
$this->newWidth = $this->newHeight * $this->aspectRatio;
|
||||
$this->log("Setting new width based on aspect ratio to {$this->newWidth}");
|
||||
|
||||
} elseif ($this->aspectRatio && is_null($this->newHeight)) {
|
||||
$this->newHeight = $this->newWidth / $this->aspectRatio;
|
||||
$this->log("Setting new height based on aspect ratio to {$this->newHeight}");
|
||||
}
|
||||
|
||||
// Change width & height based on dpr
|
||||
if ($this->dpr != 1) {
|
||||
if (!is_null($this->newWidth)) {
|
||||
$this->newWidth = round($this->newWidth * $this->dpr);
|
||||
$this->log("Setting new width based on dpr={$this->dpr} - w={$this->newWidth}");
|
||||
}
|
||||
if (!is_null($this->newHeight)) {
|
||||
$this->newHeight = round($this->newHeight * $this->dpr);
|
||||
$this->log("Setting new height based on dpr={$this->dpr} - h={$this->newHeight}");
|
||||
}
|
||||
}
|
||||
|
||||
// Check values to be within domain
|
||||
is_null($this->newWidth)
|
||||
or is_numeric($this->newWidth)
|
||||
or $this->raiseError('Width not numeric');
|
||||
|
||||
is_null($this->newHeight)
|
||||
or is_numeric($this->newHeight)
|
||||
or $this->raiseError('Height not numeric');
|
||||
|
||||
$this->log("Init dimension (after) newWidth x newHeight is {$this->newWidth} x {$this->newHeight}.");
|
||||
$this->imageResizer->setBaseWidthHeight($this->newWidth, $this->newHeight)
|
||||
->setBaseAspecRatio($this->aspectRatio)
|
||||
->setBaseDevicePixelRate($this->dpr)
|
||||
->prepareTargetDimensions();
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -1016,6 +1050,31 @@ class CImage
|
||||
*/
|
||||
public function calculateNewWidthAndHeight()
|
||||
{
|
||||
$imres = $this->imageResizer;
|
||||
$strategy = null;
|
||||
|
||||
$strategy = $imres::KEEP_RATIO;
|
||||
|
||||
if ($this->keepRatio == false) {
|
||||
$strategy = $imres::STRETCH;
|
||||
}
|
||||
|
||||
if ($this->cropToFit == true) {
|
||||
$strategy = $imres::CROP_TO_FIT;
|
||||
}
|
||||
|
||||
if ($this->fillToFit == true) {
|
||||
$strategy = $imres::FILL_TO_FIT;
|
||||
}
|
||||
|
||||
$imres->setResizeStrategy($strategy)
|
||||
->allowUpscale($this->upscale)
|
||||
->calculateTargetWidthAndHeight();
|
||||
|
||||
//$this->newWidth = $imres->getTargetWidth();
|
||||
//$this->newHeight = $imres->getTargetHeight();
|
||||
|
||||
/*
|
||||
// Crop, use cropped width and height as base for calulations
|
||||
$this->log("Calculate new width and height.");
|
||||
$this->log("Original width x height is {$this->width} x {$this->height}.");
|
||||
@@ -1098,7 +1157,13 @@ class CImage
|
||||
$this->newWidth = round($factor * $width);
|
||||
$this->log("New height was set.");
|
||||
|
||||
} else {
|
||||
|
||||
// Use existing width and height as new width and height.
|
||||
$this->newWidth = $width;
|
||||
$this->newHeight = $height;
|
||||
}
|
||||
|
||||
|
||||
// Get image dimensions for pre-resize image.
|
||||
if ($this->cropToFit || $this->fillToFit) {
|
||||
@@ -1137,18 +1202,12 @@ class CImage
|
||||
$this->newHeight = round(isset($this->newHeight) ? $this->newHeight : $this->crop['height']);
|
||||
}
|
||||
|
||||
// Fill to fit, ensure to set new width and height
|
||||
/*if ($this->fillToFit) {
|
||||
$this->log("FillToFit.");
|
||||
$this->newWidth = round(isset($this->newWidth) ? $this->newWidth : $this->crop['width']);
|
||||
$this->newHeight = round(isset($this->newHeight) ? $this->newHeight : $this->crop['height']);
|
||||
}*/
|
||||
|
||||
// No new height or width is set, use existing measures.
|
||||
$this->newWidth = round(isset($this->newWidth) ? $this->newWidth : $this->width);
|
||||
$this->newHeight = round(isset($this->newHeight) ? $this->newHeight : $this->height);
|
||||
$this->log("Calculated new width x height as {$this->newWidth} x {$this->newHeight}.");
|
||||
|
||||
*/
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -1161,7 +1220,10 @@ class CImage
|
||||
*/
|
||||
public function reCalculateDimensions()
|
||||
{
|
||||
$this->log("Re-calculate image dimensions, newWidth x newHeigh was: " . $this->newWidth . " x " . $this->newHeight);
|
||||
$this->log("Re-calculate image dimensions, newWidth x newHeigh was: "
|
||||
. $this->newWidth
|
||||
. " x "
|
||||
. $this->newHeight);
|
||||
|
||||
$this->newWidth = $this->newWidthOrig;
|
||||
$this->newHeight = $this->newHeightOrig;
|
||||
@@ -1282,6 +1344,7 @@ class CImage
|
||||
&& !$this->autoRotate
|
||||
&& !$this->bgColor
|
||||
&& ($this->upscale === self::UPSCALE_DEFAULT)
|
||||
&& !$this->lossy
|
||||
) {
|
||||
$this->log("Using original image.");
|
||||
$this->output($this->pathToImage);
|
||||
@@ -1307,6 +1370,7 @@ class CImage
|
||||
$filename = basename($this->pathToImage);
|
||||
$cropToFit = $this->cropToFit ? '_cf' : null;
|
||||
$fillToFit = $this->fillToFit ? '_ff' : null;
|
||||
$stretch = $this->keepRatio === false ? '_st' : null;
|
||||
$crop_x = $this->crop_x ? "_x{$this->crop_x}" : null;
|
||||
$crop_y = $this->crop_y ? "_y{$this->crop_y}" : null;
|
||||
$scale = $this->scale ? "_s{$this->scale}" : null;
|
||||
@@ -1315,6 +1379,7 @@ class CImage
|
||||
$compress = $this->compress ? "_co{$this->compress}" : null;
|
||||
$rotateBefore = $this->rotateBefore ? "_rb{$this->rotateBefore}" : null;
|
||||
$rotateAfter = $this->rotateAfter ? "_ra{$this->rotateAfter}" : null;
|
||||
$lossy = $this->lossy ? "_l" : null;
|
||||
|
||||
$saveAs = $this->normalizeFileExtension();
|
||||
$saveAs = $saveAs ? "_$saveAs" : null;
|
||||
@@ -1374,14 +1439,14 @@ class CImage
|
||||
$subdir = ($subdir == '.') ? '_.' : $subdir;
|
||||
$subdir .= '_';
|
||||
}
|
||||
|
||||
|
||||
$file = $prefix . $subdir . $filename . $width . $height
|
||||
. $offset . $crop . $cropToFit . $fillToFit
|
||||
. $offset . $crop . $cropToFit . $fillToFit . $stretch
|
||||
. $crop_x . $crop_y . $upscale
|
||||
. $quality . $filters . $sharpen . $emboss . $blur . $palette
|
||||
. $optimize . $compress
|
||||
. $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor
|
||||
. $convolve . $copyStrat . $saveAs;
|
||||
. $convolve . $copyStrat . $lossy . $saveAs;
|
||||
|
||||
return $this->setTarget($file, $base);
|
||||
}
|
||||
@@ -1424,8 +1489,7 @@ class CImage
|
||||
|
||||
|
||||
/**
|
||||
* Load image from disk. Try to load image without verbose error message,
|
||||
* if fail, load again and display error messages.
|
||||
* Load image from disk.
|
||||
*
|
||||
* @param string $src of image.
|
||||
* @param string $dir as base directory where images are.
|
||||
@@ -1439,9 +1503,14 @@ class CImage
|
||||
$this->setSource($src, $dir);
|
||||
}
|
||||
|
||||
$this->loadImageDetails($this->pathToImage);
|
||||
$this->loadImageDetails();
|
||||
|
||||
$this->image = imagecreatefromstring(file_get_contents($this->pathToImage));
|
||||
if ($this->fileType === IMG_WEBP) {
|
||||
$this->image = imagecreatefromwebp($this->pathToImage);
|
||||
} else {
|
||||
$imageAsString = file_get_contents($this->pathToImage);
|
||||
$this->image = imagecreatefromstring($imageAsString);
|
||||
}
|
||||
if ($this->image === false) {
|
||||
throw new Exception("Could not load image.");
|
||||
}
|
||||
@@ -1520,7 +1589,6 @@ class CImage
|
||||
}
|
||||
|
||||
switch ($pngType) {
|
||||
|
||||
case self::PNG_GREYSCALE:
|
||||
$text = "PNG is type 0, Greyscale$transparent";
|
||||
break;
|
||||
@@ -1626,11 +1694,11 @@ class CImage
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setCopyResizeStrategy($strategy)
|
||||
{
|
||||
$this->copyStrategy = $strategy;
|
||||
return $this;
|
||||
}
|
||||
public function setCopyResizeStrategy($strategy)
|
||||
{
|
||||
$this->copyStrategy = $strategy;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1641,7 +1709,7 @@ class CImage
|
||||
*/
|
||||
public function imageCopyResampled($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h)
|
||||
{
|
||||
if($this->copyStrategy == self::RESIZE) {
|
||||
if ($this->copyStrategy == self::RESIZE) {
|
||||
$this->log("Copy by resize");
|
||||
imagecopyresized($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
|
||||
} else {
|
||||
@@ -1659,13 +1727,35 @@ class CImage
|
||||
*/
|
||||
public function resize()
|
||||
{
|
||||
$res = $this->imageResizer;
|
||||
|
||||
$this->log("### Starting to Resize()");
|
||||
$this->log("Upscale = '$this->upscale'");
|
||||
$this->log(" Upscale = '$this->upscale'");
|
||||
|
||||
$sw = $res->getSourceWidth();
|
||||
$sh = $res->getSourceHeight();
|
||||
$tw = $res->getTargetWidth();
|
||||
$th = $res->getTargetHeight();
|
||||
$cx = $res->getCropX();
|
||||
$cy = $res->getCropY();
|
||||
$cw = $res->getCropWidth();
|
||||
$ch = $res->getCropHeight();
|
||||
$dx = $res->getDestinationX();
|
||||
$dy = $res->getDestinationY();
|
||||
$dw = $res->getDestinationWidth();
|
||||
$dh = $res->getDestinationHeight();
|
||||
|
||||
$img = $this->CreateImageKeepTransparency($tw, $th);
|
||||
$this->imageCopyResampled($img, $this->image, $dx, $dy, $cx, $cy, $dw, $dh, $cw, $ch);
|
||||
$this->image = $img;
|
||||
$this->width = $tw;
|
||||
$this->height = $th;
|
||||
|
||||
return $this;
|
||||
|
||||
|
||||
// Only use a specified area of the image, $this->offset is defining the area to use
|
||||
if (isset($this->offset)) {
|
||||
|
||||
$this->log("Offset for area to use, cropping it width={$this->offset['width']}, height={$this->offset['height']}, start_x={$this->offset['left']}, start_y={$this->offset['top']}");
|
||||
$img = $this->CreateImageKeepTransparency($this->offset['width'], $this->offset['height']);
|
||||
imagecopy($img, $this->image, 0, 0, $this->offset['left'], $this->offset['top'], $this->offset['width'], $this->offset['height']);
|
||||
@@ -1675,7 +1765,6 @@ class CImage
|
||||
}
|
||||
|
||||
if ($this->crop) {
|
||||
|
||||
// Do as crop, take only part of image
|
||||
$this->log("Cropping area width={$this->crop['width']}, height={$this->crop['height']}, start_x={$this->crop['start_x']}, start_y={$this->crop['start_y']}");
|
||||
$img = $this->CreateImageKeepTransparency($this->crop['width'], $this->crop['height']);
|
||||
@@ -1692,44 +1781,67 @@ class CImage
|
||||
}
|
||||
|
||||
if ($this->cropToFit) {
|
||||
|
||||
// Resize by crop to fit
|
||||
$this->log("Resizing using strategy - Crop to fit");
|
||||
|
||||
if (!$this->upscale && ($this->width < $this->newWidth || $this->height < $this->newHeight)) {
|
||||
if (!$this->upscale
|
||||
&& ($this->width < $this->newWidth || $this->height < $this->newHeight)) {
|
||||
$this->log("Resizing - smaller image, do not upscale.");
|
||||
|
||||
$cropX = round(($this->cropWidth/2) - ($this->newWidth/2));
|
||||
$cropY = round(($this->cropHeight/2) - ($this->newHeight/2));
|
||||
|
||||
$posX = 0;
|
||||
$posY = 0;
|
||||
$cropX = 0;
|
||||
$cropY = 0;
|
||||
|
||||
if ($this->newWidth > $this->width) {
|
||||
$posX = round(($this->newWidth - $this->width) / 2);
|
||||
}
|
||||
if ($this->newWidth < $this->width) {
|
||||
$cropX = round(($this->width/2) - ($this->newWidth/2));
|
||||
}
|
||||
|
||||
if ($this->newHeight > $this->height) {
|
||||
$posY = round(($this->newHeight - $this->height) / 2);
|
||||
}
|
||||
if ($this->newHeight < $this->height) {
|
||||
$cropY = round(($this->height/2) - ($this->newHeight/2));
|
||||
}
|
||||
$this->log(" cwidth: $this->cropWidth");
|
||||
$this->log(" cheight: $this->cropHeight");
|
||||
$this->log(" nwidth: $this->newWidth");
|
||||
$this->log(" nheight: $this->newHeight");
|
||||
$this->log(" width: $this->width");
|
||||
$this->log(" height: $this->height");
|
||||
$this->log(" posX: $posX");
|
||||
$this->log(" posY: $posY");
|
||||
$this->log(" cropX: $cropX");
|
||||
$this->log(" cropY: $cropY");
|
||||
|
||||
$imageResized = $this->CreateImageKeepTransparency($this->newWidth, $this->newHeight);
|
||||
imagecopy($imageResized, $this->image, $posX, $posY, $cropX, $cropY, $this->newWidth, $this->newHeight);
|
||||
imagecopy($imageResized, $this->image, $posX, $posY, $cropX, $cropY, $this->width, $this->height);
|
||||
} else {
|
||||
$cropX = round(($this->cropWidth/2) - ($this->newWidth/2));
|
||||
$cropY = round(($this->cropHeight/2) - ($this->newHeight/2));
|
||||
$imgPreCrop = $this->CreateImageKeepTransparency($this->cropWidth, $this->cropHeight);
|
||||
$cropX = $imgres->getCropX();
|
||||
$cropY = $imgres->getCropY();
|
||||
$cropWidth = $imgres->getCropWidth();
|
||||
$cropHeight = $imgres->getCropHeight();
|
||||
$this->log(" Crop from $cropX x $cropY by $cropWidth x $cropHeight.");
|
||||
|
||||
|
||||
//$cropX = round(($this->cropWidth/2) - ($this->newWidth/2));
|
||||
//$cropY = round(($this->cropHeight/2) - ($this->newHeight/2));
|
||||
|
||||
//$imgPreCrop = $this->CreateImageKeepTransparency($this->cropWidth, $this->cropHeight);
|
||||
$imgPreCrop = $this->CreateImageKeepTransparency($cropWidth, $cropHeight);
|
||||
$imageResized = $this->CreateImageKeepTransparency($this->newWidth, $this->newHeight);
|
||||
$this->imageCopyResampled($imgPreCrop, $this->image, 0, 0, 0, 0, $this->cropWidth, $this->cropHeight, $this->width, $this->height);
|
||||
// $this->imageCopyResampled($imgPreCrop, $this->image, 0, 0, 0, 0, $this->cropWidth, $this->cropHeight, $this->width, $this->height);
|
||||
$this->imageCopyResampled($imgPreCrop, $this->image, 0, 0, 0, 0, $cropWidth, $cropHeight, $this->width, $this->height);
|
||||
imagecopy($imageResized, $imgPreCrop, 0, 0, $cropX, $cropY, $this->newWidth, $this->newHeight);
|
||||
}
|
||||
|
||||
$this->image = $imageResized;
|
||||
$this->width = $this->newWidth;
|
||||
$this->height = $this->newHeight;
|
||||
|
||||
} elseif ($this->fillToFit) {
|
||||
|
||||
// Resize by fill to fit
|
||||
$this->log("Resizing using strategy - Fill to fit");
|
||||
|
||||
@@ -1747,15 +1859,13 @@ class CImage
|
||||
}
|
||||
|
||||
if (!$this->upscale
|
||||
&& ($this->width < $this->newWidth || $this->height < $this->newHeight)
|
||||
&& ($this->width < $this->newWidth && $this->height < $this->newHeight)
|
||||
) {
|
||||
|
||||
$this->log("Resizing - smaller image, do not upscale.");
|
||||
$posX = round(($this->fillWidth - $this->width) / 2);
|
||||
$posY = round(($this->fillHeight - $this->height) / 2);
|
||||
$posX = round(($this->newWidth - $this->width) / 2);
|
||||
$posY = round(($this->newHeight - $this->height) / 2);
|
||||
$imageResized = $this->CreateImageKeepTransparency($this->newWidth, $this->newHeight);
|
||||
imagecopy($imageResized, $this->image, $posX, $posY, 0, 0, $this->fillWidth, $this->fillHeight);
|
||||
|
||||
imagecopy($imageResized, $this->image, $posX, $posY, 0, 0, $this->width, $this->height);
|
||||
} else {
|
||||
$imgPreFill = $this->CreateImageKeepTransparency($this->fillWidth, $this->fillHeight);
|
||||
$imageResized = $this->CreateImageKeepTransparency($this->newWidth, $this->newHeight);
|
||||
@@ -1766,9 +1876,7 @@ class CImage
|
||||
$this->image = $imageResized;
|
||||
$this->width = $this->newWidth;
|
||||
$this->height = $this->newHeight;
|
||||
|
||||
} elseif (!($this->newWidth == $this->width && $this->newHeight == $this->height)) {
|
||||
|
||||
// Resize it
|
||||
$this->log("Resizing, new height and/or width");
|
||||
|
||||
@@ -1796,9 +1904,8 @@ class CImage
|
||||
$cropX = round(($this->width - $this->newWidth) / 2);
|
||||
}
|
||||
|
||||
//$this->log("posX=$posX, posY=$posY, cropX=$cropX, cropY=$cropY.");
|
||||
$imageResized = $this->CreateImageKeepTransparency($this->newWidth, $this->newHeight);
|
||||
imagecopy($imageResized, $this->image, $posX, $posY, $cropX, $cropY, $this->newWidth, $this->newHeight);
|
||||
imagecopy($imageResized, $this->image, $posX, $posY, $cropX, $cropY, $this->width, $this->height);
|
||||
$this->image = $imageResized;
|
||||
$this->width = $this->newWidth;
|
||||
$this->height = $this->newHeight;
|
||||
@@ -1834,12 +1941,10 @@ class CImage
|
||||
|
||||
// Apply filters
|
||||
if (isset($this->filters) && is_array($this->filters)) {
|
||||
|
||||
foreach ($this->filters as $filter) {
|
||||
$this->log("Applying filter {$filter['type']}.");
|
||||
|
||||
switch ($filter['argc']) {
|
||||
|
||||
case 0:
|
||||
imagefilter($this->image, $filter['type']);
|
||||
break;
|
||||
@@ -2184,7 +2289,6 @@ class CImage
|
||||
$img = isset($img) ? $img : $this->image;
|
||||
|
||||
if ($this->bgColorDefault) {
|
||||
|
||||
$red = $this->bgColorDefault['red'];
|
||||
$green = $this->bgColorDefault['green'];
|
||||
$blue = $this->bgColorDefault['blue'];
|
||||
@@ -2197,7 +2301,6 @@ class CImage
|
||||
}
|
||||
|
||||
return $color;
|
||||
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
@@ -2225,16 +2328,13 @@ class CImage
|
||||
: -1;
|
||||
|
||||
if ($index != -1) {
|
||||
|
||||
imagealphablending($img, true);
|
||||
$transparent = imagecolorsforindex($this->image, $index);
|
||||
$color = imagecolorallocatealpha($img, $transparent['red'], $transparent['green'], $transparent['blue'], $transparent['alpha']);
|
||||
imagefill($img, 0, 0, $color);
|
||||
$index = imagecolortransparent($img, $color);
|
||||
$this->Log("Detected transparent color = " . implode(", ", $transparent) . " at index = $index");
|
||||
|
||||
} elseif ($this->bgColorDefault) {
|
||||
|
||||
$color = $this->getBackgroundColor($img);
|
||||
imagefill($img, 0, 0, $color);
|
||||
$this->Log("Filling image with background color.");
|
||||
@@ -2260,6 +2360,14 @@ class CImage
|
||||
$this->jpegOptimizeCmd = null;
|
||||
}
|
||||
|
||||
if (array_key_exists("png_lossy", $options)
|
||||
&& $options['png_lossy'] !== false) {
|
||||
$this->pngLossy = $options['png_lossy'];
|
||||
$this->pngLossyCmd = $options['png_lossy_cmd'];
|
||||
} else {
|
||||
$this->pngLossyCmd = null;
|
||||
}
|
||||
|
||||
if (isset($options['png_filter']) && $options['png_filter']) {
|
||||
$this->pngFilterCmd = $options['png_filter_cmd'];
|
||||
} else {
|
||||
@@ -2287,9 +2395,11 @@ class CImage
|
||||
// switch on mimetype
|
||||
if (isset($this->extension)) {
|
||||
return strtolower($this->extension);
|
||||
} else {
|
||||
return substr(image_type_to_extension($this->fileType), 1);
|
||||
} elseif ($this->fileType === IMG_WEBP) {
|
||||
return "webp";
|
||||
}
|
||||
|
||||
return substr(image_type_to_extension($this->fileType), 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -2319,8 +2429,7 @@ class CImage
|
||||
|
||||
$type = $this->getTargetImageExtension();
|
||||
$this->Log("Saving image as " . $type);
|
||||
switch($type) {
|
||||
|
||||
switch ($type) {
|
||||
case 'jpeg':
|
||||
case 'jpg':
|
||||
$this->Log("Saving image as JPEG to cache using quality = {$this->quality}.");
|
||||
@@ -2345,6 +2454,11 @@ class CImage
|
||||
imagegif($this->image, $this->cacheFileName);
|
||||
break;
|
||||
|
||||
case 'webp':
|
||||
$this->Log("Saving image as WEBP to cache using quality = {$this->quality}.");
|
||||
imagewebp($this->image, $this->cacheFileName, $this->quality);
|
||||
break;
|
||||
|
||||
case 'png':
|
||||
default:
|
||||
$this->Log("Saving image as PNG to cache using compression = {$this->compress}.");
|
||||
@@ -2354,6 +2468,24 @@ class CImage
|
||||
imagesavealpha($this->image, true);
|
||||
imagepng($this->image, $this->cacheFileName, $this->compress);
|
||||
|
||||
// Use external program to process lossy PNG, if defined
|
||||
$lossyEnabled = $this->pngLossy === true;
|
||||
$lossySoftEnabled = $this->pngLossy === null;
|
||||
$lossyActiveEnabled = $this->lossy === true;
|
||||
if ($lossyEnabled || ($lossySoftEnabled && $lossyActiveEnabled)) {
|
||||
if ($this->verbose) {
|
||||
clearstatcache();
|
||||
$this->log("Lossy enabled: $lossyEnabled");
|
||||
$this->log("Lossy soft enabled: $lossySoftEnabled");
|
||||
$this->Log("Filesize before lossy optimize: " . filesize($this->cacheFileName) . " bytes.");
|
||||
}
|
||||
$res = array();
|
||||
$cmd = $this->pngLossyCmd . " $this->cacheFileName $this->cacheFileName";
|
||||
exec($cmd, $res);
|
||||
$this->Log($cmd);
|
||||
$this->Log($res);
|
||||
}
|
||||
|
||||
// Use external program to filter PNG, if defined
|
||||
if ($this->pngFilterCmd) {
|
||||
if ($this->verbose) {
|
||||
@@ -2417,7 +2549,7 @@ class CImage
|
||||
$this->log("# Converting image to sRGB colorspace.");
|
||||
}
|
||||
|
||||
if (!class_exists("Imagick")) {
|
||||
if (!class_exists("\Imagick")) {
|
||||
$this->log(" Ignoring since Imagemagick is not installed.");
|
||||
return false;
|
||||
}
|
||||
@@ -2438,10 +2570,10 @@ class CImage
|
||||
}
|
||||
}
|
||||
|
||||
// Only covert if cachedir is writable
|
||||
// Only convert if cachedir is writable
|
||||
if (is_writable($this->saveFolder)) {
|
||||
// Load file and check if conversion is needed
|
||||
$image = new Imagick($this->pathToImage);
|
||||
$image = new \Imagick($this->pathToImage);
|
||||
$colorspace = $image->getImageColorspace();
|
||||
$this->log(" Current colorspace: " . $colorspace);
|
||||
|
||||
@@ -2449,13 +2581,13 @@ class CImage
|
||||
$hasICCProfile = (array_search('icc', $profiles) !== false);
|
||||
$this->log(" Has ICC color profile: " . ($hasICCProfile ? "YES" : "NO"));
|
||||
|
||||
if ($colorspace != Imagick::COLORSPACE_SRGB || $hasICCProfile) {
|
||||
if ($colorspace != \Imagick::COLORSPACE_SRGB || $hasICCProfile) {
|
||||
$this->log(" Converting to sRGB.");
|
||||
|
||||
$sRGBicc = file_get_contents($iccFile);
|
||||
$image->profileImage('icc', $sRGBicc);
|
||||
|
||||
$image->transformImageColorspace(Imagick::COLORSPACE_SRGB);
|
||||
$image->transformImageColorspace(\Imagick::COLORSPACE_SRGB);
|
||||
$image->writeImage($this->cacheFileName);
|
||||
return $this->cacheFileName;
|
||||
}
|
||||
@@ -2499,7 +2631,7 @@ class CImage
|
||||
|
||||
|
||||
/**
|
||||
* Add HTTP header for putputting together with image.
|
||||
* Add HTTP header for output together with image.
|
||||
*
|
||||
* @param string $type the header type such as "Cache-Control"
|
||||
* @param string $value the value to use
|
||||
@@ -2533,6 +2665,7 @@ class CImage
|
||||
$format = $this->outputFormat;
|
||||
}
|
||||
|
||||
$this->log("### Output");
|
||||
$this->log("Output format is: $format");
|
||||
|
||||
if (!$this->verbose && $format == 'json') {
|
||||
@@ -2550,18 +2683,24 @@ class CImage
|
||||
// Get image modification time
|
||||
clearstatcache();
|
||||
$lastModified = filemtime($file);
|
||||
$gmdate = gmdate("D, d M Y H:i:s", $lastModified);
|
||||
$lastModifiedFormat = "D, d M Y H:i:s";
|
||||
$gmdate = gmdate($lastModifiedFormat, $lastModified);
|
||||
|
||||
if (!$this->verbose) {
|
||||
header('Last-Modified: ' . $gmdate . " GMT");
|
||||
$header = "Last-Modified: $gmdate GMT";
|
||||
header($header);
|
||||
$this->fastTrackCache->addHeader($header);
|
||||
$this->fastTrackCache->setLastModified($lastModified);
|
||||
}
|
||||
|
||||
foreach($this->HTTPHeader as $key => $val) {
|
||||
header("$key: $val");
|
||||
foreach ($this->HTTPHeader as $key => $val) {
|
||||
$header = "$key: $val";
|
||||
header($header);
|
||||
$this->fastTrackCache->addHeader($header);
|
||||
}
|
||||
|
||||
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $lastModified) {
|
||||
|
||||
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])
|
||||
&& strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $lastModified) {
|
||||
if ($this->verbose) {
|
||||
$this->log("304 not modified");
|
||||
$this->verboseOutput();
|
||||
@@ -2569,13 +2708,12 @@ class CImage
|
||||
}
|
||||
|
||||
header("HTTP/1.0 304 Not Modified");
|
||||
|
||||
if (CIMAGE_DEBUG) {
|
||||
trace(__CLASS__ . " 304");
|
||||
}
|
||||
} else {
|
||||
|
||||
// Get details on image
|
||||
$info = getimagesize($file);
|
||||
!empty($info) or $this->raiseError("The file doesn't seem to be an image.");
|
||||
$mime = $info['mime'];
|
||||
$this->loadImageDetails($file);
|
||||
$mime = $this->getMimeType();
|
||||
$size = filesize($file);
|
||||
|
||||
if ($this->verbose) {
|
||||
@@ -2589,8 +2727,19 @@ class CImage
|
||||
}
|
||||
}
|
||||
|
||||
header("Content-type: $mime");
|
||||
header("Content-length: $size");
|
||||
$header = "Content-type: $mime";
|
||||
header($header);
|
||||
$this->fastTrackCache->addHeaderOnOutput($header);
|
||||
|
||||
$header = "Content-length: $size";
|
||||
header($header);
|
||||
$this->fastTrackCache->addHeaderOnOutput($header);
|
||||
|
||||
$this->fastTrackCache->setSource($file);
|
||||
$this->fastTrackCache->writeToCache();
|
||||
if (CIMAGE_DEBUG) {
|
||||
trace(__CLASS__ . " 200");
|
||||
}
|
||||
readfile($file);
|
||||
}
|
||||
|
||||
@@ -2625,7 +2774,7 @@ class CImage
|
||||
$this->load($file);
|
||||
|
||||
$details['filename'] = basename($file);
|
||||
$details['mimeType'] = image_type_to_mime_type($this->fileType);
|
||||
$details['mimeType'] = $this->getMimeType($this->fileType);
|
||||
$details['width'] = $this->width;
|
||||
$details['height'] = $this->height;
|
||||
$details['aspectRatio'] = round($this->width / $this->height, 3);
|
||||
@@ -2727,6 +2876,7 @@ class CImage
|
||||
private function verboseOutput()
|
||||
{
|
||||
$log = null;
|
||||
$this->log("### Summary of verbose log");
|
||||
$this->log("As JSON: \n" . $this->json());
|
||||
$this->log("Memory peak: " . round(memory_get_peak_usage() /1024/1024) . "M");
|
||||
$this->log("Memory limit: " . ini_get('memory_limit'));
|
838
src/CImage/CImageResizer.php
Normal file
@@ -0,0 +1,838 @@
|
||||
<?php
|
||||
|
||||
namespace Mos\CImage;
|
||||
|
||||
/**
|
||||
* Resize and crop images.
|
||||
*
|
||||
* @author Mikael Roos mos@dbwebb.se
|
||||
* @example http://dbwebb.se/opensource/cimage
|
||||
* @link https://github.com/mosbth/cimage
|
||||
*/
|
||||
class CImageResizer
|
||||
{
|
||||
/**
|
||||
* Log function.
|
||||
*/
|
||||
private $log;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Source image dimensions, calculated from loaded image.
|
||||
*/
|
||||
private $srcWidth;
|
||||
private $srcHeight;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set as expected target image/canvas dimensions.
|
||||
*/
|
||||
private $targetWidth;
|
||||
private $targetHeight;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Where should the image go on the canvas.
|
||||
*/
|
||||
private $destinationX;
|
||||
private $destinationY;
|
||||
private $destinationWidth;
|
||||
private $destinationHeight;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Which parts to crop from the source.
|
||||
*/
|
||||
private $cropX;
|
||||
private $cropY;
|
||||
private $cropWidth;
|
||||
private $cropHeight;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Change target height & width when different dpr, dpr 2 means double
|
||||
* image dimensions.
|
||||
*/
|
||||
private $dpr = null;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set aspect ratio for the target image.
|
||||
*/
|
||||
private $aspectRatio;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Array with details on how to crop.
|
||||
* Array contains xxxxxx
|
||||
*/
|
||||
public $crop;
|
||||
public $cropOrig; // Save original value?
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Area to use for target image, crop out parts not in area.
|
||||
* Array with top, right, bottom, left percentage values to crop out.
|
||||
*/
|
||||
private $area;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Pixel offset in source image to decide which part of image is used.
|
||||
* Array with top, right, bottom, left percentage values to crop out.
|
||||
*/
|
||||
private $offset;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Resize strategy, image should keep its original ratio.
|
||||
*/
|
||||
const KEEP_RATIO = 1;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Resize strategy, image should crop and fill area.
|
||||
*/
|
||||
const CROP_TO_FIT = 2;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Resize strategy, image should fit in area and fill remains.
|
||||
*/
|
||||
const FILL_TO_FIT = 3;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Resize strategy, image should stretch to fit in area.
|
||||
*/
|
||||
const STRETCH = 4;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The currently selected resize strategy.
|
||||
*/
|
||||
private $resizeStrategy = self::KEEP_RATIO;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Allow upscale of smaller images by default, set to false to disallow.
|
||||
*/
|
||||
private $upscale = true;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructor, set log function to use for verbose logging or null
|
||||
* to disable logging.
|
||||
*
|
||||
* @param callable $log function to call for logging.
|
||||
*/
|
||||
public function __construct($log = null)
|
||||
{
|
||||
$this->log = $log;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Log string using logger.
|
||||
*
|
||||
* @param string $str to log.
|
||||
*/
|
||||
public function log($str)
|
||||
{
|
||||
if ($this->log) {
|
||||
call_user_func($this->log, $str);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set source dimensions.
|
||||
*
|
||||
* @param integer $width of source image.
|
||||
* @param integer $height of source image.
|
||||
*
|
||||
* @throws Exception
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setSource($width, $height)
|
||||
{
|
||||
$this->srcWidth = $width;
|
||||
$this->srcHeight = $height;
|
||||
$this->log("# Source image dimension: {$this->srcWidth}x{$this->srcHeight}.");
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get resize strategy as string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getResizeStrategyAsString()
|
||||
{
|
||||
switch ($this->resizeStrategy) {
|
||||
case self::KEEP_RATIO:
|
||||
return "KEEP_RATIO";
|
||||
break;
|
||||
|
||||
case self::CROP_TO_FIT:
|
||||
return "CROP_TO_FIT";
|
||||
break;
|
||||
|
||||
case self::FILL_TO_FIT:
|
||||
return "FILL_TO_FIT";
|
||||
break;
|
||||
|
||||
case self::STRETCH:
|
||||
return "STRETCH";
|
||||
break;
|
||||
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set resize strategy as KEEP_RATIO, CROP_TO_FIT or FILL_TO_FIT.
|
||||
*
|
||||
* @param integer $strategy
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setResizeStrategy($strategy)
|
||||
{
|
||||
$this->resizeStrategy = $strategy;
|
||||
$this->log("# Resize strategy is " . $this->getResizeStrategyAsString());
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Allow or disallow upscale smaller images.
|
||||
*
|
||||
* @param boolean $upscale
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function allowUpscale($upscale)
|
||||
{
|
||||
$this->upscale = $upscale;
|
||||
$this->log("# Allow upscale is $this->upscale.");
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Check if a value is upscaled or not by compare $current to $orig,
|
||||
* if $current is larger than $orig then check if upscaled is allowed.
|
||||
*
|
||||
* @param float &$current value to check and change.
|
||||
* @param float $orig value to check against.
|
||||
*
|
||||
* @return boolean true if upscaled changed values, else false.
|
||||
*/
|
||||
public function respectUpscale(&$current, $orig)
|
||||
{
|
||||
if (!$this->upscale && $current > $orig) {
|
||||
$this->log("# Disallowed upscale to $current ($orig)");
|
||||
$current = $orig;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set base for requested width and height.
|
||||
*
|
||||
* @param numeric|null $width as requested target width
|
||||
* @param numeric|null $height as requested target height
|
||||
*
|
||||
* @throws Exception
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setBaseWidthHeight($width = null, $height = null)
|
||||
{
|
||||
$this->log("# Set base for width and height.");
|
||||
|
||||
$this->targetWidth = $width;
|
||||
$this->targetHeight = $height;
|
||||
|
||||
// Width specified as %
|
||||
if ($this->targetWidth[strlen($this->targetWidth)-1] == '%') {
|
||||
$this->targetWidth = $this->srcWidth * substr($this->targetWidth, 0, -1) / 100;
|
||||
$this->log(" Setting new width based on $width to {$this->targetWidth}.");
|
||||
}
|
||||
|
||||
// Height specified as %
|
||||
if ($this->targetHeight[strlen($this->targetHeight)-1] == '%') {
|
||||
$this->targetHeight = $this->srcHeight * substr($this->targetHeight, 0, -1) / 100;
|
||||
$this->log(" Setting new height based on $height to {$this->targetHeight}.");
|
||||
}
|
||||
|
||||
if (!(is_null($this->targetWidth) || is_numeric($this->targetWidth))) {
|
||||
throw new Exception('Width not numeric');
|
||||
}
|
||||
|
||||
if (!(is_null($this->targetHeight) || is_numeric($this->targetHeight))) {
|
||||
throw new Exception('Height not numeric');
|
||||
}
|
||||
|
||||
$this->log(" Requested target dimension as: {$this->targetWidth}x{$this->targetHeight}.");
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set base for requested aspect ratio.
|
||||
*
|
||||
* @param float|null $aspectRatio as requested aspect ratio
|
||||
*
|
||||
* @throws Exception
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setBaseAspecRatio($aspectRatio = null)
|
||||
{
|
||||
$this->log("# Set base for aspect ratio.");
|
||||
|
||||
$this->aspectRatio = $aspectRatio;
|
||||
|
||||
if (!(is_null($this->aspectRatio) || is_numeric($this->aspectRatio))) {
|
||||
throw new Exception("Aspect ratio out of range");
|
||||
}
|
||||
|
||||
$this->log(" Requested aspectRatio={$this->aspectRatio}.");
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set base for requested device pixel ratio.
|
||||
*
|
||||
* @param float $dpr as requested density pixel rate
|
||||
*
|
||||
* @throws Exception
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setBaseDevicePixelRate($dpr = null)
|
||||
{
|
||||
$this->log("# Set base for device pixel rate.");
|
||||
|
||||
$this->dpr = $dpr;
|
||||
|
||||
if (!(is_null($dpr) || (is_numeric($this->dpr) && $this->dpr > 0))) {
|
||||
throw new Exception("Device pixel rate out of range");
|
||||
}
|
||||
|
||||
$this->log(" Requested dpr={$this->dpr}.");
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Calculate target width and height by considering the selected
|
||||
* aspect ratio.
|
||||
*
|
||||
* @throws Exception
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function prepareByConsiderAspectRatio()
|
||||
{
|
||||
$this->log(" Prepare by aspect ratio {$this->aspectRatio}.");
|
||||
|
||||
if (is_null($this->aspectRatio)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
// Both null, use source as base for target
|
||||
if (is_null($this->targetWidth) && is_null($this->targetHeight)) {
|
||||
$this->targetWidth = ($this->aspectRatio >= 1)
|
||||
? $this->srcWidth
|
||||
: null;
|
||||
|
||||
$this->targetHeight = ($this->aspectRatio >= 1)
|
||||
? null
|
||||
: $this->srcHeight;
|
||||
|
||||
$this->log(" Using source as base {$this->targetWidth}x{$this->targetHeight}");
|
||||
}
|
||||
|
||||
// Both or either set, calculate the other
|
||||
if (isset($this->targetWidth) && isset($this->targetHeight)) {
|
||||
$this->targetWidth = ($this->aspectRatio >= 1)
|
||||
? $this->targetWidth
|
||||
: $this->targetHeight * $this->aspectRatio;
|
||||
|
||||
$this->targetHeight = ($this->aspectRatio >= 1)
|
||||
? $this->targetWidth / $this->aspectRatio
|
||||
: $this->targetHeight;
|
||||
|
||||
$this->log(" New target width height {$this->targetWidth}x{$this->targetHeight}");
|
||||
} elseif (isset($this->targetWidth)) {
|
||||
$this->targetHeight = $this->targetWidth / $this->aspectRatio;
|
||||
$this->log(" New target height x{$this->targetHeight}");
|
||||
} elseif (isset($this->targetHeight)) {
|
||||
$this->targetWidth = $this->targetHeight * $this->aspectRatio;
|
||||
$this->log(" New target width {$this->targetWidth}x");
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Calculate target width and height by considering the selected
|
||||
* dpr.
|
||||
*
|
||||
* @throws Exception
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function prepareByConsiderDpr()
|
||||
{
|
||||
$this->log(" Prepare by dpr={$this->dpr}.");
|
||||
|
||||
if (is_null($this->dpr)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
// If both not set, use source as base
|
||||
if (is_null($this->targetWidth) && is_null($this->targetHeight)) {
|
||||
$this->targetWidth = $this->srcWidth;
|
||||
$this->targetHeight = $this->srcHeight;
|
||||
}
|
||||
|
||||
if (isset($this->targetWidth)) {
|
||||
$this->targetWidth = $this->targetWidth * $this->dpr;
|
||||
$this->log(" Update target width to {$this->targetWidth}.");
|
||||
}
|
||||
|
||||
if (isset($this->targetHeight)) {
|
||||
$this->targetHeight = $this->targetHeight * $this->dpr;
|
||||
$this->log(" Update target height to {$this->targetHeight}.");
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Calculate target width and height and do sanity checks on constraints.
|
||||
* After this method the $targetWidth and $targetHeight will have
|
||||
* the expected dimensions on the target image.
|
||||
*
|
||||
* @throws Exception
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function prepareTargetDimensions()
|
||||
{
|
||||
$this->log("# Prepare target dimension (before): {$this->targetWidth}x{$this->targetHeight}.");
|
||||
|
||||
$this->prepareByConsiderAspectRatio()
|
||||
->prepareByConsiderDpr();
|
||||
|
||||
$this->log(" Prepare target dimension (after): {$this->targetWidth}x{$this->targetHeight}.");
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Calculate new width and height of image.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function calculateTargetWidthAndHeight()
|
||||
{
|
||||
$this->log("# Calculate new width and height.");
|
||||
$this->log(" Source size {$this->srcWidth}x{$this->srcHeight}.");
|
||||
$this->log(" Target dimension (before) {$this->targetWidth}x{$this->targetHeight}.");
|
||||
|
||||
// Set default values to crop area to be whole source image
|
||||
$sw = $this->srcWidth;
|
||||
$sh = $this->srcHeight;
|
||||
$ar = $sw / $sh;
|
||||
$tw = $this->targetWidth;
|
||||
$th = $this->targetHeight;
|
||||
$dx = 0;
|
||||
$dy = 0;
|
||||
$dw = null;
|
||||
$dh = null;
|
||||
$cx = 0;
|
||||
$cy = 0;
|
||||
$cw = $sw;
|
||||
$ch = $sh;
|
||||
$rs = $this->resizeStrategy;
|
||||
$both = isset($tw) && isset($th);
|
||||
$ratio = $both ? $tw / $th : null;
|
||||
|
||||
if (is_null($tw) && is_null($th)) {
|
||||
// No tw/th use sw/sh
|
||||
$tw = $sw;
|
||||
$th = $sh;
|
||||
$this->log(" New tw x th {$tw}x{$th}");
|
||||
} elseif (isset($tw) && is_null($th)) {
|
||||
// Keep aspect ratio, make th based on tw
|
||||
$this->respectUpscale($tw, $sw);
|
||||
$th = $tw / $ar;
|
||||
$this->log(" New th x{$th}");
|
||||
} elseif (is_null($tw) && isset($th)) {
|
||||
// Keep aspect ratio, make tw based on th
|
||||
$this->respectUpscale($th, $sh);
|
||||
$tw = $th * $ar;
|
||||
$this->log(" New tw {$tw}x");
|
||||
} elseif ($rs === CImageResizer::KEEP_RATIO && $both) {
|
||||
// Keep aspect ratio, make fit in box not larger than tw/th
|
||||
$this->log(" Keep ratio, ratio target=$ratio, source=$ar");
|
||||
|
||||
if ($ratio > $ar) {
|
||||
$this->respectUpscale($th, $sh);
|
||||
$tw = $th * $ar;
|
||||
$this->log(" New tw {$tw}x");
|
||||
} elseif ($ratio < $ar) {
|
||||
$this->respectUpscale($tw, $sw);
|
||||
$th = $tw / $ar;
|
||||
$this->log(" New th x{$th}");
|
||||
} else {
|
||||
$this->respectUpscale($tw, $sw);
|
||||
$this->respectUpscale($th, $sh);
|
||||
}
|
||||
} elseif ($rs === CImageResizer::STRETCH && $both) {
|
||||
// Stretch to fit, leave as is
|
||||
$this->log(" Stretch");
|
||||
|
||||
// respectUpscale
|
||||
$dw = $tw;
|
||||
$dh = $th;
|
||||
$this->respectUpscale($dw, $sw);
|
||||
$this->respectUpscale($dh, $sh);
|
||||
$dx = ($tw - $dw) / 2;
|
||||
$dy = ($th - $dh) / 2;
|
||||
|
||||
$this->log(" Destination area dx=$dx, dy=$dy, dw=$dw, dh=$dh");
|
||||
} elseif ($rs === CImageResizer::CROP_TO_FIT && $both) {
|
||||
// Crop to fit image in box
|
||||
$this->log(" Crop to fit, ratio target=$ratio, source=$ar");
|
||||
|
||||
// Respect upscale
|
||||
$dw = $tw;
|
||||
$dh = $th;
|
||||
$this->respectUpscale($dw, $sw);
|
||||
$this->respectUpscale($dh, $sh);
|
||||
$dx = ($tw - $dw) / 2;
|
||||
$dy = ($th - $dh) / 2;
|
||||
|
||||
// Manage landscape/portrait
|
||||
if ($ratio > $ar) {
|
||||
$ch = $sw / $ratio;
|
||||
$cy = ($sh - $ch) / 2;
|
||||
$this->log(" Crop by cy=$cy ch=$ch");
|
||||
} elseif ($ratio < $ar) {
|
||||
$cw = $sh * $ratio;
|
||||
$cx = ($sw - $cw) / 2;
|
||||
$this->log(" Crop by cx=$cx cw=$cw");
|
||||
}
|
||||
|
||||
// Update crop when no upscale
|
||||
if (!$this->upscale && $dx) {
|
||||
$cy = $th < $sh ? ($sh - $th) / 2 : 0;
|
||||
$ch = $dh;
|
||||
}
|
||||
if (!$this->upscale && $dy) {
|
||||
$cx = $tw < $sw ? ($sw - $tw) / 2 : 0;
|
||||
$cw = $dw;
|
||||
}
|
||||
|
||||
$this->log(" Parts cx=$cx, cy=$cy, cw=$cw, ch=$ch");
|
||||
$this->log(" Destination area dx=$dx, dy=$dy, dw=$dw, dh=$dh");
|
||||
} elseif ($rs === CImageResizer::FILL_TO_FIT && $both) {
|
||||
// Fill to fit image in box
|
||||
$this->log(" Fill to fit, ratio target=$ratio, source=$ar");
|
||||
$dw = $tw;
|
||||
$dh = $th;
|
||||
|
||||
// Manage landscape/portrait
|
||||
if ($ratio > $ar) {
|
||||
$dw = $th * $ar;
|
||||
$dh = $th;
|
||||
} elseif ($ratio < $ar) {
|
||||
$dw = $tw;
|
||||
$dh = $tw / $ar;
|
||||
}
|
||||
|
||||
$this->respectUpscale($dw, $sw);
|
||||
$this->respectUpscale($dh, $sh);
|
||||
$dx = ($tw - $dw) / 2;
|
||||
$dy = ($th - $dh) / 2;
|
||||
|
||||
$this->log(" Destination area dx=$dx, dy=$dy, dw=$dw, dh=$dh");
|
||||
}
|
||||
|
||||
// All done, sum it up
|
||||
$dw = is_null($dw) ? $tw : $dw;
|
||||
$dh = is_null($dh) ? $th : $dh;
|
||||
|
||||
$this->targetWidth = round($tw);
|
||||
$this->targetHeight = round($th);
|
||||
$this->destinationX = round($dx);
|
||||
$this->destinationY = round($dy);
|
||||
$this->destinationWidth = round($dw);
|
||||
$this->destinationHeight = round($dh);
|
||||
$this->cropX = round($cx);
|
||||
$this->cropY = round($cy);
|
||||
$this->cropWidth = round($cw);
|
||||
$this->cropHeight = round($ch);
|
||||
|
||||
$str = <<<EOD
|
||||
Target dimension (after) {$this->targetWidth}x{$this->targetHeight}.
|
||||
Crop area {$this->cropX}x{$this->cropY} by {$this->cropWidth}x{$this->cropHeight}.
|
||||
Destination area {$this->destinationX}x{$this->destinationY} by {$this->destinationWidth}x{$this->destinationHeight}.
|
||||
EOD;
|
||||
$this->log($str);
|
||||
|
||||
/*
|
||||
|
||||
// Check if there is an area to crop off
|
||||
if (isset($this->area)) {
|
||||
$this->offset['top'] = round($this->area['top'] / 100 * $this->srcHeight);
|
||||
$this->offset['right'] = round($this->area['right'] / 100 * $this->srcWidth);
|
||||
$this->offset['bottom'] = round($this->area['bottom'] / 100 * $this->srcHeight);
|
||||
$this->offset['left'] = round($this->area['left'] / 100 * $this->srcWidth);
|
||||
$this->offset['width'] = $this->srcWidth - $this->offset['left'] - $this->offset['right'];
|
||||
$this->offset['height'] = $this->srcHeight - $this->offset['top'] - $this->offset['bottom'];
|
||||
$this->srcWidth = $this->offset['width'];
|
||||
$this->srcHeight = $this->offset['height'];
|
||||
$this->log("The offset for the area to use is top {$this->area['top']}%, right {$this->area['right']}%, bottom {$this->area['bottom']}%, left {$this->area['left']}%.");
|
||||
$this->log("The offset for the area to use is top {$this->offset['top']}px, right {$this->offset['right']}px, bottom {$this->offset['bottom']}px, left {$this->offset['left']}px, width {$this->offset['width']}px, height {$this->offset['height']}px.");
|
||||
}
|
||||
|
||||
|
||||
// Check if crop is set
|
||||
if ($this->crop) {
|
||||
$width = $this->crop['width'] = $this->crop['width'] <= 0 ? $this->srcWidth + $this->crop['width'] : $this->crop['width'];
|
||||
$height = $this->crop['height'] = $this->crop['height'] <= 0 ? $this->srcHeight + $this->crop['height'] : $this->crop['height'];
|
||||
|
||||
if ($this->crop['start_x'] == 'left') {
|
||||
$this->crop['start_x'] = 0;
|
||||
} elseif ($this->crop['start_x'] == 'right') {
|
||||
$this->crop['start_x'] = $this->srcWidth - $width;
|
||||
} elseif ($this->crop['start_x'] == 'center') {
|
||||
$this->crop['start_x'] = round($this->srcWidth / 2) - round($width / 2);
|
||||
}
|
||||
|
||||
if ($this->crop['start_y'] == 'top') {
|
||||
$this->crop['start_y'] = 0;
|
||||
} elseif ($this->crop['start_y'] == 'bottom') {
|
||||
$this->crop['start_y'] = $this->srcHeight - $height;
|
||||
} elseif ($this->crop['start_y'] == 'center') {
|
||||
$this->crop['start_y'] = round($this->srcHeight / 2) - round($height / 2);
|
||||
}
|
||||
|
||||
$this->log(" Crop area is width {$width}px, height {$height}px, start_x {$this->crop['start_x']}px, start_y {$this->crop['start_y']}px.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Crop, ensure to set new width and height
|
||||
if ($this->crop) {
|
||||
$this->log(" Crop.");
|
||||
$this->targetWidth = round(isset($this->targetWidth)
|
||||
? $this->targetWidth
|
||||
: $this->crop['width']);
|
||||
$this->targetHeight = round(isset($this->targetHeight)
|
||||
? $this->targetHeight
|
||||
: $this->crop['height']);
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get source width.
|
||||
*
|
||||
* @return integer as source width
|
||||
*/
|
||||
public function getSourceWidth()
|
||||
{
|
||||
return $this->srcWidth;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get source height.
|
||||
*
|
||||
* @return integer as source height
|
||||
*/
|
||||
public function getSourceHeight()
|
||||
{
|
||||
return $this->srcHeight;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get target width.
|
||||
*
|
||||
* @return integer as target width
|
||||
*/
|
||||
public function getTargetWidth()
|
||||
{
|
||||
return $this->targetWidth;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get target height.
|
||||
*
|
||||
* @return integer as target height
|
||||
*/
|
||||
public function getTargetHeight()
|
||||
{
|
||||
return $this->targetHeight;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get destination x.
|
||||
*
|
||||
* @return integer as destination x
|
||||
*/
|
||||
public function getDestinationX()
|
||||
{
|
||||
return $this->destinationX;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get destination y.
|
||||
*
|
||||
* @return integer as destination y
|
||||
*/
|
||||
public function getDestinationY()
|
||||
{
|
||||
return $this->destinationY;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get destination width.
|
||||
*
|
||||
* @return integer as destination width
|
||||
*/
|
||||
public function getDestinationWidth()
|
||||
{
|
||||
return $this->destinationWidth;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get destination height.
|
||||
*
|
||||
* @return integer as destination height
|
||||
*/
|
||||
public function getDestinationHeight()
|
||||
{
|
||||
return $this->destinationHeight;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get crop position x.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getCropX()
|
||||
{
|
||||
return $this->cropX;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get crop position y.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getCropY()
|
||||
{
|
||||
return $this->cropY;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get crop width.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getCropWidth()
|
||||
{
|
||||
return $this->cropWidth;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get crop height.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getCropHeight()
|
||||
{
|
||||
return $this->cropHeight;
|
||||
}
|
||||
}
|
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Mos\CImage;
|
||||
|
||||
/**
|
||||
* Get a image from a remote server using HTTP GET and If-Modified-Since.
|
||||
*
|
||||
@@ -101,7 +104,7 @@ class CRemoteImage
|
||||
*/
|
||||
public function setCache($path)
|
||||
{
|
||||
$this->saveFolder = $path;
|
||||
$this->saveFolder = rtrim($path, "/") . "/";
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -147,7 +150,12 @@ class CRemoteImage
|
||||
*/
|
||||
public function setHeaderFields()
|
||||
{
|
||||
$this->http->setHeader("User-Agent", "CImage/0.7.2 (PHP/". phpversion() . " cURL)");
|
||||
$cimageVersion = "CImage";
|
||||
if (defined("CIMAGE_USER_AGENT")) {
|
||||
$cimageVersion = CIMAGE_USER_AGENT;
|
||||
}
|
||||
|
||||
$this->http->setHeader("User-Agent", "$cimageVersion (PHP/". phpversion() . " cURL)");
|
||||
$this->http->setHeader("Accept", "image/jpeg,image/png,image/gif");
|
||||
|
||||
if ($this->useCache) {
|
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Mos\CImage;
|
||||
|
||||
/**
|
||||
* Act as whitelist (or blacklist).
|
||||
*
|
22
src/CImage/Exception.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Mos\CImage;
|
||||
|
||||
/**
|
||||
* Anax class for wrapping sessions.
|
||||
*
|
||||
*/
|
||||
class Exception extends \Exception
|
||||
{
|
||||
/**
|
||||
* Construct.
|
||||
*
|
||||
* @param string $message the Exception message to throw.
|
||||
* @param int $code the Exception code.
|
||||
* @param Exception previous the previous exception used for the exception chaining.
|
||||
*/
|
||||
public function __construct($message = "", $code = 0, $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
}
|
11
src/defines.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
// Version of cimage and img.php
|
||||
define("CIMAGE_VERSION", "v0.7.19* (2016-08-11)");
|
||||
|
||||
// For CRemoteImage
|
||||
define("CIMAGE_USER_AGENT", "CImage/" . CIMAGE_VERSION);
|
||||
|
||||
// Image type IMG_WEBP is only defined from 5.6.25
|
||||
if (!defined("IMG_WEBP")) {
|
||||
define("IMG_WEBP", -1);
|
||||
}
|
170
src/functions.php
Normal file
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
/**
|
||||
* General functions to use in img.php.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Trace and log execution to logfile, useful for debugging and development.
|
||||
*
|
||||
* @param string $msg message to log to file.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function trace($msg)
|
||||
{
|
||||
$file = CIMAGE_DEBUG_FILE;
|
||||
if (!is_writable($file)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$timer = number_format((microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"]), 6);
|
||||
$details = "{$timer}ms";
|
||||
$details .= ":" . round(memory_get_peak_usage()/1024/1024, 3) . "MB";
|
||||
$details .= ":" . count(get_included_files());
|
||||
file_put_contents($file, "$details:$msg\n", FILE_APPEND);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Display error message.
|
||||
*
|
||||
* @param string $msg to display.
|
||||
* @param int $type of HTTP error to display.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function errorPage($msg, $type = 500)
|
||||
{
|
||||
global $mode;
|
||||
|
||||
switch ($type) {
|
||||
case 403:
|
||||
$header = "403 Forbidden";
|
||||
break;
|
||||
case 404:
|
||||
$header = "404 Not Found";
|
||||
break;
|
||||
default:
|
||||
$header = "500 Internal Server Error";
|
||||
}
|
||||
|
||||
if ($mode == "strict") {
|
||||
$header = "404 Not Found";
|
||||
}
|
||||
|
||||
header("HTTP/1.0 $header");
|
||||
|
||||
if ($mode == "development") {
|
||||
die("[img.php] $msg");
|
||||
}
|
||||
|
||||
error_log("[img.php] $msg");
|
||||
die("HTTP/1.0 $header");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get input from query string or return default value if not set.
|
||||
*
|
||||
* @param mixed $key as string or array of string values to look for in $_GET.
|
||||
* @param mixed $default value to return when $key is not set in $_GET.
|
||||
*
|
||||
* @return mixed value from $_GET or default value.
|
||||
*/
|
||||
function get($key, $default = null)
|
||||
{
|
||||
if (is_array($key)) {
|
||||
foreach ($key as $val) {
|
||||
if (isset($_GET[$val])) {
|
||||
return $_GET[$val];
|
||||
}
|
||||
}
|
||||
} elseif (isset($_GET[$key])) {
|
||||
return $_GET[$key];
|
||||
}
|
||||
return $default;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get input from query string and set to $defined if defined or else $undefined.
|
||||
*
|
||||
* @param mixed $key as string or array of string values to look for in $_GET.
|
||||
* @param mixed $defined value to return when $key is set in $_GET.
|
||||
* @param mixed $undefined value to return when $key is not set in $_GET.
|
||||
*
|
||||
* @return mixed value as $defined or $undefined.
|
||||
*/
|
||||
function getDefined($key, $defined, $undefined)
|
||||
{
|
||||
return get($key) === null ? $undefined : $defined;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get value from config array or default if key is not set in config array.
|
||||
*
|
||||
* @param string $key the key in the config array.
|
||||
* @param mixed $default value to be default if $key is not set in config.
|
||||
*
|
||||
* @return mixed value as $config[$key] or $default.
|
||||
*/
|
||||
function getConfig($key, $default)
|
||||
{
|
||||
global $config;
|
||||
return isset($config[$key])
|
||||
? $config[$key]
|
||||
: $default;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Log when verbose mode, when used without argument it returns the result.
|
||||
*
|
||||
* @param string $msg to log.
|
||||
*
|
||||
* @return void or array.
|
||||
*/
|
||||
function verbose($msg = null)
|
||||
{
|
||||
global $verbose, $verboseFile;
|
||||
static $log = array();
|
||||
|
||||
if (!($verbose || $verboseFile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_null($msg)) {
|
||||
return $log;
|
||||
}
|
||||
|
||||
$log[] = $msg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Log when verbose mode, when used without argument it returns the result.
|
||||
*
|
||||
* @param string $msg to log.
|
||||
*
|
||||
* @return void or array.
|
||||
*/
|
||||
function checkExternalCommand($what, $enabled, $commandString)
|
||||
{
|
||||
$no = $enabled ? null : 'NOT';
|
||||
$text = "Post processing $what is $no enabled.<br>";
|
||||
|
||||
list($command) = explode(" ", $commandString);
|
||||
$no = is_executable($command) ? null : 'NOT';
|
||||
$text .= "The command for $what is $no an executable.<br>";
|
||||
|
||||
return $text;
|
||||
}
|
71
test/CCacheTest.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace Mos\CImage;
|
||||
|
||||
/**
|
||||
* A testclass
|
||||
*
|
||||
*/
|
||||
class CCacheTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* Test
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSetCacheDir()
|
||||
{
|
||||
$cache = new CCache();
|
||||
$cache->setDir(CACHE_PATH);
|
||||
|
||||
$exp = "exists, writable";
|
||||
$res = $cache->getStatusOfSubdir("");
|
||||
$this->assertEquals($exp, $res, "Status of cache dir missmatch.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test
|
||||
*
|
||||
* @expectedException Exception
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSetWrongCacheDir()
|
||||
{
|
||||
$cache = new CCache();
|
||||
$cache->setDir(CACHE_PATH . "/NO_EXISTS");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testCreateSubdir()
|
||||
{
|
||||
$cache = new CCache();
|
||||
$cache->setDir(CACHE_PATH);
|
||||
|
||||
$subdir = "__test__";
|
||||
$cache->removeSubdir($subdir);
|
||||
|
||||
$exp = "does not exist";
|
||||
$res = $cache->getStatusOfSubdir($subdir, false);
|
||||
$this->assertEquals($exp, $res, "Subdir should not be created.");
|
||||
|
||||
$res = $cache->getPathToSubdir($subdir);
|
||||
$exp = realpath(CACHE_PATH . "/$subdir");
|
||||
$this->assertEquals($exp, $res, "Subdir path missmatch.");
|
||||
|
||||
$exp = "exists, writable";
|
||||
$res = $cache->getStatusOfSubdir($subdir);
|
||||
$this->assertEquals($exp, $res, "Subdir should exist.");
|
||||
|
||||
$res = $cache->removeSubdir($subdir);
|
||||
$this->assertTrue($res, "Remove subdir.");
|
||||
}
|
||||
}
|
@@ -1,10 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace Mos\CImage;
|
||||
|
||||
/**
|
||||
* A testclass
|
||||
*
|
||||
*/
|
||||
class CImageDummyTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
const DUMMY = "__dummy__";
|
||||
private $cachepath;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Setup environment
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function setUp()
|
||||
{
|
||||
$cache = new CCache();
|
||||
$cache->setDir(CACHE_PATH);
|
||||
$this->cachepath = $cache->getPathToSubdir(self::DUMMY);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Clean up cache dir content.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function removeFilesInCacheDir()
|
||||
{
|
||||
$files = glob($this->cachepath . "/*");
|
||||
foreach ($files as $file) {
|
||||
if (is_file($file)) {
|
||||
unlink($file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Teardown environment
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function tearDown()
|
||||
{
|
||||
$cache = new CCache();
|
||||
$cache->setDir(CACHE_PATH);
|
||||
$this->removeFilesInCacheDir();
|
||||
$cache->removeSubdir(self::DUMMY);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test
|
||||
*
|
||||
@@ -14,15 +68,15 @@ class CImageDummyTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$img = new CImage();
|
||||
|
||||
$img->setSaveFolder(CACHE_PATH . "/dummy");
|
||||
$img->setSource('dummy', CACHE_PATH . "/dummy");
|
||||
$img->setSaveFolder($this->cachepath);
|
||||
$img->setSource(self::DUMMY, $this->cachepath);
|
||||
$img->createDummyImage();
|
||||
$img->generateFilename(null, false);
|
||||
$img->save(null, null, false);
|
||||
|
||||
$filename = $img->getTarget();
|
||||
|
||||
$this->assertEquals(basename($filename), "dummy_100_100", "Filename not as expected on dummy image.");
|
||||
$this->assertEquals(basename($filename), self::DUMMY . "_100_100", "Filename not as expected on dummy image.");
|
||||
}
|
||||
|
||||
|
||||
@@ -36,14 +90,14 @@ class CImageDummyTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$img = new CImage();
|
||||
|
||||
$img->setSaveFolder(CACHE_PATH . "/dummy");
|
||||
$img->setSource('dummy', CACHE_PATH . "/dummy");
|
||||
$img->setSaveFolder($this->cachepath);
|
||||
$img->setSource(self::DUMMY, $this->cachepath);
|
||||
$img->createDummyImage(200, 400);
|
||||
$img->generateFilename(null, false);
|
||||
$img->save(null, null, false);
|
||||
|
||||
$filename = $img->getTarget();
|
||||
|
||||
$this->assertEquals(basename($filename), "dummy_200_400", "Filename not as expected on dummy image.");
|
||||
$this->assertEquals(basename($filename), self::DUMMY . "_200_400", "Filename not as expected on dummy image.");
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Mos\CImage;
|
||||
|
||||
/**
|
||||
* A testclass
|
||||
*
|
||||
@@ -61,7 +64,7 @@ class CImageRemoteDownloadTest extends \PHPUnit_Framework_TestCase
|
||||
public function testAllowRemoteDownloadDefaultPatternValid($source)
|
||||
{
|
||||
$img = new CImage();
|
||||
$img->setRemoteDownload(true);
|
||||
$img->setRemoteDownload(true, "");
|
||||
|
||||
$res = $img->isRemoteSource($source);
|
||||
$this->assertTrue($res, "Should be a valid remote source: '$source'.");
|
||||
@@ -79,7 +82,7 @@ class CImageRemoteDownloadTest extends \PHPUnit_Framework_TestCase
|
||||
public function testAllowRemoteDownloadDefaultPatternInvalid($source)
|
||||
{
|
||||
$img = new CImage();
|
||||
$img->setRemoteDownload(true);
|
||||
$img->setRemoteDownload(true, "");
|
||||
|
||||
$res = $img->isRemoteSource($source);
|
||||
$this->assertFalse($res, "Should not be a valid remote source: '$source'.");
|
||||
|
74
test/CImageResizerByAspectRatioTest.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace Mos\CImage;
|
||||
|
||||
/**
|
||||
* A testclass
|
||||
*
|
||||
*/
|
||||
class CImageResizerByAspectRatioTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* Provider
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function providerImages()
|
||||
{
|
||||
return array(
|
||||
|
||||
// No value set
|
||||
array(null, 100, 100, null, null, null, null),
|
||||
|
||||
// Aspect ratio 1
|
||||
array(1, 100, 100, null, null, 100, 100),
|
||||
array(1, 100, 100, null, 100, 100, 100),
|
||||
array(1, 100, 100, 100, null, 100, 100),
|
||||
array(1, 100, 100, 100, 100, 100, 100),
|
||||
|
||||
// Aspect ratio 2
|
||||
array(2, 100, 100, null, null, 100, 50),
|
||||
array(2, 100, 100, null, 100, 200, 100),
|
||||
array(2, 100, 100, 100, null, 100, 50),
|
||||
array(2, 100, 100, 100, 100, 100, 50),
|
||||
|
||||
// Aspect ratio 0.5
|
||||
array(1/2, 100, 100, null, null, 50, 100),
|
||||
array(1/2, 100, 100, null, 100, 50, 100),
|
||||
array(1/2, 100, 100, 100, null, 100, 200),
|
||||
array(1/2, 100, 100, 100, 100, 50, 100),
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test
|
||||
*
|
||||
* @dataProvider providerImages
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testResize1(
|
||||
$aspectRatio,
|
||||
$srcWidth,
|
||||
$srcHeight,
|
||||
$targetWidth,
|
||||
$targetHeight,
|
||||
$expectedWidth,
|
||||
$expectedHeight
|
||||
) {
|
||||
$img = new CImageResizer(/*'logger'*/);
|
||||
//$img = new CImageResizer('logger');
|
||||
|
||||
$img->setSource($srcWidth, $srcHeight)
|
||||
->setBaseWidthHeight($targetWidth, $targetHeight)
|
||||
->setBaseAspecRatio($aspectRatio)
|
||||
->prepareTargetDimensions();
|
||||
// ->calculateTargetWidthAndHeight();
|
||||
|
||||
$this->assertEquals($expectedWidth, $img->getTargetWidth(), "Width not correct.");
|
||||
$this->assertEquals($expectedHeight, $img->getTargetHeight(), "Height not correct.");
|
||||
}
|
||||
}
|
75
test/CImageResizerByDensityPixelRatioTest.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace Mos\CImage;
|
||||
|
||||
/**
|
||||
* A testclass
|
||||
*
|
||||
*/
|
||||
class CImageResizerByDevicePixelRatioTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* Provider
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function providerImages()
|
||||
{
|
||||
return array(
|
||||
|
||||
// No value set
|
||||
array(null, 100, 100, null, null, null, null),
|
||||
|
||||
// dpr 1
|
||||
array(1, 100, 100, null, null, 100, 100),
|
||||
array(1, 100, 100, null, 100, null, 100),
|
||||
array(1, 100, 100, 100, null, 100, null),
|
||||
array(1, 100, 100, 100, 100, 100, 100),
|
||||
|
||||
// dpr 2
|
||||
array(2, 100, 100, null, null, 200, 200),
|
||||
array(2, 100, 100, null, 200, null, 400),
|
||||
array(2, 100, 100, 200, null, 400, null),
|
||||
array(2, 100, 100, 200, 200, 400, 400),
|
||||
|
||||
// dpr 1/2
|
||||
array(1/2, 100, 100, null, null, 50, 50),
|
||||
array(1/2, 100, 100, null, 200, null, 100),
|
||||
array(1/2, 100, 100, 200, null, 100, null),
|
||||
array(1/2, 100, 100, 200, 200, 100, 100),
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test
|
||||
*
|
||||
* @dataProvider providerImages
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testResize1(
|
||||
$dpr,
|
||||
$srcWidth,
|
||||
$srcHeight,
|
||||
$targetWidth,
|
||||
$targetHeight,
|
||||
$expectedWidth,
|
||||
$expectedHeight
|
||||
) {
|
||||
$img = new CImageResizer(/*'logger'*/);
|
||||
//$img = new CImageResizer('logger');
|
||||
|
||||
$img->setSource($srcWidth, $srcHeight)
|
||||
//->setResizeStrategy($img::KEEP_RATIO)
|
||||
->setBaseWidthHeight($targetWidth, $targetHeight)
|
||||
->setBaseDevicePixelRate($dpr)
|
||||
->prepareTargetDimensions();
|
||||
//->calculateTargetWidthAndHeight();
|
||||
|
||||
$this->assertEquals($expectedWidth, $img->getTargetWidth(), "Width not correct.");
|
||||
$this->assertEquals($expectedHeight, $img->getTargetHeight(), "Height not correct.");
|
||||
}
|
||||
}
|
131
test/CImageResizerStrategyCropToFitTest.php
Normal file
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
|
||||
namespace Mos\CImage;
|
||||
|
||||
/**
|
||||
* A testclass
|
||||
*
|
||||
*/
|
||||
class CImageResizerStrategyCropToFitTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* Provider
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function providerImages()
|
||||
{
|
||||
return [
|
||||
|
||||
// Square
|
||||
[100, 100, 200, 200, 0, 0, 100, 100],
|
||||
[100, 100, 200, 100, 0, 25, 100, 50],
|
||||
[100, 100, 100, 200, 25, 0, 50, 100],
|
||||
|
||||
// Landscape
|
||||
[200, 100, 400, 200, 0, 0, 200, 100],
|
||||
[200, 100, 50, 50, 50, 0, 100, 100],
|
||||
[200, 100, 400, 100, 0, 25, 200, 50],
|
||||
[200, 100, 100, 400, round(175/2), 0, 25, 100],
|
||||
|
||||
// Portrait
|
||||
[100, 200, 50, 100, 0, 0, 100, 200],
|
||||
[100, 200, 50, 50, 0, 50, 100, 100],
|
||||
[100, 200, 200, 50, 0, round(175/2), 100, 25],
|
||||
[100, 200, 50, 200, 25, 0, 50, 200],
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test
|
||||
*
|
||||
* @dataProvider providerImages
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testResize1($sw, $sh, $tw, $th, $cx, $cy, $cw, $ch)
|
||||
{
|
||||
$img = new CImageResizer(/*'logger'/**/);
|
||||
|
||||
$img->setSource($sw, $sh)
|
||||
->setBaseWidthHeight($tw, $th)
|
||||
->setResizeStrategy(CImageResizer::CROP_TO_FIT)
|
||||
->calculateTargetWidthAndHeight();
|
||||
|
||||
$this->assertEquals($tw, $img->getTargetWidth(), "Target width not correct.");
|
||||
$this->assertEquals($th, $img->getTargetHeight(), "Target height not correct.");
|
||||
|
||||
$this->assertEquals($cx, $img->getCropX(), "CropX not correct.");
|
||||
$this->assertEquals($cy, $img->getCropY(), "CropY not correct.");
|
||||
$this->assertEquals($cw, $img->getCropWidth(), "CropWidth not correct.");
|
||||
$this->assertEquals($ch, $img->getCropHeight(), "CropHeight not correct.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Provider
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function providerImages2()
|
||||
{
|
||||
return [
|
||||
|
||||
// Square
|
||||
[100,100, 200,200, 0,0,100,100, 50,50,100,100],
|
||||
[100,100, 200,100, 0,0,100,100, 50,0,100,100],
|
||||
[100,100, 100,200, 0,0,100,100, 0,50,100,100],
|
||||
|
||||
// Landscape
|
||||
[200,100, 400,200, 0,0,200,100, 100,50,200,100],
|
||||
//[200,100, 50,50, 50,0,100,100, 0,0,200,100],
|
||||
/*
|
||||
[200, 100, 400, 100, 0, 25, 200, 50],
|
||||
[200, 100, 100, 400, round(175/2), 0, 25, 100],
|
||||
|
||||
// Portrait
|
||||
[100, 200, 50, 100, 0, 0, 100, 200],
|
||||
[100, 200, 50, 50, 0, 50, 100, 100],
|
||||
[100, 200, 200, 50, 0, round(175/2), 100, 25],
|
||||
[100, 200, 50, 200, 25, 0, 50, 200],
|
||||
/* */
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test
|
||||
*
|
||||
* @dataProvider providerImages2
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testResize2($sw, $sh, $tw, $th, $cx, $cy, $cw, $ch, $dx, $dy, $dw, $dh)
|
||||
{
|
||||
$img = new CImageResizer(/*'logger'/**/);
|
||||
|
||||
$img->setSource($sw, $sh)
|
||||
->setBaseWidthHeight($tw, $th)
|
||||
->setResizeStrategy(CImageResizer::CROP_TO_FIT)
|
||||
->allowUpscale(false)
|
||||
->calculateTargetWidthAndHeight();
|
||||
|
||||
$this->assertEquals($tw, $img->getTargetWidth(), "Target width not correct.");
|
||||
$this->assertEquals($th, $img->getTargetHeight(), "Target height not correct.");
|
||||
|
||||
$this->assertEquals($cx, $img->getCropX(), "CropX not correct.");
|
||||
$this->assertEquals($cy, $img->getCropY(), "CropY not correct.");
|
||||
$this->assertEquals($cw, $img->getCropWidth(), "CropWidth not correct.");
|
||||
$this->assertEquals($ch, $img->getCropHeight(), "CropHeight not correct.");
|
||||
|
||||
$this->assertEquals($dx, $img->getDestinationX(), "DestinationX not correct.");
|
||||
$this->assertEquals($dy, $img->getDestinationY(), "DestinationY not correct.");
|
||||
$this->assertEquals($dw, $img->getDestinationWidth(), "DestinationWidth not correct.");
|
||||
$this->assertEquals($dh, $img->getDestinationHeight(), "DestinationHeight not correct.");
|
||||
}
|
||||
}
|
119
test/CImageResizerStrategyFillToFitTest.php
Normal file
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace Mos\CImage;
|
||||
|
||||
/**
|
||||
* A testclass
|
||||
*
|
||||
*/
|
||||
class CImageResizerStrategyFillToFitTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* Provider
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function providerImages()
|
||||
{
|
||||
return array(
|
||||
|
||||
// Square
|
||||
array(100, 100, 200, 200, 0, 0, 200, 200),
|
||||
array(100, 100, 100, 50, 25, 0, 50, 50),
|
||||
array(100, 100, 50, 100, 0, 25, 50, 50),
|
||||
|
||||
// Landscape
|
||||
array(200, 100, 400, 200, 0, 0, 400, 200),
|
||||
array(200, 100, 100, 100, 0, 25, 100, 50),
|
||||
array(200, 100, 400, 100, 100, 0, 200, 100),
|
||||
array(200, 100, 100, 400, 0, 175, 100, 50),
|
||||
|
||||
// Portrait
|
||||
array(100, 200, 200, 400, 0, 0, 200, 400),
|
||||
array(100, 200, 100, 100, 25, 0, 50, 100),
|
||||
array(100, 200, 400, 100, 175, 0, 50, 100),
|
||||
array(100, 200, 100, 400, 0, 100, 100, 200),
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test
|
||||
*
|
||||
* @dataProvider providerImages
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testResize1($sw, $sh, $tw, $th, $dx, $dy, $dw, $dh)
|
||||
{
|
||||
$img = new CImageResizer(/*'logger'/**/);
|
||||
|
||||
$img->setSource($sw, $sh)
|
||||
->setBaseWidthHeight($tw, $th)
|
||||
->setResizeStrategy(CImageResizer::FILL_TO_FIT)
|
||||
->calculateTargetWidthAndHeight();
|
||||
|
||||
$this->assertEquals($tw, $img->getTargetWidth(), "Target width not correct.");
|
||||
$this->assertEquals($th, $img->getTargetHeight(), "Target height not correct.");
|
||||
|
||||
$this->assertEquals($dx, $img->getDestinationX(), "DestinationX not correct.");
|
||||
$this->assertEquals($dy, $img->getDestinationY(), "DestinationY not correct.");
|
||||
$this->assertEquals($dw, $img->getDestinationWidth(), "DestinationWidth not correct.");
|
||||
$this->assertEquals($dh, $img->getDestinationHeight(), "DestinationHeight not correct.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Provider
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function providerImages2()
|
||||
{
|
||||
return [
|
||||
|
||||
// Square
|
||||
[100, 100, 200, 200, 50, 50, 100, 100],
|
||||
[100, 100, 400, 100, 150, 0, 100, 100],
|
||||
[100, 100, 100, 400, 0, 150, 100, 100],
|
||||
[100, 100, 400, 400, 150, 150, 100, 100],
|
||||
[491, 323, 600, 400, 55, 39, 491, 323],
|
||||
|
||||
// Landscape
|
||||
|
||||
// Portrait
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test
|
||||
*
|
||||
* @dataProvider providerImages2
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testResize2($sw, $sh, $tw, $th, $dx, $dy, $dw, $dh)
|
||||
{
|
||||
$img = new CImageResizer(/*'logger'/**/);
|
||||
|
||||
$img->setSource($sw, $sh)
|
||||
->setBaseWidthHeight($tw, $th)
|
||||
->setResizeStrategy(CImageResizer::FILL_TO_FIT)
|
||||
->allowUpscale(false)
|
||||
->calculateTargetWidthAndHeight();
|
||||
|
||||
$this->assertEquals($tw, $img->getTargetWidth(), "Target width not correct.");
|
||||
$this->assertEquals($th, $img->getTargetHeight(), "Target height not correct.");
|
||||
|
||||
$this->assertEquals($dx, $img->getDestinationX(), "DestinationX not correct.");
|
||||
$this->assertEquals($dy, $img->getDestinationY(), "DestinationY not correct.");
|
||||
$this->assertEquals($dw, $img->getDestinationWidth(), "DestinationWidth not correct.");
|
||||
$this->assertEquals($dh, $img->getDestinationHeight(), "DestinationHeight not correct.");
|
||||
}
|
||||
}
|
129
test/CImageResizerStrategyKeepAspectRatioTest.php
Normal file
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
namespace Mos\CImage;
|
||||
|
||||
/**
|
||||
* A testclass
|
||||
*
|
||||
*/
|
||||
class CImageResizerStrategyKeepAspectRatioTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* Provider
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function providerImages()
|
||||
{
|
||||
return array(
|
||||
|
||||
// Square
|
||||
array(100, 100, null, null, 100, 100, 0, 0, 100, 100),
|
||||
array(100, 100, null, 200, 200, 200, 0, 0, 100, 100),
|
||||
array(100, 100, 200, null, 200, 200, 0, 0, 100, 100),
|
||||
array(100, 100, 200, 200, 200, 200, 0, 0, 100, 100),
|
||||
|
||||
// Landscape
|
||||
array(200, 100, null, null, 200, 100, 0, 0, 200, 100),
|
||||
array(200, 100, null, 200, 400, 200, 0, 0, 200, 100),
|
||||
array(200, 100, 400, null, 400, 200, 0, 0, 200, 100),
|
||||
array(200, 100, 400, 200, 400, 200, 0, 0, 200, 100),
|
||||
|
||||
// Portrait
|
||||
array(100, 200, null, null, 100, 200, 0, 0, 100, 200),
|
||||
array(100, 200, null, 100, 50, 100, 0, 0, 100, 200),
|
||||
array(100, 200, 50, null, 50, 100, 0, 0, 100, 200),
|
||||
array(100, 200, 50, 100, 50, 100, 0, 0, 100, 200),
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test
|
||||
*
|
||||
* @dataProvider providerImages
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testResize1($sw, $sh, $tw, $th, $twa, $tha, $cx, $cy, $cw, $ch)
|
||||
{
|
||||
$img = new CImageResizer(/*'logger'/**/);
|
||||
|
||||
$img->setSource($sw, $sh)
|
||||
->setBaseWidthHeight($tw, $th)
|
||||
->setResizeStrategy(CImageResizer::KEEP_RATIO)
|
||||
->calculateTargetWidthAndHeight();
|
||||
|
||||
$this->assertEquals($twa, $img->getTargetWidth(), "Target width not correct.");
|
||||
$this->assertEquals($tha, $img->getTargetHeight(), "Target height not correct.");
|
||||
|
||||
$this->assertEquals($cx, $img->getCropX(), "CropX not correct.");
|
||||
$this->assertEquals($cy, $img->getCropY(), "CropY not correct.");
|
||||
$this->assertEquals($cw, $img->getCropWidth(), "CropWidth not correct.");
|
||||
$this->assertEquals($ch, $img->getCropHeight(), "CropHeight not correct.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Provider
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function providerImages2()
|
||||
{
|
||||
return array(
|
||||
|
||||
// Square
|
||||
array(100, 100, 100, 100, 100, 100, 0, 0, 100, 100),
|
||||
array(100, 100, null, 200, 100, 100, 0, 0, 100, 100),
|
||||
array(100, 100, 200, null, 100, 100, 0, 0, 100, 100),
|
||||
array(100, 100, 200, 100, 100, 100, 0, 0, 100, 100),
|
||||
array(100, 100, 100, 200, 100, 100, 0, 0, 100, 100),
|
||||
array(100, 100, 200, 200, 100, 100, 0, 0, 100, 100),
|
||||
|
||||
// Landscape
|
||||
//array(200, 100, null, null, 200, 100, 0, 0, 200, 100),
|
||||
//array(200, 100, null, 200, 400, 200, 0, 0, 200, 100),
|
||||
//array(200, 100, 400, null, 400, 200, 0, 0, 200, 100),
|
||||
//array(200, 100, 400, 200, 400, 200, 0, 0, 200, 100),
|
||||
|
||||
// Portrait
|
||||
//array(100, 200, null, null, 100, 200, 0, 0, 100, 200),
|
||||
//array(100, 200, null, 100, 50, 100, 0, 0, 100, 200),
|
||||
//array(100, 200, 50, null, 50, 100, 0, 0, 100, 200),
|
||||
//array(100, 200, 50, 100, 50, 100, 0, 0, 100, 200),
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test
|
||||
*
|
||||
* @dataProvider providerImages2
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testResize2($sw, $sh, $tw, $th, $twa, $tha, $cx, $cy, $cw, $ch)
|
||||
{
|
||||
$img = new CImageResizer(/*'logger'/**/);
|
||||
|
||||
$img->setSource($sw, $sh)
|
||||
->setBaseWidthHeight($tw, $th)
|
||||
->setResizeStrategy(CImageResizer::KEEP_RATIO)
|
||||
->allowUpscale(false)
|
||||
->calculateTargetWidthAndHeight();
|
||||
|
||||
$this->assertEquals($twa, $img->getTargetWidth(), "Target width not correct.");
|
||||
$this->assertEquals($tha, $img->getTargetHeight(), "Target height not correct.");
|
||||
|
||||
$this->assertEquals($cx, $img->getCropX(), "CropX not correct.");
|
||||
$this->assertEquals($cy, $img->getCropY(), "CropY not correct.");
|
||||
$this->assertEquals($cw, $img->getCropWidth(), "CropWidth not correct.");
|
||||
$this->assertEquals($ch, $img->getCropHeight(), "CropHeight not correct.");
|
||||
}
|
||||
}
|
57
test/CImageResizerStrategyStretchTest.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace Mos\CImage;
|
||||
|
||||
/**
|
||||
* A testclass
|
||||
*
|
||||
*/
|
||||
class CImageResizerStrategyStretchTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* Provider
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function providerImages()
|
||||
{
|
||||
return array(
|
||||
|
||||
// Square
|
||||
array(100, 100, 200, 200),
|
||||
array(100, 100, 200, 100),
|
||||
array(100, 100, 100, 200),
|
||||
|
||||
// Landscape
|
||||
array(200, 100, 400, 200),
|
||||
array(200, 100, 100, 200),
|
||||
|
||||
// Portrait
|
||||
array(100, 200, 50, 100),
|
||||
array(100, 200, 100, 100),
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test
|
||||
*
|
||||
* @dataProvider providerImages
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testResize1($sw, $sh, $tw, $th)
|
||||
{
|
||||
$img = new CImageResizer(/*'logger'/**/);
|
||||
|
||||
$img->setSource($sw, $sh)
|
||||
->setBaseWidthHeight($tw, $th)
|
||||
->setResizeStrategy(CImageResizer::STRETCH)
|
||||
->calculateTargetWidthAndHeight();
|
||||
|
||||
$this->assertEquals($tw, $img->getTargetWidth(), "Target width not correct.");
|
||||
$this->assertEquals($th, $img->getTargetHeight(), "Target height not correct.");
|
||||
}
|
||||
}
|
207
test/CImageResizerTest.php
Normal file
@@ -0,0 +1,207 @@
|
||||
<?php
|
||||
|
||||
namespace Mos\CImage;
|
||||
|
||||
/**
|
||||
* A testclass
|
||||
*
|
||||
*/
|
||||
function logger($str)
|
||||
{
|
||||
echo "$str\n";
|
||||
}
|
||||
|
||||
function loggerDummy($str)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
class CImageResizerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* Provider
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function providerFaultImages()
|
||||
{
|
||||
return array(
|
||||
array('xx', 100, null, 1),
|
||||
array( 100, 'yy', null, 1),
|
||||
array( 100, 100, 'zz', 1),
|
||||
array( 100, 100, null, -1),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test
|
||||
*
|
||||
* @dataProvider providerFaultImages
|
||||
*
|
||||
* @expectedException Exception
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testResizeFaults($targetWidth, $targetHeight, $aspectRatio, $dpr)
|
||||
{
|
||||
$img = new CImageResizer(/*'logger'*/);
|
||||
|
||||
$img->setBaseWidthHeight($targetWidth, $targetHeight)
|
||||
->setBaseAspecRatio($aspectRatio)
|
||||
->setBaseDevicePixelRate($dpr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testLogger()
|
||||
{
|
||||
$img = new CImageResizer('Mos\CImage\loggerDummy');
|
||||
|
||||
$img->setBaseWidthHeight(100, 100);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Provider
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function providerResizeStrategy()
|
||||
{
|
||||
return array(
|
||||
array(CImageResizer::KEEP_RATIO, "KEEP_RATIO"),
|
||||
array(CImageResizer::CROP_TO_FIT, "CROP_TO_FIT"),
|
||||
array(CImageResizer::FILL_TO_FIT, "FILL_TO_FIT"),
|
||||
array(CImageResizer::STRETCH, "STRETCH"),
|
||||
array(-1, "UNKNOWN"),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test
|
||||
*
|
||||
* @dataProvider providerResizeStrategy
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testResizeStrategy($strategy, $str)
|
||||
{
|
||||
$img = new CImageResizer(/*'logger'*/);
|
||||
|
||||
$img->setResizeStrategy($strategy);
|
||||
$res = $img->getResizeStrategyAsString();
|
||||
|
||||
$this->assertEquals($str, $res, "Strategy not matching.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Provider
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function providerPercent()
|
||||
{
|
||||
return array(
|
||||
array(100, 100, "100%", "100%", 100, 100),
|
||||
array(100, 100, "50%", "50%", 50, 50),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test
|
||||
*
|
||||
* @dataProvider providerPercent
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testPercent($sw, $sh, $tw, $th, $w, $h)
|
||||
{
|
||||
$img = new CImageResizer(/*'logger'*/);
|
||||
|
||||
$img->setSource($sw, $sh)
|
||||
->setBaseWidthHeight($tw, $th);
|
||||
|
||||
$this->assertEquals($w, $img->getTargetWidth(), "Target width not correct.");
|
||||
$this->assertEquals($h, $img->getTargetHeight(), "Target height not correct.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testGetSource()
|
||||
{
|
||||
$img = new CImageResizer(/*'logger'*/);
|
||||
|
||||
$w = 100;
|
||||
$h = 100;
|
||||
|
||||
$img->setSource($w, $h);
|
||||
|
||||
$this->assertEquals($w, $img->getSourceWidth(), "Source width not correct.");
|
||||
$this->assertEquals($h, $img->getSourceHeight(), "Source height not correct.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Provider
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function providerImages()
|
||||
{
|
||||
return [
|
||||
|
||||
// car.png
|
||||
[CImageResizer::KEEP_RATIO, 491, 324, 500, 200, 303, 200, 0, 0, 491, 324],
|
||||
[CImageResizer::KEEP_RATIO, 491, 324, 500, 500, 500, 330, 0, 0, 491, 324],
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test
|
||||
*
|
||||
* @dataProvider providerImages
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testResize($strat, $sw, $sh, $tw, $th, $twa, $tha, $cx, $cy, $cw, $ch)
|
||||
{
|
||||
$img = new CImageResizer(/*'logger'/**/);
|
||||
|
||||
$img->setSource($sw, $sh)
|
||||
->setBaseWidthHeight($tw, $th)
|
||||
->setResizeStrategy($strat)
|
||||
->calculateTargetWidthAndHeight();
|
||||
|
||||
$this->assertEquals($twa, $img->getTargetWidth(), "Target width not correct.");
|
||||
$this->assertEquals($tha, $img->getTargetHeight(), "Target height not correct.");
|
||||
|
||||
$this->assertEquals($cx, $img->getCropX(), "CropX not correct.");
|
||||
$this->assertEquals($cy, $img->getCropY(), "CropY not correct.");
|
||||
$this->assertEquals($cw, $img->getCropWidth(), "CropWidth not correct.");
|
||||
$this->assertEquals($ch, $img->getCropHeight(), "CropHeight not correct.");
|
||||
}
|
||||
}
|
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Mos\CImage;
|
||||
|
||||
/**
|
||||
* A testclass
|
||||
*
|
||||
@@ -38,7 +41,7 @@ class CImageSRGBTest extends \PHPUnit_Framework_TestCase
|
||||
$img = new CImage();
|
||||
|
||||
$filename = $img->convert2sRGBColorSpace(
|
||||
'car.png',
|
||||
'car.png',
|
||||
IMAGE_PATH,
|
||||
$this->cache,
|
||||
$this->srgbColorProfile
|
||||
@@ -63,8 +66,8 @@ class CImageSRGBTest extends \PHPUnit_Framework_TestCase
|
||||
$img = new CImage();
|
||||
|
||||
$filename = $img->convert2sRGBColorSpace(
|
||||
'car.jpg',
|
||||
IMAGE_PATH,
|
||||
'car.jpg',
|
||||
IMAGE_PATH,
|
||||
$this->cache,
|
||||
$this->srgbColorProfile
|
||||
);
|
||||
|
54
test/CImgTest.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace Mos\CImage;
|
||||
|
||||
/**
|
||||
* A testclass for img.php
|
||||
*
|
||||
*/
|
||||
class CImgTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Provider
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function providerQueryString()
|
||||
{
|
||||
return [
|
||||
|
||||
//
|
||||
[[
|
||||
"src" => "car.png",
|
||||
"json" => true,
|
||||
"rotate" => 90,
|
||||
]],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test
|
||||
*
|
||||
* @-preserveGlobalState disabled
|
||||
* @runInSeparateProcess
|
||||
*
|
||||
* @dataProvider providerQueryString
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testResize($query)
|
||||
{
|
||||
//$_GET = $query;
|
||||
|
||||
#ob_start();
|
||||
//$res = require "webroot/img.php";
|
||||
#$res = ob_get_clean();
|
||||
|
||||
//echo "MOPED $res";
|
||||
}
|
||||
}
|
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Mos\CImage;
|
||||
|
||||
/**
|
||||
* A testclass
|
||||
*
|
||||
|
13
test/Tests.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
# Tests to be done
|
||||
|
||||
Use resize fill-to-fit, crop-to-fit, stretch without width and height should result in image having original width and height.
|
||||
|
||||
## Integration tests
|
||||
|
||||
Checkout a version using composer and execute all tests, prefarably on cimage.se.
|
||||
|
||||
|
||||
|
||||
## Reference images
|
||||
|
||||
Create a bunch of reference images to compare between versions. Save together with how it was created.
|
@@ -3,7 +3,12 @@
|
||||
* Get all configuration details to be able to execute the test suite.
|
||||
*
|
||||
*/
|
||||
require __DIR__ . "/../autoload.php";
|
||||
require __DIR__ . "/../vendor/autoload.php";
|
||||
|
||||
define('IMAGE_PATH', __DIR__ . '/../webroot/img/');
|
||||
define('CACHE_PATH', __DIR__ . '/../cache/');
|
||||
if (!defined("IMAGE_PATH")) {
|
||||
define("IMAGE_PATH", __DIR__ . "/../webroot/img/");
|
||||
}
|
||||
|
||||
if (!defined("CACHE_PATH")) {
|
||||
define("CACHE_PATH", __DIR__ . "/../cache/");
|
||||
}
|
||||
|
7
vendor/autoload.php
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
// autoload.php @generated by Composer
|
||||
|
||||
require_once __DIR__ . '/composer/autoload_real.php';
|
||||
|
||||
return ComposerAutoloaderInit2b4448ad4be850d755525f1f201dede8::getLoader();
|
441
vendor/composer/ClassLoader.php
vendored
Normal file
@@ -0,0 +1,441 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
/**
|
||||
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
||||
*
|
||||
* $loader = new \Composer\Autoload\ClassLoader();
|
||||
*
|
||||
* // register classes with namespaces
|
||||
* $loader->add('Symfony\Component', __DIR__.'/component');
|
||||
* $loader->add('Symfony', __DIR__.'/framework');
|
||||
*
|
||||
* // activate the autoloader
|
||||
* $loader->register();
|
||||
*
|
||||
* // to enable searching the include path (eg. for PEAR packages)
|
||||
* $loader->setUseIncludePath(true);
|
||||
*
|
||||
* In this example, if you try to use a class in the Symfony\Component
|
||||
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||
* the autoloader will first look for the class under the component/
|
||||
* directory, and it will then fallback to the framework/ directory if not
|
||||
* found before giving up.
|
||||
*
|
||||
* This class is loosely based on the Symfony UniversalClassLoader.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @see http://www.php-fig.org/psr/psr-0/
|
||||
* @see http://www.php-fig.org/psr/psr-4/
|
||||
*/
|
||||
class ClassLoader
|
||||
{
|
||||
// PSR-4
|
||||
private $prefixLengthsPsr4 = array();
|
||||
private $prefixDirsPsr4 = array();
|
||||
private $fallbackDirsPsr4 = array();
|
||||
|
||||
// PSR-0
|
||||
private $prefixesPsr0 = array();
|
||||
private $fallbackDirsPsr0 = array();
|
||||
|
||||
private $useIncludePath = false;
|
||||
private $classMap = array();
|
||||
private $classMapAuthoritative = false;
|
||||
private $missingClasses = array();
|
||||
private $apcuPrefix;
|
||||
|
||||
public function getPrefixes()
|
||||
{
|
||||
if (!empty($this->prefixesPsr0)) {
|
||||
return call_user_func_array('array_merge', $this->prefixesPsr0);
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
public function getPrefixesPsr4()
|
||||
{
|
||||
return $this->prefixDirsPsr4;
|
||||
}
|
||||
|
||||
public function getFallbackDirs()
|
||||
{
|
||||
return $this->fallbackDirsPsr0;
|
||||
}
|
||||
|
||||
public function getFallbackDirsPsr4()
|
||||
{
|
||||
return $this->fallbackDirsPsr4;
|
||||
}
|
||||
|
||||
public function getClassMap()
|
||||
{
|
||||
return $this->classMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $classMap Class to filename map
|
||||
*/
|
||||
public function addClassMap(array $classMap)
|
||||
{
|
||||
if ($this->classMap) {
|
||||
$this->classMap = array_merge($this->classMap, $classMap);
|
||||
} else {
|
||||
$this->classMap = $classMap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix, either
|
||||
* appending or prepending to the ones previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param array|string $paths The PSR-0 root directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*/
|
||||
public function add($prefix, $paths, $prepend = false)
|
||||
{
|
||||
if (!$prefix) {
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
(array) $paths,
|
||||
$this->fallbackDirsPsr0
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
$this->fallbackDirsPsr0,
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$first = $prefix[0];
|
||||
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
||||
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
|
||||
|
||||
return;
|
||||
}
|
||||
if ($prepend) {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
(array) $paths,
|
||||
$this->prefixesPsr0[$first][$prefix]
|
||||
);
|
||||
} else {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
$this->prefixesPsr0[$first][$prefix],
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace, either
|
||||
* appending or prepending to the ones previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param array|string $paths The PSR-4 base directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function addPsr4($prefix, $paths, $prepend = false)
|
||||
{
|
||||
if (!$prefix) {
|
||||
// Register directories for the root namespace.
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
(array) $paths,
|
||||
$this->fallbackDirsPsr4
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
$this->fallbackDirsPsr4,
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
||||
// Register directories for a new namespace.
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||
} elseif ($prepend) {
|
||||
// Prepend directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
(array) $paths,
|
||||
$this->prefixDirsPsr4[$prefix]
|
||||
);
|
||||
} else {
|
||||
// Append directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
$this->prefixDirsPsr4[$prefix],
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix,
|
||||
* replacing any others previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param array|string $paths The PSR-0 base directories
|
||||
*/
|
||||
public function set($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr0 = (array) $paths;
|
||||
} else {
|
||||
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace,
|
||||
* replacing any others previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param array|string $paths The PSR-4 base directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function setPsr4($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr4 = (array) $paths;
|
||||
} else {
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns on searching the include path for class files.
|
||||
*
|
||||
* @param bool $useIncludePath
|
||||
*/
|
||||
public function setUseIncludePath($useIncludePath)
|
||||
{
|
||||
$this->useIncludePath = $useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to check if the autoloader uses the include path to check
|
||||
* for classes.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getUseIncludePath()
|
||||
{
|
||||
return $this->useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns off searching the prefix and fallback directories for classes
|
||||
* that have not been registered with the class map.
|
||||
*
|
||||
* @param bool $classMapAuthoritative
|
||||
*/
|
||||
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||
{
|
||||
$this->classMapAuthoritative = $classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should class lookup fail if not found in the current class map?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isClassMapAuthoritative()
|
||||
{
|
||||
return $this->classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||
*
|
||||
* @param string|null $apcuPrefix
|
||||
*/
|
||||
public function setApcuPrefix($apcuPrefix)
|
||||
{
|
||||
$this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The APCu prefix in use, or null if APCu caching is not enabled.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getApcuPrefix()
|
||||
{
|
||||
return $this->apcuPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers this instance as an autoloader.
|
||||
*
|
||||
* @param bool $prepend Whether to prepend the autoloader or not
|
||||
*/
|
||||
public function register($prepend = false)
|
||||
{
|
||||
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters this instance as an autoloader.
|
||||
*/
|
||||
public function unregister()
|
||||
{
|
||||
spl_autoload_unregister(array($this, 'loadClass'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given class or interface.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
* @return bool|null True if loaded, null otherwise
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
if ($file = $this->findFile($class)) {
|
||||
includeFile($file);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the path to the file where the class is defined.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
*
|
||||
* @return string|false The path if found, false otherwise
|
||||
*/
|
||||
public function findFile($class)
|
||||
{
|
||||
// class map lookup
|
||||
if (isset($this->classMap[$class])) {
|
||||
return $this->classMap[$class];
|
||||
}
|
||||
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
||||
return false;
|
||||
}
|
||||
if (null !== $this->apcuPrefix) {
|
||||
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
||||
if ($hit) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
$file = $this->findFileWithExtension($class, '.php');
|
||||
|
||||
// Search for Hack files if we are running on HHVM
|
||||
if (false === $file && defined('HHVM_VERSION')) {
|
||||
$file = $this->findFileWithExtension($class, '.hh');
|
||||
}
|
||||
|
||||
if (null !== $this->apcuPrefix) {
|
||||
apcu_add($this->apcuPrefix.$class, $file);
|
||||
}
|
||||
|
||||
if (false === $file) {
|
||||
// Remember that this class does not exist.
|
||||
$this->missingClasses[$class] = true;
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
private function findFileWithExtension($class, $ext)
|
||||
{
|
||||
// PSR-4 lookup
|
||||
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
|
||||
|
||||
$first = $class[0];
|
||||
if (isset($this->prefixLengthsPsr4[$first])) {
|
||||
foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
|
||||
if (0 === strpos($class, $prefix)) {
|
||||
foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-4 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr4 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 lookup
|
||||
if (false !== $pos = strrpos($class, '\\')) {
|
||||
// namespaced class name
|
||||
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
||||
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
||||
} else {
|
||||
// PEAR-like class name
|
||||
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
|
||||
}
|
||||
|
||||
if (isset($this->prefixesPsr0[$first])) {
|
||||
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
||||
if (0 === strpos($class, $prefix)) {
|
||||
foreach ($dirs as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr0 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 include paths.
|
||||
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope isolated include.
|
||||
*
|
||||
* Prevents access to $this/self from included files.
|
||||
*/
|
||||
function includeFile($file)
|
||||
{
|
||||
include $file;
|
||||
}
|
21
vendor/composer/LICENSE
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
Copyright (c) 2016 Nils Adermann, Jordi Boggiano
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
9
vendor/composer/autoload_classmap.php
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
// autoload_classmap.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(dirname(__FILE__));
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
);
|
11
vendor/composer/autoload_files.php
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
// autoload_files.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(dirname(__FILE__));
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'c033e147fa8801d0fd8ea2bc8fa37e2a' => $baseDir . '/src/defines.php',
|
||||
'3b345cc3469552d097f31e5a67742144' => $baseDir . '/src/functions.php',
|
||||
);
|
9
vendor/composer/autoload_namespaces.php
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
// autoload_namespaces.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(dirname(__FILE__));
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
);
|
10
vendor/composer/autoload_psr4.php
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
// autoload_psr4.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(dirname(__FILE__));
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'Mos\\' => array($baseDir . '/src'),
|
||||
);
|
70
vendor/composer/autoload_real.php
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
// autoload_real.php @generated by Composer
|
||||
|
||||
class ComposerAutoloaderInit2b4448ad4be850d755525f1f201dede8
|
||||
{
|
||||
private static $loader;
|
||||
|
||||
public static function loadClassLoader($class)
|
||||
{
|
||||
if ('Composer\Autoload\ClassLoader' === $class) {
|
||||
require __DIR__ . '/ClassLoader.php';
|
||||
}
|
||||
}
|
||||
|
||||
public static function getLoader()
|
||||
{
|
||||
if (null !== self::$loader) {
|
||||
return self::$loader;
|
||||
}
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInit2b4448ad4be850d755525f1f201dede8', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInit2b4448ad4be850d755525f1f201dede8', 'loadClassLoader'));
|
||||
|
||||
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
||||
if ($useStaticLoader) {
|
||||
require_once __DIR__ . '/autoload_static.php';
|
||||
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInit2b4448ad4be850d755525f1f201dede8::getInitializer($loader));
|
||||
} else {
|
||||
$map = require __DIR__ . '/autoload_namespaces.php';
|
||||
foreach ($map as $namespace => $path) {
|
||||
$loader->set($namespace, $path);
|
||||
}
|
||||
|
||||
$map = require __DIR__ . '/autoload_psr4.php';
|
||||
foreach ($map as $namespace => $path) {
|
||||
$loader->setPsr4($namespace, $path);
|
||||
}
|
||||
|
||||
$classMap = require __DIR__ . '/autoload_classmap.php';
|
||||
if ($classMap) {
|
||||
$loader->addClassMap($classMap);
|
||||
}
|
||||
}
|
||||
|
||||
$loader->register(true);
|
||||
|
||||
if ($useStaticLoader) {
|
||||
$includeFiles = Composer\Autoload\ComposerStaticInit2b4448ad4be850d755525f1f201dede8::$files;
|
||||
} else {
|
||||
$includeFiles = require __DIR__ . '/autoload_files.php';
|
||||
}
|
||||
foreach ($includeFiles as $fileIdentifier => $file) {
|
||||
composerRequire2b4448ad4be850d755525f1f201dede8($fileIdentifier, $file);
|
||||
}
|
||||
|
||||
return $loader;
|
||||
}
|
||||
}
|
||||
|
||||
function composerRequire2b4448ad4be850d755525f1f201dede8($fileIdentifier, $file)
|
||||
{
|
||||
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
|
||||
require $file;
|
||||
|
||||
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
|
||||
}
|
||||
}
|
36
vendor/composer/autoload_static.php
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
// autoload_static.php @generated by Composer
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
class ComposerStaticInit2b4448ad4be850d755525f1f201dede8
|
||||
{
|
||||
public static $files = array (
|
||||
'c033e147fa8801d0fd8ea2bc8fa37e2a' => __DIR__ . '/../..' . '/src/defines.php',
|
||||
'3b345cc3469552d097f31e5a67742144' => __DIR__ . '/../..' . '/src/functions.php',
|
||||
);
|
||||
|
||||
public static $prefixLengthsPsr4 = array (
|
||||
'M' =>
|
||||
array (
|
||||
'Mos\\' => 4,
|
||||
),
|
||||
);
|
||||
|
||||
public static $prefixDirsPsr4 = array (
|
||||
'Mos\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/../..' . '/src',
|
||||
),
|
||||
);
|
||||
|
||||
public static function getInitializer(ClassLoader $loader)
|
||||
{
|
||||
return \Closure::bind(function () use ($loader) {
|
||||
$loader->prefixLengthsPsr4 = ComposerStaticInit2b4448ad4be850d755525f1f201dede8::$prefixLengthsPsr4;
|
||||
$loader->prefixDirsPsr4 = ComposerStaticInit2b4448ad4be850d755525f1f201dede8::$prefixDirsPsr4;
|
||||
|
||||
}, null, ClassLoader::class);
|
||||
}
|
||||
}
|
1
vendor/composer/installed.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[]
|
@@ -2,7 +2,7 @@
|
||||
|
||||
echo 'Current PHP version: ' . phpversion() . '<br><br>';
|
||||
|
||||
echo 'Running on: ' . $_SERVER['SERVER_SOFTWARE'] . '<br><br>';
|
||||
echo 'Running on: ' . htmlentities($_SERVER['SERVER_SOFTWARE']) . '<br><br>';
|
||||
|
||||
$no = extension_loaded('exif') ? null : 'NOT';
|
||||
echo "Extension exif is $no loaded.<br>";
|
||||
@@ -15,13 +15,15 @@ echo "Extension imagick is $no loaded.<br>";
|
||||
|
||||
$no = extension_loaded('gd') ? null : 'NOT';
|
||||
echo "Extension gd is $no loaded.<br>";
|
||||
|
||||
if (!$no) {
|
||||
echo "<pre>", var_dump(gd_info()), "</pre>";
|
||||
}
|
||||
|
||||
echo "<strong>Checking path for postprocessing tools</strong>";
|
||||
|
||||
echo "<br>pngquant: ";
|
||||
system("which pngquant");
|
||||
|
||||
echo "<br>optipng: ";
|
||||
system("which optipng");
|
||||
|
||||
|
@@ -4,7 +4,7 @@
|
||||
# The example is set up as following.
|
||||
#
|
||||
# img A directory where all images are stored
|
||||
# img/me.jpg Access a image as usually.
|
||||
# img/me.jpg Access a image as usual.
|
||||
# image/me.jpg Access a image though img.php using htaccess rewrite.
|
||||
# image/me.jpg?w=300 Using options to img.php.
|
||||
#
|
||||
|
367
webroot/img.php
@@ -8,45 +8,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
$version = "v0.7.8 (2015-12-06)";
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Display error message.
|
||||
*
|
||||
* @param string $msg to display.
|
||||
* @param int $type of HTTP error to display.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function errorPage($msg, $type = 500)
|
||||
{
|
||||
global $mode;
|
||||
|
||||
switch ($type) {
|
||||
case 403:
|
||||
$header = "403 Forbidden";
|
||||
break;
|
||||
case 404:
|
||||
$header = "404 Not Found";
|
||||
break;
|
||||
default:
|
||||
$header = "500 Internal Server Error";
|
||||
}
|
||||
|
||||
header("HTTP/1.0 $header");
|
||||
|
||||
if ($mode == 'development') {
|
||||
die("[img.php] $msg");
|
||||
}
|
||||
|
||||
error_log("[img.php] $msg");
|
||||
die("HTTP/1.0 $header");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Custom exception handler.
|
||||
*/
|
||||
@@ -56,95 +17,13 @@ set_exception_handler(function ($exception) {
|
||||
. $exception->getMessage()
|
||||
. "</p><pre>"
|
||||
. $exception->getTraceAsString()
|
||||
. "</pre>"
|
||||
, 500);
|
||||
. "</pre>",
|
||||
500
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get input from query string or return default value if not set.
|
||||
*
|
||||
* @param mixed $key as string or array of string values to look for in $_GET.
|
||||
* @param mixed $default value to return when $key is not set in $_GET.
|
||||
*
|
||||
* @return mixed value from $_GET or default value.
|
||||
*/
|
||||
function get($key, $default = null)
|
||||
{
|
||||
if (is_array($key)) {
|
||||
foreach ($key as $val) {
|
||||
if (isset($_GET[$val])) {
|
||||
return $_GET[$val];
|
||||
}
|
||||
}
|
||||
} elseif (isset($_GET[$key])) {
|
||||
return $_GET[$key];
|
||||
}
|
||||
return $default;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get input from query string and set to $defined if defined or else $undefined.
|
||||
*
|
||||
* @param mixed $key as string or array of string values to look for in $_GET.
|
||||
* @param mixed $defined value to return when $key is set in $_GET.
|
||||
* @param mixed $undefined value to return when $key is not set in $_GET.
|
||||
*
|
||||
* @return mixed value as $defined or $undefined.
|
||||
*/
|
||||
function getDefined($key, $defined, $undefined)
|
||||
{
|
||||
return get($key) === null ? $undefined : $defined;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get value from config array or default if key is not set in config array.
|
||||
*
|
||||
* @param string $key the key in the config array.
|
||||
* @param mixed $default value to be default if $key is not set in config.
|
||||
*
|
||||
* @return mixed value as $config[$key] or $default.
|
||||
*/
|
||||
function getConfig($key, $default)
|
||||
{
|
||||
global $config;
|
||||
return isset($config[$key])
|
||||
? $config[$key]
|
||||
: $default;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Log when verbose mode, when used without argument it returns the result.
|
||||
*
|
||||
* @param string $msg to log.
|
||||
*
|
||||
* @return void or array.
|
||||
*/
|
||||
function verbose($msg = null)
|
||||
{
|
||||
global $verbose, $verboseFile;
|
||||
static $log = array();
|
||||
|
||||
if (!($verbose || $verboseFile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_null($msg)) {
|
||||
return $log;
|
||||
}
|
||||
|
||||
$log[] = $msg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get configuration options from file, if the file exists, else use $config
|
||||
* if its defined or create an empty $config.
|
||||
@@ -157,6 +36,24 @@ if (is_file($configFile)) {
|
||||
$config = array();
|
||||
}
|
||||
|
||||
// Make CIMAGE_DEBUG false by default, if not already defined
|
||||
if (!defined("CIMAGE_DEBUG")) {
|
||||
define("CIMAGE_DEBUG", false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Setup the autoloader, but not when using a bundle.
|
||||
*/
|
||||
if (!defined("CIMAGE_BUNDLE")) {
|
||||
if (!isset($config["autoloader"])) {
|
||||
die("CImage: Missing autoloader.");
|
||||
}
|
||||
|
||||
require $config["autoloader"];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@@ -165,7 +62,7 @@ if (is_file($configFile)) {
|
||||
*/
|
||||
$verbose = getDefined(array('verbose', 'v'), true, false);
|
||||
$verboseFile = getDefined('vf', true, false);
|
||||
verbose("img.php version = $version");
|
||||
verbose("img.php version = " . CIMAGE_VERSION);
|
||||
|
||||
|
||||
|
||||
@@ -192,36 +89,28 @@ if (!extension_loaded('gd')) {
|
||||
|
||||
// Specific settings for each mode
|
||||
if ($mode == 'strict') {
|
||||
|
||||
error_reporting(0);
|
||||
ini_set('display_errors', 0);
|
||||
ini_set('log_errors', 1);
|
||||
$verbose = false;
|
||||
$status = false;
|
||||
$verboseFile = false;
|
||||
|
||||
} elseif ($mode == 'production') {
|
||||
|
||||
error_reporting(-1);
|
||||
ini_set('display_errors', 0);
|
||||
ini_set('log_errors', 1);
|
||||
$verbose = false;
|
||||
$status = false;
|
||||
$verboseFile = false;
|
||||
|
||||
} elseif ($mode == 'development') {
|
||||
|
||||
error_reporting(-1);
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('log_errors', 0);
|
||||
$verboseFile = false;
|
||||
|
||||
} elseif ($mode == 'test') {
|
||||
|
||||
error_reporting(-1);
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('log_errors', 0);
|
||||
|
||||
} else {
|
||||
errorPage("Unknown mode: $mode", 500);
|
||||
}
|
||||
@@ -256,7 +145,7 @@ $pwd = get(array('password', 'pwd'), null);
|
||||
// Check if passwords match, if configured to use passwords
|
||||
$passwordMatch = null;
|
||||
if ($pwd) {
|
||||
switch($pwdType) {
|
||||
switch ($pwdType) {
|
||||
case 'md5':
|
||||
$passwordMatch = ($pwdConfig === md5($pwd));
|
||||
break;
|
||||
@@ -311,7 +200,6 @@ if (!$allowHotlinking) {
|
||||
} else {
|
||||
errorPage("Hotlinking/leeching not allowed by whitelist. Referer: $referer.", 403);
|
||||
}
|
||||
|
||||
} else {
|
||||
errorPage("Hotlinking/leeching not allowed.", 403);
|
||||
}
|
||||
@@ -324,24 +212,58 @@ verbose("referer host = $refererHost");
|
||||
|
||||
|
||||
/**
|
||||
* Get the source files.
|
||||
* Create the class for the image.
|
||||
*/
|
||||
$autoloader = getConfig('autoloader', false);
|
||||
$cimageClass = getConfig('cimage_class', false);
|
||||
|
||||
if ($autoloader) {
|
||||
require $autoloader;
|
||||
} elseif ($cimageClass) {
|
||||
require $cimageClass;
|
||||
}
|
||||
$CImage = getConfig('CImage', '\Mos\CImage\CImage');
|
||||
$img = new $CImage();
|
||||
$img->setVerbose($verbose || $verboseFile);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create the class for the image.
|
||||
* Get the cachepath from config.
|
||||
*/
|
||||
$img = new CImage();
|
||||
$img->setVerbose($verbose || $verboseFile);
|
||||
$CCache = getConfig('CCache', '\Mos\CImage\CCache');
|
||||
$cachePath = getConfig('cache_path', __DIR__ . '/../cache/');
|
||||
$cache = new $CCache();
|
||||
$cache->setDir($cachePath);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* no-cache, nc - skip the cached version and process and create a new version in cache.
|
||||
*/
|
||||
$useCache = getDefined(array('no-cache', 'nc'), false, true);
|
||||
|
||||
verbose("use cache = $useCache");
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Prepare fast track cache for swriting cache items.
|
||||
*/
|
||||
$fastTrackCache = "fasttrack";
|
||||
$allowFastTrackCache = getConfig('fast_track_allow', false);
|
||||
|
||||
$CFastTrackCache = getConfig('CFastTrackCache', '\Mos\CImage\CFastTrackCache');
|
||||
$ftc = new $CFastTrackCache();
|
||||
$ftc->setCacheDir($cache->getPathToSubdir($fastTrackCache))
|
||||
->enable($allowFastTrackCache)
|
||||
->setFilename(array('no-cache', 'nc'));
|
||||
$img->injectDependency("fastTrackCache", $ftc);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Load and output images from fast track cache, if items are available
|
||||
* in cache.
|
||||
*/
|
||||
if ($useCache && $allowFastTrackCache) {
|
||||
if (CIMAGE_DEBUG) {
|
||||
trace("img.php fast track cache enabled and used");
|
||||
}
|
||||
$ftc->output();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -353,8 +275,10 @@ $img->setVerbose($verbose || $verboseFile);
|
||||
$allowRemote = getConfig('remote_allow', false);
|
||||
|
||||
if ($allowRemote && $passwordMatch !== false) {
|
||||
$cacheRemote = $cache->getPathToSubdir("remote");
|
||||
|
||||
$pattern = getConfig('remote_pattern', null);
|
||||
$img->setRemoteDownload($allowRemote, $pattern);
|
||||
$img->setRemoteDownload($allowRemote, $cacheRemote, $pattern);
|
||||
|
||||
$whitelist = getConfig('remote_whitelist', null);
|
||||
$img->setRemoteHostWhitelist($whitelist);
|
||||
@@ -374,8 +298,8 @@ $shortcutConfig = getConfig('shortcut', array(
|
||||
verbose("shortcut = $shortcut");
|
||||
|
||||
if (isset($shortcut)
|
||||
&& isset($shortcutConfig[$shortcut])) {
|
||||
|
||||
&& isset($shortcutConfig[$shortcut])
|
||||
) {
|
||||
parse_str($shortcutConfig[$shortcut], $get);
|
||||
verbose("shortcut-constant = {$shortcutConfig[$shortcut]}");
|
||||
$_GET = array_merge($_GET, $get);
|
||||
@@ -389,45 +313,73 @@ if (isset($shortcut)
|
||||
$srcImage = urldecode(get('src'))
|
||||
or errorPage('Must set src-attribute.', 404);
|
||||
|
||||
// Get settings for src-alt as backup image
|
||||
$srcAltImage = urldecode(get('src-alt', null));
|
||||
$srcAltConfig = getConfig('src_alt', null);
|
||||
if (empty($srcAltImage)) {
|
||||
$srcAltImage = $srcAltConfig;
|
||||
}
|
||||
|
||||
// Check for valid/invalid characters
|
||||
$imagePath = getConfig('image_path', __DIR__ . '/img/');
|
||||
$imagePathConstraint = getConfig('image_path_constraint', true);
|
||||
$validFilename = getConfig('valid_filename', '#^[a-z0-9A-Z-/_ \.:]+$#');
|
||||
|
||||
// Source is remote
|
||||
$remoteSource = false;
|
||||
|
||||
// Dummy image feature
|
||||
$dummyEnabled = getConfig('dummy_enabled', true);
|
||||
$dummyFilename = getConfig('dummy_filename', 'dummy');
|
||||
$dummyImage = false;
|
||||
|
||||
preg_match($validFilename, $srcImage)
|
||||
or errorPage('Filename contains invalid characters.', 404);
|
||||
or errorPage('Source filename contains invalid characters.', 404);
|
||||
|
||||
if ($dummyEnabled && $srcImage === $dummyFilename) {
|
||||
|
||||
// Prepare to create a dummy image and use it as the source image.
|
||||
$dummyImage = true;
|
||||
|
||||
} elseif ($allowRemote && $img->isRemoteSource($srcImage)) {
|
||||
|
||||
// If source is a remote file, ignore local file checks.
|
||||
|
||||
} elseif ($imagePathConstraint) {
|
||||
|
||||
// Check that the image is a file below the directory 'image_path'.
|
||||
$remoteSource = true;
|
||||
} else {
|
||||
// Check if file exists on disk or try using src-alt
|
||||
$pathToImage = realpath($imagePath . $srcImage);
|
||||
$imageDir = realpath($imagePath);
|
||||
|
||||
is_file($pathToImage)
|
||||
or errorPage(
|
||||
'Source image is not a valid file, check the filename and that a
|
||||
matching file exists on the filesystem.'
|
||||
, 404);
|
||||
if (!is_file($pathToImage) && !empty($srcAltImage)) {
|
||||
// Try using the src-alt instead
|
||||
$srcImage = $srcAltImage;
|
||||
$pathToImage = realpath($imagePath . $srcImage);
|
||||
|
||||
preg_match($validFilename, $srcImage)
|
||||
or errorPage('Source (alt) filename contains invalid characters.', 404);
|
||||
|
||||
if ($dummyEnabled && $srcImage === $dummyFilename) {
|
||||
// Check if src-alt is the dummy image
|
||||
$dummyImage = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$dummyImage) {
|
||||
is_file($pathToImage)
|
||||
or errorPage(
|
||||
'Source image is not a valid file, check the filename and that a
|
||||
matching file exists on the filesystem.',
|
||||
404
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($imagePathConstraint && !$dummyImage && !$remoteSource) {
|
||||
// Check that the image is a file below the directory 'image_path'.
|
||||
$imageDir = realpath($imagePath);
|
||||
|
||||
substr_compare($imageDir, $pathToImage, 0, strlen($imageDir)) == 0
|
||||
or errorPage(
|
||||
'Security constraint: Source image is not below the directory "image_path"
|
||||
as specified in the config file img_config.php.'
|
||||
, 404);
|
||||
as specified in the config file img_config.php.',
|
||||
404
|
||||
);
|
||||
}
|
||||
|
||||
verbose("src = $srcImage");
|
||||
@@ -646,23 +598,14 @@ $useOriginal = getDefined(array('skip-original', 'so'), false, true);
|
||||
$useOriginalDefault = getConfig('skip_original', false);
|
||||
|
||||
if ($useOriginalDefault === true) {
|
||||
verbose("use original is default ON");
|
||||
$useOriginal = true;
|
||||
verbose("skip original is default ON");
|
||||
$useOriginal = false;
|
||||
}
|
||||
|
||||
verbose("use original = $useOriginal");
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* no-cache, nc - skip the cached version and process and create a new version in cache.
|
||||
*/
|
||||
$useCache = getDefined(array('no-cache', 'nc'), false, true);
|
||||
|
||||
verbose("use cache = $useCache");
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* quality, q - set level of quality for jpeg images
|
||||
*/
|
||||
@@ -899,6 +842,9 @@ verbose("upscale = $upscale");
|
||||
* Get details for post processing
|
||||
*/
|
||||
$postProcessing = getConfig('postprocessing', array(
|
||||
'png_lossy' => false,
|
||||
'png_lossy_cmd' => '/usr/local/bin/pngquant --force --output',
|
||||
|
||||
'png_filter' => false,
|
||||
'png_filter_cmd' => '/usr/local/bin/optipng -q',
|
||||
|
||||
@@ -911,6 +857,15 @@ $postProcessing = getConfig('postprocessing', array(
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* lossy - Do lossy postprocessing, if available.
|
||||
*/
|
||||
$lossy = getDefined(array('lossy'), true, null);
|
||||
|
||||
verbose("lossy = $lossy");
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* alias - Save resulting image to another alias name.
|
||||
* Password always apply, must be defined.
|
||||
@@ -940,14 +895,7 @@ verbose("alias = $alias");
|
||||
|
||||
|
||||
/**
|
||||
* Get the cachepath from config.
|
||||
*/
|
||||
$cachePath = getConfig('cache_path', __DIR__ . '/../cache/');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the cachepath from config.
|
||||
* Add cache control HTTP header.
|
||||
*/
|
||||
$cacheControl = getConfig('cache_control', null);
|
||||
|
||||
@@ -961,11 +909,8 @@ if ($cacheControl) {
|
||||
/**
|
||||
* Prepare a dummy image and use it as source image.
|
||||
*/
|
||||
$dummyDir = getConfig('dummy_dir', $cachePath. "/" . $dummyFilename);
|
||||
|
||||
if ($dummyImage === true) {
|
||||
is_writable($dummyDir)
|
||||
or verbose("dummy dir not writable = $dummyDir");
|
||||
$dummyDir = $cache->getPathToSubdir("dummy");
|
||||
|
||||
$img->setSaveFolder($dummyDir)
|
||||
->setSource($dummyFilename, $dummyDir)
|
||||
@@ -993,24 +938,16 @@ if ($dummyImage === true) {
|
||||
/**
|
||||
* Prepare a sRGB version of the image and use it as source image.
|
||||
*/
|
||||
$srgbDirName = "/srgb";
|
||||
$srgbDir = realpath(getConfig('srgb_dir', $cachePath . $srgbDirName));
|
||||
$srgbDefault = getConfig('srgb_default', false);
|
||||
$srgbColorProfile = getConfig('srgb_colorprofile', __DIR__ . '/../icc/sRGB_IEC61966-2-1_black_scaled.icc');
|
||||
$srgb = getDefined('srgb', true, null);
|
||||
|
||||
if ($srgb || $srgbDefault) {
|
||||
|
||||
if (!is_writable($srgbDir)) {
|
||||
if (is_writable($cachePath)) {
|
||||
mkdir($srgbDir);
|
||||
}
|
||||
}
|
||||
|
||||
$filename = $img->convert2sRGBColorSpace(
|
||||
$srcImage,
|
||||
$imagePath,
|
||||
$srgbDir,
|
||||
$cache->getPathToSubdir("srgb"),
|
||||
$srgbColorProfile,
|
||||
$useCache
|
||||
);
|
||||
@@ -1030,13 +967,26 @@ if ($srgb || $srgbDefault) {
|
||||
* Display status
|
||||
*/
|
||||
if ($status) {
|
||||
$text = "img.php version = $version\n";
|
||||
$text = "img.php version = " . CIMAGE_VERSION . "\n";
|
||||
$text .= "PHP version = " . PHP_VERSION . "\n";
|
||||
$text .= "Running on: " . $_SERVER['SERVER_SOFTWARE'] . "\n";
|
||||
$text .= "Allow remote images = $allowRemote\n";
|
||||
$text .= "Cache writable = " . is_writable($cachePath) . "\n";
|
||||
$text .= "Cache dummy writable = " . is_writable($dummyDir) . "\n";
|
||||
$text .= "Cache srgb writable = " . is_writable($srgbDir) . "\n";
|
||||
|
||||
$res = $cache->getStatusOfSubdir("");
|
||||
$text .= "Cache $res\n";
|
||||
|
||||
$res = $cache->getStatusOfSubdir("remote");
|
||||
$text .= "Cache remote $res\n";
|
||||
|
||||
$res = $cache->getStatusOfSubdir("dummy");
|
||||
$text .= "Cache dummy $res\n";
|
||||
|
||||
$res = $cache->getStatusOfSubdir("srgb");
|
||||
$text .= "Cache srgb $res\n";
|
||||
|
||||
$res = $cache->getStatusOfSubdir($fastTrackCache);
|
||||
$text .= "Cache fasttrack $res\n";
|
||||
|
||||
$text .= "Alias path writable = " . is_writable($aliasPath) . "\n";
|
||||
|
||||
$no = extension_loaded('exif') ? null : 'NOT';
|
||||
@@ -1051,6 +1001,11 @@ if ($status) {
|
||||
$no = extension_loaded('gd') ? null : 'NOT';
|
||||
$text .= "Extension gd is $no loaded.<br>";
|
||||
|
||||
$text .= checkExternalCommand("PNG LOSSY", $postProcessing["png_lossy"], $postProcessing["png_lossy_cmd"]);
|
||||
$text .= checkExternalCommand("PNG FILTER", $postProcessing["png_filter"], $postProcessing["png_filter_cmd"]);
|
||||
$text .= checkExternalCommand("PNG DEFLATE", $postProcessing["png_deflate"], $postProcessing["png_deflate_cmd"]);
|
||||
$text .= checkExternalCommand("JPEG OPTIMIZE", $postProcessing["jpeg_optimize"], $postProcessing["jpeg_optimize_cmd"]);
|
||||
|
||||
if (!$no) {
|
||||
$text .= print_r(gd_info(), 1);
|
||||
}
|
||||
@@ -1119,6 +1074,7 @@ if (is_callable($hookBeforeCImage)) {
|
||||
|
||||
// Other
|
||||
'postProcessing' => $postProcessing,
|
||||
'lossy' => $lossy,
|
||||
));
|
||||
verbose(print_r($allConfig, 1));
|
||||
extract($allConfig);
|
||||
@@ -1166,7 +1122,7 @@ EOD;
|
||||
/**
|
||||
* Load, process and output the image
|
||||
*/
|
||||
$img->log("Incoming arguments: " . print_r(verbose(), 1))
|
||||
$res = $img->log("Incoming arguments: " . print_r(verbose(), 1))
|
||||
->setSaveFolder($cachePath)
|
||||
->useCache($useCache)
|
||||
->setSource($srcImage, $imagePath)
|
||||
@@ -1203,6 +1159,9 @@ $img->log("Incoming arguments: " . print_r(verbose(), 1))
|
||||
// Output format
|
||||
'outputFormat' => $outputFormat,
|
||||
'dpr' => $dpr,
|
||||
|
||||
// Postprocessing using external tools
|
||||
'lossy' => $lossy,
|
||||
)
|
||||
)
|
||||
->loadImageDetails()
|
||||
@@ -1222,3 +1181,5 @@ $img->log("Incoming arguments: " . print_r(verbose(), 1))
|
||||
->save()
|
||||
->linkToCacheFile($aliasTarget)
|
||||
->output();
|
||||
|
||||
return $res;
|
||||
|
BIN
webroot/img/apple.jpg
Normal file
After Width: | Height: | Size: 16 KiB |
171
webroot/img/drawing.svg
Normal file
@@ -0,0 +1,171 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="210mm"
|
||||
height="297mm"
|
||||
viewBox="0 0 744.09448819 1052.3622047"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="drawing.svg">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="2"
|
||||
inkscape:cx="76.428572"
|
||||
inkscape:cy="-22.526694"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="919"
|
||||
inkscape:window-height="416"
|
||||
inkscape:window-x="167"
|
||||
inkscape:window-y="177"
|
||||
inkscape:window-maximized="0" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<rect
|
||||
style="fill:#e6e6e6;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
id="rect4146"
|
||||
width="100"
|
||||
height="100"
|
||||
x="-7.4924429e-08"
|
||||
y="952.36218"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<path
|
||||
style="fill:#009600;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
d="m 0,952.3622 0,20 20,0 0,-20 -20,0 z"
|
||||
id="rect4136"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4140"
|
||||
d="m 166,948.8622 0,10 10,0 0,-10 -10,0 z"
|
||||
style="fill:#009600;fill-opacity:1;stroke:none;stroke-opacity:1" />
|
||||
<path
|
||||
style="fill:#009600;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
d="m 185.5,949.3622 0,10 10,0 0,-10 -10,0 z"
|
||||
id="path4142"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4144"
|
||||
d="m 201.5,949.8622 0,10 10,0 0,-10 -10,0 z"
|
||||
style="fill:#009600;fill-opacity:1;stroke:none;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4148"
|
||||
d="m 40,952.3622 0,20 20,0 0,-20 -20,0 z"
|
||||
style="fill:#ffff00;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<path
|
||||
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
d="m 80,952.3622 0,20 20,0 0,-20 -20,0 z"
|
||||
id="path4150"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4152"
|
||||
d="m 20,972.3622 0,20 20,0 0,-20 -20,0 z"
|
||||
style="fill:#00ffff;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<path
|
||||
style="fill:#000080;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
d="m 60,972.3622 0,20 20,0 0,-20 -20,0 z"
|
||||
id="path4154"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4156"
|
||||
d="m 0,992.3622 0,20 20,0 0,-20 -20,0 z"
|
||||
style="fill:#009600;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<path
|
||||
style="fill:#ffff00;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
d="m 40,992.3622 0,20 20,0 0,-20 -20,0 z"
|
||||
id="path4158"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4160"
|
||||
d="m 80,992.3622 0,20 20,0 0,-20 -20,0 z"
|
||||
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<path
|
||||
style="fill:#00ffff;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
d="m 20,1012.3622 0,20 20,0 0,-20 -20,0 z"
|
||||
id="path4162"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4164"
|
||||
d="m 60,1012.3622 0,20 20,0 0,-20 -20,0 z"
|
||||
style="fill:#000080;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4166"
|
||||
d="m 0,1032.3622 0,20 20,0 0,-20 -20,0 z"
|
||||
style="fill:#009600;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<path
|
||||
style="fill:#ffff00;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
d="m 40,1032.3622 0,20 20,0 0,-20 -20,0 z"
|
||||
id="path4168"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4170"
|
||||
d="m 80,1032.3622 0,20 20,0 0,-20 -20,0 z"
|
||||
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.7 KiB |
BIN
webroot/img/duke.png
Normal file
After Width: | Height: | Size: 228 KiB |
BIN
webroot/img/lena.jpg
Normal file
After Width: | Height: | Size: 395 KiB |
BIN
webroot/img/lena.png
Normal file
After Width: | Height: | Size: 464 KiB |
BIN
webroot/img/lena.tif
Normal file
BIN
webroot/img/lena.webp
Normal file
After Width: | Height: | Size: 131 KiB |
BIN
webroot/img/planet.gif
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
webroot/img/test_100x100.png
Normal file
After Width: | Height: | Size: 445 B |
BIN
webroot/img/tower.jpg
Normal file
After Width: | Height: | Size: 104 KiB |
BIN
webroot/img/webp/1.webp
Normal file
After Width: | Height: | Size: 30 KiB |
@@ -5,46 +5,102 @@
|
||||
* config-file imgtest_config.php.
|
||||
*
|
||||
*/
|
||||
return array(
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Change to true to enable debug mode which logs additional information
|
||||
* to file. Only use for test and development. You must create the logfile
|
||||
* and make it writable by the webserver or log entries will silently fail.
|
||||
*
|
||||
* CIMAGE_DEBUG will be false by default, if its not defined.
|
||||
*/
|
||||
if (!defined("CIMAGE_DEBUG")) {
|
||||
define("CIMAGE_DEBUG", false);
|
||||
//define("CIMAGE_DEBUG", true);
|
||||
define("CIMAGE_DEBUG_FILE", "/tmp/cimage");
|
||||
}
|
||||
|
||||
|
||||
|
||||
return [
|
||||
|
||||
/**
|
||||
* Set mode as 'strict', 'production' or 'development'.
|
||||
*
|
||||
* development: Development mode with verbose error reporting. Option
|
||||
* &verbose and &status enabled.
|
||||
* production: Production mode logs all errors to file, giving server
|
||||
* error 500 for bad usage. Option &verbose and &status
|
||||
* disabled.
|
||||
* strict: Strict mode logs few errors to file, giving server error
|
||||
* 500 for bad usage. Stripped from comments and spaces.
|
||||
* Option &verbose and &status disabled.
|
||||
*
|
||||
* Default values:
|
||||
* mode: 'production'
|
||||
*/
|
||||
//'mode' => 'production', // 'development', 'strict'
|
||||
//'mode' => 'development', // 'development', 'strict'
|
||||
//'mode' => 'production',
|
||||
'mode' => 'development',
|
||||
//'mode' => 'strict',
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Where are the sources for the classfiles.
|
||||
* Where to find the autoloader.
|
||||
*
|
||||
* Default values:
|
||||
* autoloader: null // used from v0.6.2
|
||||
* cimage_class: null // used until v0.6.1
|
||||
* autoloader: null
|
||||
*/
|
||||
'autoloader' => __DIR__ . '/../autoload.php',
|
||||
//'cimage_class' => __DIR__ . '/../CImage.php',
|
||||
//'autoloader' => __DIR__ . '/../autoload.php',
|
||||
'autoloader' => __DIR__ . '/../vendor/autoload.php',
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Paths, where are the images stored and where is the cache.
|
||||
* Path to aliases, useful when downloading external images and you
|
||||
* want to create a local copy of the file, a alias file.
|
||||
* End all paths with a slash.
|
||||
*
|
||||
* Default values:
|
||||
* image_path: __DIR__ . '/img/'
|
||||
* cache_path: __DIR__ . '/../cache/'
|
||||
* alias_path: null
|
||||
* image_path: __DIR__ . '/img/'
|
||||
* cache_path: __DIR__ . '/../cache/'
|
||||
* alias_path: null
|
||||
*/
|
||||
'image_path' => __DIR__ . '/img/',
|
||||
'cache_path' => __DIR__ . '/../cache/',
|
||||
'image_path' => __DIR__ . '/img/',
|
||||
'cache_path' => __DIR__ . '/../cache/',
|
||||
//'alias_path' => __DIR__ . '/img/alias/',
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Fast track cache. Save a json representation of the image as a
|
||||
* fast track to the cached version of the image. This avoids some
|
||||
* processing and allows for quicker load times of cached images.
|
||||
*
|
||||
* Default values:
|
||||
* fast_track_allow: false
|
||||
*/
|
||||
//'fast_track_allow' => true,
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Class names to use, to ease dependency injection. You can change Class
|
||||
* name if you want to use your own class instead. This is a way to extend
|
||||
* the codebase.
|
||||
*
|
||||
* Default values:
|
||||
* CImage: \Mos\CImage\CImage
|
||||
* CCache: \Mos\CImage\CCache
|
||||
* CFastTrackCache: \Mos\CImage\CFastTrackCache
|
||||
*/
|
||||
//'CImage' => '\Mos\CImage\CImage',
|
||||
//'CCache' => '\Mos\CImage\CCache',
|
||||
//'CFastTrackCache' => '\Mos\CImage\CFastTrackCache',
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Use password to protect from missusage, send &pwd=... or &password=..
|
||||
* with the request to match the password or set to false to disable.
|
||||
@@ -87,13 +143,28 @@ return array(
|
||||
* remote_whitelist: null // use default values from CImage which is to
|
||||
* // allow download from any hosts.
|
||||
*/
|
||||
//'remote_allow' => true,
|
||||
//'remote_pattern' => '#^https?://#',
|
||||
//'remote_whitelist' => array(
|
||||
// '\.facebook\.com$',
|
||||
// '^(?:images|photos-[a-z])\.ak\.instagram\.com$',
|
||||
// '\.google\.com$'
|
||||
//),
|
||||
/*
|
||||
'remote_allow' => true,
|
||||
'remote_pattern' => '#^https?://#',
|
||||
'remote_whitelist' => [
|
||||
'\.facebook\.com$',
|
||||
'^(?:images|photos-[a-z])\.ak\.instagram\.com$',
|
||||
'\.google\.com$'
|
||||
], */
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Use backup image if src-image is not found on disk. The backup image
|
||||
* is only available for local images and based on wether the original
|
||||
* image is found on disk or not. The backup image must be a local image
|
||||
* or the dummy image.
|
||||
*
|
||||
* Default value:
|
||||
* src_alt: null //disabled by default
|
||||
*/
|
||||
//'src_alt' => 'car.png',
|
||||
//'src_alt' => 'dummy',
|
||||
|
||||
|
||||
|
||||
@@ -114,32 +185,44 @@ return array(
|
||||
* when saving images.
|
||||
*
|
||||
* Default value:
|
||||
* jpg_quality: null, integer between 0-100
|
||||
* png_compression: null, integer between 0-9
|
||||
* jpg_quality: null, integer between 0-100,
|
||||
* default is 60
|
||||
* png_compression: null, integer between 0-9,
|
||||
* default is -1 (PHP GD decides)
|
||||
*/
|
||||
//'jpg_quality' => 75,
|
||||
//'png_compression' => 1,
|
||||
//'jpg_quality' => 60,
|
||||
//'png_compression' => -1,
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Convert the image to srgb before processing. Saves the converted
|
||||
* image in the sub cache dir. This option is default false but can
|
||||
* be changed to default true to do this conversion for all images.
|
||||
* Convert the image to sRGB before processing. Saves the converted
|
||||
* image in a cache subdir 'srgb'. This option is default false but can
|
||||
* be changed to default true to always do conversion for all images.
|
||||
* This option requires PHP extension imagick and will silently fail
|
||||
* if that is not installed.
|
||||
*
|
||||
* Default value:
|
||||
* srgb_dir: $cachePath/srgb
|
||||
* srgb_default: false
|
||||
* srgb_colorprofile: __DIR__ . '/../icc/sRGB_IEC61966-2-1_black_scaled.icc'
|
||||
*/
|
||||
//'srgb_dir' => __DIR__ . '/../cache/srgb/',
|
||||
//'srgb_default' => false,
|
||||
//'srgb_colorprofile' => __DIR__ . '/../icc/sRGB_IEC61966-2-1_black_scaled.icc',
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set skip-original to true to always process the image and use
|
||||
* the cached version. Default is false and to use the original
|
||||
* image when its no processing needed.
|
||||
*
|
||||
* Default value:
|
||||
* skip_original: false
|
||||
*/
|
||||
//'skip_original' => true,
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A function (hook) can be called after img.php has processed all
|
||||
* configuration options and before processing the image using CImage.
|
||||
@@ -170,30 +253,27 @@ return array(
|
||||
|
||||
/**
|
||||
* The name representing a dummy image which is automatically created
|
||||
* and stored at the defined path. The dummy image can then be used
|
||||
* inplace of an original image as a placeholder.
|
||||
* The dummy_dir must be writable and it defaults to a subdir of the
|
||||
* cache directory.
|
||||
* Write protect the dummy_dir to prevent creation of new dummy images,
|
||||
* but continue to use the existing ones.
|
||||
* and stored as a image in the dir CACHE_PATH/dummy. The dummy image
|
||||
* can then be used as a placeholder image.
|
||||
* The dir CACHE_PATH/dummy is automatically created when needed.
|
||||
* Write protect the CACHE_PATH/dummy to prevent creation of new
|
||||
* dummy images, but continue to use the existing ones.
|
||||
*
|
||||
* Default value:
|
||||
* dummy_enabled: true as default, disable dummy feature by setting
|
||||
* to false.
|
||||
* dummy_filename: 'dummy' use this as ?src=dummy to create a dummy image.
|
||||
* dummy_dir: Defaults to subdirectory of 'cache_path',
|
||||
* named the same as 'dummy_filename'
|
||||
*/
|
||||
//'dummy_enabled' => true,
|
||||
//'dummy_filename' => 'dummy',
|
||||
//'dummy_dir' => 'some writable directory',
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Check that the imagefile is a file below 'image_path' using realpath().
|
||||
* Security constraint to avoid reaching images outside image_path.
|
||||
* This means that symbolic links to images outside the image_path will fail.
|
||||
* This means that symbolic links to images outside the image_path will
|
||||
* fail.
|
||||
*
|
||||
* Default value:
|
||||
* image_path_constraint: true
|
||||
@@ -246,8 +326,16 @@ return array(
|
||||
* Post processing of images using external tools, set to true or false
|
||||
* and set command to be executed.
|
||||
*
|
||||
* The png_lossy can alos have a value of null which means that its
|
||||
* enabled but not used as default. Each image having the option
|
||||
* &lossy will be processed. This means one can individually choose
|
||||
* when to use the lossy processing.
|
||||
*
|
||||
* Default values.
|
||||
*
|
||||
* png_lossy: false
|
||||
* png_lossy_cmd: '/usr/local/bin/pngquant --force --output'
|
||||
*
|
||||
* png_filter: false
|
||||
* png_filter_cmd: '/usr/local/bin/optipng -q'
|
||||
*
|
||||
@@ -258,7 +346,10 @@ return array(
|
||||
* jpeg_optimize_cmd: '/usr/local/bin/jpegtran -copy none -optimize'
|
||||
*/
|
||||
/*
|
||||
'postprocessing' => array(
|
||||
'postprocessing' => [
|
||||
'png_lossy' => null,
|
||||
'png_lossy_cmd' => '/usr/local/bin/pngquant --force --output',
|
||||
|
||||
'png_filter' => false,
|
||||
'png_filter_cmd' => '/usr/local/bin/optipng -q',
|
||||
|
||||
@@ -267,7 +358,7 @@ return array(
|
||||
|
||||
'jpeg_optimize' => false,
|
||||
'jpeg_optimize_cmd' => '/usr/local/bin/jpegtran -copy none -optimize',
|
||||
),
|
||||
],
|
||||
*/
|
||||
|
||||
|
||||
@@ -277,13 +368,13 @@ return array(
|
||||
* offset.
|
||||
*
|
||||
* Default values.
|
||||
* convolution_constant: array()
|
||||
* convolution_constant: []
|
||||
*/
|
||||
/*
|
||||
'convolution_constant' => array(
|
||||
'convolution_constant' => [
|
||||
//'sharpen' => '-1,-1,-1, -1,16,-1, -1,-1,-1, 8, 0',
|
||||
//'sharpen-alt' => '0,-1,0, -1,5,-1, 0,-1,0, 1, 0',
|
||||
),
|
||||
],
|
||||
*/
|
||||
|
||||
|
||||
@@ -300,13 +391,13 @@ return array(
|
||||
*
|
||||
* Default values.
|
||||
* allow_hotlinking: true
|
||||
* hotlinking_whitelist: array()
|
||||
* hotlinking_whitelist: []
|
||||
*/
|
||||
/*
|
||||
'allow_hotlinking' => false,
|
||||
'hotlinking_whitelist' => array(
|
||||
'hotlinking_whitelist' => [
|
||||
'^dbwebb\.se$',
|
||||
),
|
||||
],
|
||||
*/
|
||||
|
||||
|
||||
@@ -314,14 +405,14 @@ return array(
|
||||
* Create custom shortcuts for more advanced expressions.
|
||||
*
|
||||
* Default values.
|
||||
* shortcut: array(
|
||||
* shortcut: [
|
||||
* 'sepia' => "&f=grayscale&f0=brightness,-10&f1=contrast,-20&f2=colorize,120,60,0,0&sharpen",
|
||||
* )
|
||||
* ]
|
||||
*/
|
||||
/*
|
||||
'shortcut' => array(
|
||||
'shortcut' => [
|
||||
'sepia' => "&f=grayscale&f0=brightness,-10&f1=contrast,-20&f2=colorize,120,60,0,0&sharpen",
|
||||
),*/
|
||||
],*/
|
||||
|
||||
|
||||
|
||||
@@ -344,10 +435,10 @@ return array(
|
||||
'size_constant' => function () {
|
||||
|
||||
// Set sizes to map constant to value, easier to use with width or height
|
||||
$sizes = array(
|
||||
'w1' => 613,
|
||||
'w2' => 630,
|
||||
);
|
||||
$sizes = [
|
||||
'w1' => 613,
|
||||
'w2' => 630,
|
||||
];
|
||||
|
||||
// Add grid column width, useful for use as predefined size for width (or height).
|
||||
$gridColumnWidth = 30;
|
||||
@@ -370,7 +461,7 @@ return array(
|
||||
* aspect_ratio_constant: As the function below.
|
||||
*/
|
||||
/*'aspect_ratio_constant' => function () {
|
||||
return array(
|
||||
return [
|
||||
'3:1' => 3/1,
|
||||
'3:2' => 3/2,
|
||||
'4:3' => 4/3,
|
||||
@@ -378,13 +469,13 @@ return array(
|
||||
'16:10' => 16/10,
|
||||
'16:9' => 16/9,
|
||||
'golden' => 1.618,
|
||||
);
|
||||
];
|
||||
},*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* default options for ascii image.
|
||||
* Default options for ascii image.
|
||||
*
|
||||
* Default values as specified below in the array.
|
||||
* ascii-options:
|
||||
@@ -394,11 +485,11 @@ return array(
|
||||
* luminanceStrategy: Choose any strategy available in CAsciiArt.
|
||||
* customCharacterSet: Define your own character set.
|
||||
*/
|
||||
/*'ascii-options' => array(
|
||||
/*'ascii-options' => [
|
||||
"characterSet" => 'two',
|
||||
"scale" => 14,
|
||||
"luminanceStrategy" => 3,
|
||||
"customCharacterSet" => null,
|
||||
);
|
||||
},*/
|
||||
);
|
||||
],*/
|
||||
];
|
||||
|
@@ -10,6 +10,7 @@
|
||||
* @link https://github.com/mosbth/cimage
|
||||
*
|
||||
*/
|
||||
define("CIMAGE_BUNDLE", true);
|
||||
|
||||
|
||||
/**
|
||||
|
1216
webroot/imgd.php
91
webroot/imgf.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
/**
|
||||
* Fast track cache, read entries from the cache before processing image
|
||||
* the ordinary way.
|
||||
*/
|
||||
// Load the config file or use defaults
|
||||
$configFile = __DIR__
|
||||
. "/"
|
||||
. basename(__FILE__, ".php")
|
||||
. "_config.php";
|
||||
|
||||
if (is_file($configFile) && is_readable($configFile)) {
|
||||
$config = require $configFile;
|
||||
} elseif (!isset($config)) {
|
||||
$config = array(
|
||||
"fast_track_allow" => true,
|
||||
"autoloader" => __DIR__ . "/../autoload.php",
|
||||
"cache_path" => __DIR__ . "/../cache/",
|
||||
);
|
||||
}
|
||||
|
||||
// Make CIMAGE_DEBUG false by default, if not already defined
|
||||
if (!defined("CIMAGE_DEBUG")) {
|
||||
define("CIMAGE_DEBUG", false);
|
||||
}
|
||||
|
||||
// Debug mode needs additional functions
|
||||
if (CIMAGE_DEBUG) {
|
||||
require $config["autoloader"];
|
||||
}
|
||||
|
||||
// Cache path must be valid
|
||||
$cacheIsReadable = is_dir($config["cache_path"]) && is_readable($config["cache_path"]);
|
||||
if (!$cacheIsReadable) {
|
||||
die("imgf.php: Cache is not readable, check path in configfile.");
|
||||
}
|
||||
|
||||
// Prepare to check if fast cache should be used
|
||||
$cachePath = $config["cache_path"] . "/fasttrack";
|
||||
$query = $_GET;
|
||||
|
||||
// Do not use cache when no-cache is active
|
||||
$useCache = !(array_key_exists("no-cache", $query) || array_key_exists("nc", $query));
|
||||
|
||||
// Only use cache if enabled by configuration
|
||||
$useCache = $useCache && isset($config["fast_track_allow"]) && $config["fast_track_allow"] === true;
|
||||
|
||||
// Remove parts from querystring that should not be part of filename
|
||||
$clear = array("nc", "no-cache");
|
||||
foreach ($clear as $value) {
|
||||
unset($query[$value]);
|
||||
}
|
||||
|
||||
// Create the cache filename
|
||||
arsort($query);
|
||||
$queryAsString = http_build_query($query);
|
||||
$filename = md5($queryAsString);
|
||||
$filename = "$cachePath/$filename";
|
||||
|
||||
// Check cached item, if any
|
||||
if ($useCache && is_readable($filename)) {
|
||||
$item = json_decode(file_get_contents($filename), true);
|
||||
|
||||
if (is_readable($item["source"])) {
|
||||
foreach ($item["header"] as $value) {
|
||||
header($value);
|
||||
}
|
||||
|
||||
if (isset($_SERVER["HTTP_IF_MODIFIED_SINCE"])
|
||||
&& strtotime($_SERVER["HTTP_IF_MODIFIED_SINCE"]) == $item["last-modified"]) {
|
||||
header("HTTP/1.0 304 Not Modified");
|
||||
if (CIMAGE_DEBUG) {
|
||||
trace("imgf 304");
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
foreach ($item["header-output"] as $value) {
|
||||
header($value);
|
||||
}
|
||||
|
||||
if (CIMAGE_DEBUG) {
|
||||
trace("imgf 200");
|
||||
}
|
||||
readfile($item["source"]);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
// No fast track cache, proceed as usual
|
||||
include __DIR__ . "/img.php";
|
1
webroot/imgf_config.php
Symbolic link
@@ -0,0 +1 @@
|
||||
img_config.php
|
1216
webroot/imgp.php
58
webroot/test/option-no-upscale.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
// Include config for all testcases
|
||||
include __DIR__ . "/config.php";
|
||||
|
||||
|
||||
|
||||
// The title of the test case
|
||||
$title = "Testing option no-upscale";
|
||||
|
||||
|
||||
|
||||
// Provide a short description of the testcase.
|
||||
$description = "Do not upscale image when original image (slice) is smaller than target image.";
|
||||
|
||||
|
||||
|
||||
// Use these images in the test
|
||||
$images = array(
|
||||
'car.png',
|
||||
'apple.jpg',
|
||||
'tower.jpg',
|
||||
);
|
||||
|
||||
|
||||
|
||||
// For each image, apply these testcases
|
||||
$nc = "&bgc=660000&nc"; //null; //"&nc"; //null; //&nc';
|
||||
$testcase = array(
|
||||
$nc . '&w=600',
|
||||
$nc . '&w=600&no-upscale',
|
||||
$nc . '&h=420',
|
||||
$nc . '&h=420&no-upscale',
|
||||
$nc . '&w=600&h=420',
|
||||
$nc . '&w=600&h=420&no-upscale',
|
||||
$nc . '&w=700&h=420&stretch',
|
||||
$nc . '&w=700&h=420&no-upscale&stretch',
|
||||
$nc . '&w=700&h=200&stretch',
|
||||
$nc . '&w=700&h=200&no-upscale&stretch',
|
||||
$nc . '&w=250&h=420&stretch',
|
||||
$nc . '&w=250&h=420&no-upscale&stretch',
|
||||
$nc . '&w=700&h=420&crop-to-fit',
|
||||
$nc . '&w=700&h=420&no-upscale&crop-to-fit',
|
||||
$nc . '&w=700&h=200&crop-to-fit',
|
||||
$nc . '&w=700&h=200&no-upscale&crop-to-fit',
|
||||
$nc . '&w=250&h=420&crop-to-fit',
|
||||
$nc . '&w=250&h=420&no-upscale&crop-to-fit',
|
||||
$nc . '&w=600&h=500&fill-to-fit',
|
||||
$nc . '&w=600&h=500&no-upscale&fill-to-fit',
|
||||
$nc . '&w=250&h=420&fill-to-fit',
|
||||
$nc . '&w=250&h=420&no-upscale&fill-to-fit',
|
||||
$nc . '&w=700&h=420&fill-to-fit',
|
||||
$nc . '&w=700&h=420&no-upscale&fill-to-fit',
|
||||
);
|
||||
|
||||
|
||||
|
||||
// Apply testcases and present results
|
||||
include __DIR__ . "/template.php";
|
43
webroot/test/resize-landscape.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
// Include config for all testcases
|
||||
include __DIR__ . "/config.php";
|
||||
|
||||
|
||||
|
||||
// The title of the test case
|
||||
$title = "Testing resize landscape image";
|
||||
|
||||
|
||||
|
||||
// Provide a short description of the testcase.
|
||||
$description = "Resize landscape image";
|
||||
|
||||
|
||||
|
||||
// Use these images in the test
|
||||
$images = array(
|
||||
'car.png',
|
||||
);
|
||||
|
||||
|
||||
|
||||
// For each image, apply these testcases
|
||||
$nc = empty($_SERVER['QUERY_STRING']) ? "" : "&" . $_SERVER['QUERY_STRING'];
|
||||
|
||||
$testcase = array(
|
||||
$nc . '&w=500',
|
||||
$nc . '&h=200',
|
||||
$nc . '&w=500&h=500',
|
||||
$nc . '&w=500&h=200',
|
||||
$nc . '&w=500&h=200&crop-to-fit',
|
||||
$nc . '&w=200&h=500&crop-to-fit',
|
||||
$nc . '&w=500&h=200&fill-to-fit',
|
||||
$nc . '&w=200&h=500&fill-to-fit',
|
||||
$nc . '&w=500&h=200&stretch',
|
||||
$nc . '&w=200&h=500&stretch',
|
||||
);
|
||||
|
||||
|
||||
|
||||
// Apply testcases and present results
|
||||
include __DIR__ . "/template.php";
|
43
webroot/test/resize-portrait.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
// Include config for all testcases
|
||||
include __DIR__ . "/config.php";
|
||||
|
||||
|
||||
|
||||
// The title of the test case
|
||||
$title = "Testing resize portrait image";
|
||||
|
||||
|
||||
|
||||
// Provide a short description of the testcase.
|
||||
$description = "Resize portrait image";
|
||||
|
||||
|
||||
|
||||
// Use these images in the test
|
||||
$images = array(
|
||||
'kodim04.png',
|
||||
);
|
||||
|
||||
|
||||
|
||||
// For each image, apply these testcases
|
||||
$nc = empty($_SERVER['QUERY_STRING']) ? "" : "&" . $_SERVER['QUERY_STRING'];
|
||||
|
||||
$testcase = array(
|
||||
$nc . '&w=500',
|
||||
$nc . '&h=200',
|
||||
$nc . '&w=500&h=500',
|
||||
$nc . '&w=500&h=200',
|
||||
$nc . '&w=500&h=200&crop-to-fit',
|
||||
$nc . '&w=200&h=500&crop-to-fit',
|
||||
$nc . '&w=500&h=200&fill-to-fit',
|
||||
$nc . '&w=200&h=500&fill-to-fit',
|
||||
$nc . '&w=500&h=200&stretch',
|
||||
$nc . '&w=200&h=500&stretch',
|
||||
);
|
||||
|
||||
|
||||
|
||||
// Apply testcases and present results
|
||||
include __DIR__ . "/template.php";
|
@@ -1,58 +0,0 @@
|
||||
<?php
|
||||
// Include config for all testcases
|
||||
include __DIR__ . "/config.php";
|
||||
|
||||
|
||||
|
||||
// The title of the test case
|
||||
$title = "Testing option no-upscale";
|
||||
|
||||
|
||||
|
||||
// Provide a short description of the testcase.
|
||||
$description = "Do not upscale image when original image (slice) is smaller than target image.";
|
||||
|
||||
|
||||
|
||||
// Use these images in the test
|
||||
$images = array(
|
||||
'car.png',
|
||||
);
|
||||
|
||||
|
||||
|
||||
// For each image, apply these testcases
|
||||
$nc = null; //"&nc"; //null; //&nc';
|
||||
$testcase = array(
|
||||
$nc . '&w=600',
|
||||
$nc . '&w=600&no-upscale',
|
||||
$nc . '&h=400',
|
||||
$nc . '&h=400&no-upscale',
|
||||
$nc . '&w=600&h=400',
|
||||
$nc . '&w=600&h=400&no-upscale',
|
||||
$nc . '&w=700&h=400&stretch',
|
||||
$nc . '&w=700&h=400&no-upscale&stretch',
|
||||
$nc . '&w=700&h=200&stretch',
|
||||
$nc . '&w=700&h=200&no-upscale&stretch',
|
||||
$nc . '&w=300&h=400&stretch',
|
||||
$nc . '&w=300&h=400&no-upscale&stretch',
|
||||
$nc . '&w=600&h=400&crop-to-fit',
|
||||
$nc . '&w=600&h=400&no-upscale&crop-to-fit',
|
||||
$nc . '&w=600&h=200&crop-to-fit',
|
||||
$nc . '&w=600&h=200&no-upscale&crop-to-fit',
|
||||
$nc . '&w=300&h=400&crop-to-fit',
|
||||
$nc . '&w=300&h=400&no-upscale&crop-to-fit',
|
||||
$nc . '&w=600&h=400&fill-to-fit',
|
||||
$nc . '&w=600&h=400&no-upscale&fill-to-fit',
|
||||
/*
|
||||
$nc . '&w=600&ar=1.6',
|
||||
$nc . '&w=600&ar=1.6&no-upscale',
|
||||
$nc . '&h=400&ar=1.6',
|
||||
$nc . '&h=400&ar=1.6&no-upscale',
|
||||
*/
|
||||
);
|
||||
|
||||
|
||||
|
||||
// Apply testcases and present results
|
||||
include __DIR__ . "/template.php";
|