1
0
mirror of https://github.com/mosbth/cimage.git synced 2025-08-26 09:04:26 +02:00

Compare commits

..

38 Commits

Author SHA1 Message Date
Mikael Roos
daf39105fb make tests pass on travis 2017-03-03 22:59:07 +01:00
Mikael Roos
026e01b2cd made passing behat 2017-03-03 22:53:29 +01:00
Mikael Roos
0f0d954e61 prepare to run on circleci 2017-03-03 22:04:59 +01:00
Mikael Roos
58d83ba494 prepare to run on circleci 2017-03-03 21:41:35 +01:00
Mikael Roos
4f8fb82baf change how path is working in makefile 2017-03-03 21:40:46 +01:00
Mikael Roos
1bd8965535 rearranged Makefile 2017-03-03 21:01:37 +01:00
Mikael Roos
081601ebbb merged with master 2017-03-03 20:38:35 +01:00
Mikael Roos
547259cd11 intermediate 2016-07-10 18:18:17 +02:00
Mikael Roos
fbaf05d0d4 adding behat for feature testing 2016-06-03 11:44:27 +02:00
Mikael Roos
3d2c74e9df adding local dev environment 2016-06-02 10:16:18 +02:00
Mikael Roos
74428f066c passed test for resize strategies including no upscale using test/option-no-upscale 2016-06-01 13:57:48 +02:00
Mikael Roos
00ab2d7ca6 mergin parts from latest 2016-06-01 10:39:27 +02:00
Mikael Roos
d5546b669b spelling 2016-06-01 10:06:10 +02:00
Mikael Roos
53fb8da987 tests to be written 2016-06-01 10:05:20 +02:00
Mikael Roos
226f8adbeb merged changes from v0.7.12 2016-06-01 10:04:54 +02:00
Mikael Roos
29d18c4b3c minor 2016-03-09 18:03:08 +01:00
Mikael Roos
d697809a69 update array short syntax 2016-03-09 12:22:03 +01:00
Mikael Roos
8667a9ec79 move alias settings to own section 2016-03-09 12:12:02 +01:00
Mikael Roos
ca6118b355 intermediate 2016-01-14 16:15:09 +01:00
Mikael Roos
cf2fc3de4f intermediate 2015-12-11 10:07:16 +01:00
Mikael Roos
276f46fce2 merged img.php 2015-12-07 17:35:53 +01:00
Mikael Roos
0f3c1b4bde merged v0.7.9 into resize 2015-12-07 17:12:27 +01:00
Mikael Roos
f2153e27a8 update to use cimage version 2015-12-07 11:10:47 +01:00
Mikael Roos
7e5937d7ec ignore mac files 2015-12-06 20:53:36 +01:00
Mikael Roos
3c77a63fbc ignore coverage 2015-12-06 20:52:29 +01:00
Mikael Roos
13da8b0573 add composer validate to travis tests 2015-12-06 20:51:29 +01:00
Mikael Roos
52ce33d928 stretch not applying no upscale 2015-12-06 11:55:09 +01:00
Mikael Roos
5a09c38f5d resize-strategies together with no upscale 2015-12-06 01:24:30 +01:00
Mikael Roos
679714422d fix phpunit for scrutinizer 2015-12-05 17:19:49 +01:00
Mikael Roos
ec72246e9c allow travis failure on hhvm and nightly 2015-12-05 15:04:19 +01:00
Mikael Roos
389c3c48ee install phpcs into build dir on travis 2015-12-05 14:59:17 +01:00
Mikael Roos
fcedac6e62 scrutinizer to make build-dir 2015-12-05 14:58:01 +01:00
Mikael Roos
3daa8549ab update travis to use build directory 2015-12-05 14:53:51 +01:00
Mikael Roos
6a93f843be major rearrange to prepare to move to PHP 5.4 2015-12-05 14:50:49 +01:00
Mikael Roos
f9b149eb5d merged changes from master into resize 2015-12-05 13:58:57 +01:00
Mikael Roos
e41e23c007 adding new tests for resize 2015-11-25 09:58:37 +01:00
Mikael Roos
5673ce4f55 intermediate 2015-11-25 09:58:09 +01:00
Mikael Roos
9bf94e9cf6 calculate target dimensions 2015-10-27 00:21:36 +01:00
77 changed files with 3631 additions and 937 deletions

7
.gitignore vendored
View File

@@ -1,16 +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

View File

@@ -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
View 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>

View File

@@ -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'

View File

@@ -4,9 +4,10 @@ php:
- 5.4
- 5.5
- 5.6
- "7.0"
- "7.1"
- hhvm
- nightly
- "7.0"
@@ -35,50 +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
- composer validate
- phpunit
#- make phpcs
- make test

227
Makefile Normal file
View 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)

View File

@@ -2,10 +2,14 @@ Image conversion on the fly using PHP
=====================================
[![Join the chat at https://gitter.im/mosbth/cimage](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mosbth/cimage?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
<!--
[![Build Status](https://travis-ci.org/mosbth/cimage.svg?branch=master)](https://travis-ci.org/mosbth/cimage)
[![Build Status](https://scrutinizer-ci.com/g/mosbth/cimage/badges/build.png?b=master)](https://scrutinizer-ci.com/g/mosbth/cimage/build-status/master)
-->
[![Build Status](https://travis-ci.org/mosbth/cimage.svg?branch=resize)](https://travis-ci.org/mosbth/cimage)
[![CircleCI](https://circleci.com/gh/mosbth/cimage.svg?style=svg)](https://circleci.com/gh/mosbth/cimage)
[![Build Status](https://scrutinizer-ci.com/g/mosbth/cimage/badges/build.png?b=resize)](https://scrutinizer-ci.com/g/mosbth/cimage/build-status/resize)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/mosbth/cimage/badges/quality-score.png?b=resize)](https://scrutinizer-ci.com/g/mosbth/cimage/?branch=resize)
[![Code Coverage](https://scrutinizer-ci.com/g/mosbth/cimage/badges/coverage.png?b=resize)](https://scrutinizer-ci.com/g/mosbth/cimage/?branch=resize)
[![SensioLabsInsight](https://insight.sensiolabs.com/projects/ebc10d27-449d-42ca-b380-ba5ecb7813ba/mini.png)](https://insight.sensiolabs.com/projects/ebc10d27-449d-42ca-b380-ba5ecb7813ba)
About
-------------------------------------
@@ -47,7 +51,7 @@ There are several ways of installing. You either install the whole project which
### Install source from GitHub
###Install source from GitHub
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).
@@ -68,7 +72,7 @@ chmod 777 cache
```
### Install all-included bundle
###Install all-included bundle
There are some all-included bundles of `img.php` that can be downloaded and used without dependency to the rest of the sourcecode.
@@ -88,7 +92,7 @@ Open up the file in your editor and edit the array `$config`. Ensure that the pa
### Install from Packagist
###Install from Packagist
You can install the package [`mos/cimage` from Packagist](https://packagist.org/packages/mos/cimage) using composer.
@@ -141,13 +145,13 @@ Get going quickly
### Check out the test page
###Check out the test page
Try it out by pointing your browser to the test file `webroot/test/test.php`. It will show some example images and you can review how they are created.
### Process your first image
###Process your first image
<img src="https://cimage.se/cimage/imgd.php?src=example/kodim04.png&amp;w=w2&amp;a=40,0,50,0" alt=''>
@@ -161,20 +165,20 @@ and try to resize it to a thumbnail by adding the options
### What does "processing the image" involves?
###What does "processing the image" involves?
Add `&verbose` to the link to get a verbose output of what is happens during image processing. This is useful for developers and those who seek a deeper understanding on how it works behind the scene.
### Check your system
###Check your system
Open up `webroot/check_system.php` if you are uncertain that your system has the right extensions loaded.
### How does it work?
###How does it work?
Review the settings in `webroot/img_config.php` and check out `webroot/img.php` on how it uses `CImage`.
@@ -195,7 +199,7 @@ Basic usage
### Select the source
###Select the source
Open an image through `img.php` by using its `src` attribute.
@@ -211,7 +215,7 @@ All images are stored in a directory structure and you access them as:
### Resize using constraints on width and height
###Resize using constraints on width and height
Create a thumbnail of the image by applying constraints on width and height, or one of them.
@@ -225,7 +229,7 @@ Think of the constraints as a imaginary box where the image should fit. With `wi
### Resize to fit a certain dimension
###Resize to fit a certain dimension
Creating a thumbnail with a certain dimension of width and height, usually involves stretching or cropping the image to fit in the selected dimensions. Here is how you create a image that has the exact dimensions of 300x150 pixels, by either *stretching*, *cropping* or *fill to fit*.
@@ -245,7 +249,7 @@ Fill to fit is useful when you have some image that must fit in a certain dimens
### List of parameters
###List of parameters
`img.php` supports a lot of parameters. Combine the parameters to get the desired behavior and resulting image. For example, take the original image, resize it using width, aspect-ratio and crop-to-fit, apply a sharpen effect, save the image as JPEG using quality 30.
@@ -257,7 +261,7 @@ Fill to fit is useful when you have some image that must fit in a certain dimens
Here is a list of all parameters that you can use together with `img.php`, grouped by its basic intent of usage.
#### Mandatory options and debugging
####Mandatory options and debugging
Option `src` is the only mandatory option. The options in this section is useful for debugging or deciding what version of the target image is used.
@@ -272,7 +276,7 @@ Option `src` is the only mandatory option. The options in this section is useful
#### Options for deciding width and height of target image
####Options for deciding width and height of target image
These options are all affecting the final dimensions, width and height, of the resulting image.
@@ -285,7 +289,7 @@ These options are all affecting the final dimensions, width and height, of the r
#### Options for resize strategy
####Options for resize strategy
These options affect strategy to use when resizing an image into a target image that has both width and height set.
@@ -298,7 +302,7 @@ These options affect strategy to use when resizing an image into a target image
#### Options for cropping part of image
####Options for cropping part of image
These options enable to decide what part of image to crop out.
@@ -309,7 +313,7 @@ These options enable to decide what part of image to crop out.
#### General processing options
####General processing options
These options are general options affecting processing.
@@ -319,7 +323,7 @@ These options are general options affecting processing.
#### Processing of image before resizing
####Processing of image before resizing
This option are executed *before* the image is resized.
@@ -331,7 +335,7 @@ This option are executed *before* the image is resized.
#### Processing of image after resizing
####Processing of image after resizing
These options are executed *after* the image is resized.
@@ -349,7 +353,7 @@ These options are executed *after* the image is resized.
#### Saving image, affecting quality and file size
####Saving image, affecting quality and file size
Options for saving the target image.
@@ -405,7 +409,7 @@ Consult the file `webroot/img-config.php` for a complete list together with the
### Create and name the config file
###Create and name the config file
The file `img.php` looks for the config-file `img_config.php`, and uses it if its found. The three files where everything is included -- `imgd.php`, `imgp.php` and `imgs.php` -- includes an empty `$config`-array which can be overridden by saving a config-file in the same directory. If the script is `imgp.php` then name the config-file `imgp_config.php` and it will find it and use those settings.
@@ -470,19 +474,19 @@ Here are some thoughts when applying `img.php` on a live system.
### Select the proper mode
###Select the proper mode
Select the proper mode for `img.php`. Set it to "strict" or "production" to prevent outsiders to get information about your system. Use only "development" for internal use since its quite verbose in its nature of error reporting.
### Put the installation directory outside web root
###Put the installation directory outside web root
Edit the config file to put the installation directory -- and the cache directory -- outside of the web root. Best practice would be to store the installation directory and cache, outside of the web root. The only thing needed in the web root is `img.php` and `img_config.php` (if used) which can be placed, for example, in `/img/img.php` or just as `/img.php`.
### Friendly urls through `.htaccess`
###Friendly urls through `.htaccess`
Use `.htaccess`and rewrite rules (Apache) to get friendly image urls. Put `img.php` in the `/img` directory. Put the file `.htaccess` in the web root.
@@ -520,7 +524,7 @@ The result is good readable urls to your images. Its easy for the search engine
### Monitor cache size
###Monitor cache size
There is a utility `cache.bash` included for monitoring the size of the cache-directory. It generates an output like this.
@@ -558,13 +562,13 @@ Use it as a base if you feel the need to monitor the size och the cache-director
### Read-only cache
###Read-only cache
The cache directory need to be writable for `img.php` to create new files. But its possible to first create all cache-files and then set the directory to be read-only. This will give you a way of shutting of `img.php` from creating new cache files. `img.php` will then continue to work for all images having a cached version but will fail if someone tries to create a new, not previously cached, version of the image.
### Post-processing with external tools
###Post-processing with external tools
You can use external tools to post-process the images to optimize the file size. This option is available for JPEG and for PNG images. Post-processing is disabled by default, edit `img_config.php` to enable it.
@@ -574,7 +578,7 @@ These tools for post processing is not a part of `CImage` and `img.php`, you nee
### Allowing remote download of images
###Allowing remote download of images
You can allow `img.php` to download remote images. That can be enabled in the config-file. However, before doing so, consider the implications on allowing anyone to download a file, hopefully an image, to your server and then the possibility to access it through the webserver.

View File

@@ -1,100 +1,26 @@
Revision history
=====================================
<!--
[![Build Status](https://travis-ci.org/mosbth/cimage.svg?branch=master)](https://travis-ci.org/mosbth/cimage)
[![Build Status](https://scrutinizer-ci.com/g/mosbth/cimage/badges/build.png?b=master)](https://scrutinizer-ci.com/g/mosbth/cimage/build-status/master)
--->
v0.8.6 (2023-10-27)
v0.8.* (2015-12-05) (branch resize)
-------------------------------------
* Fix deprecation notice on "Creation of dynamic property" for PHP 8.2.
* 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.8.5 (2022-11-17)
v0.7.9* (2015-12-07)
-------------------------------------
* Enable configuration fix for solving Windows 2 WSL2 issue with is_readable/is_writable #189.
* Update CHttpGet.php for php 8.1 deprecated notice #188.
* Remove build status from README (since it is not up to date).
* Fix strict mode only reporting 404 when failure, #127.
v0.8.4 (2022-05-30)
v0.7.19* (2016-08-31)
-------------------------------------
* Support PHP 8.1 and remove (more) deprecated messages when run in in development mode.
v0.8.3 (2022-05-24)
-------------------------------------
* Support PHP 8.1 and remove deprecated messages when run in in development mode.
* Generate prebuilt all include files for various settings
* Fix deprecated for PHP 8.1
* Fix deprecated for PHP 8.1
* Add php version as output in verbose mode
* Add PHP 81 as test environment
v0.8.2 (2021-10-27)
-------------------------------------
* Remove bad configuration.
v0.8.1 (2020-06-08)
-------------------------------------
* Updated version number in define.php.
v0.8.0 (2020-06-08)
-------------------------------------
* Enable to set JPEG image as interlaced, implement feature #177.
* Add function getValue() to read from querystring.
* Set PHP 7.0 as precondition (to prepare to update the codebase).
v0.7.23 (2020-05-06)
-------------------------------------
* Fix error in composer.json
v0.7.22 (2020-05-06)
-------------------------------------
* Update composer.json and move ext-gd from required to suggested to ease installation where cli does not have all extensions installed.
v0.7.21 (2020-01-15)
-------------------------------------
* Support PHP 7.4, some minor fixes with notices.
v0.7.20 (2017-11-06)
-------------------------------------
* Remove webroot/img/{round8.PNG,wider.JPEG,wider.JPG} to avoid unzip warning message when installing with composer.
* Adding docker-compose.yml #169.
v0.7.19 (2017-03-31)
-------------------------------------
* Move exception handler from functions.php to img.php #166.
* Correct XSS injection in `check_system.php`.
* Composer suggests ext-imagick and ext-curl.
@@ -180,7 +106,7 @@ v0.7.8 (2015-12-06)
* HTTP error messages now 403, 404 and 500 as in #128 and #127.
* More examples on dealing with cache through bash `bin/cache.bash`, #129.
* Added conversion to sRGB using option `?srgb`. #120.
* Added conversion to sRGB using option `?srgb`. #120.
* Added Gitter badge to README, #126.
* Fix proper download url in README, #125.
* Change path in `webroot/htaccess` to make it work in current environment.
@@ -191,11 +117,11 @@ v0.7.7 (2015-10-21)
* One can now add a HTTP header for Cache-Control in the config file, #109.
* Added hook in img,php before CImage is called, #123.
* Added configuration for default jpeg quality and png compression in the config file, #107.
* Added configuration for default jpeg quality and png compression in the config file, #107.
* Strip comments and whitespace in imgs.php, #115.
* Bundle imgs.php did not have the correct mode.
* Adding option &status to get an overview of the installed on configured utilities, #116.
* Bug, all files saved as png-files, when not saving as specific file.
* Bug, all files saved as png-files, when not saving as specific file.
* Removed saving filename extension for alias images.
* Added option to decide if resample or resize when copying images internally. `&no-resample` makes resize, instead of resample as is default.
* Verbose now correctly states if transparent color is detected.
@@ -250,14 +176,14 @@ v0.7.1 (2015-07-25)
* Using `CWhitelist` for checking hotlinking to images, fix #88.
* Added mode for `test` which enables logging verbose mode to file, fix #97.
* Improved codestyle and added `phpcs.xml` to start using phpcs to check code style, fix #95.
* Adding `composer.json` for publishing on packagist.
* Adding `composer.json` for publishing on packagist.
* Add permalink to setup for comparing images with `webroot/compare/compare.php`, fix #92.
* Allow space in filename by using `urlencode()` and allow space as valid filenam character. fix #91.
* Support redirections for remote images, fix #87, fix #90.
* Support redirections for remote images, fix #87, fix #90.
* Improving usage of Travis and Scrutinizer.
* Naming cache-file using md5 for remote images, fix #86.
* Loading images without depending on filename extension, fix #85.
* Adding unittest with phpunit #84, fix #13
* Adding unittest with phpunit #84, fix #13
* Adding support for whitelist of remote hostnames, #84
* Adding phpdoc, fix #48.
* Adding travis, fix #15.

View File

@@ -1,6 +0,0 @@
Security policy
======================
To report security vulnerabilities in the project, send en email to mikael.t.h.roos@gmail.com.
For other security related issues, please open an issue on the project.

13
circle.yml Normal file
View File

@@ -0,0 +1,13 @@
machine:
php:
#version: 5.6.18
test:
pre:
- make install
- make check
override:
- make test

View File

@@ -1,44 +1,39 @@
{
"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": ">=7.0"
"php": ">=5.4",
"ext-gd": "*"
},
"suggest": {
"ext-curl": "*",
"ext-exif": "*",
"ext-gd": "*",
"ext-curl": "*",
"ext-imagick": "*"
},
"autoload": {
"files": [
"defines.php",
"functions.php"
],
"classmap": [
"CImage.php",
"CHttpGet.php",
"CRemoteImage.php",
"CWhitelist.php",
"CAsciiArt.php",
"CCache.php",
"CFastTrackCache.php"
"psr-4": {
"Mos\\": "src/"
},
"files": [
"src/defines.php",
"src/functions.php"
]
}
}

20
composer.lock generated Normal file
View 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": []
}

View File

@@ -1,97 +0,0 @@
version: "3"
services:
cli:
image: anax/dev
volumes: [ ".:/home/anax/repo" ]
apache:
image: anax/dev:apache
volumes: [ ".:/home/anax/repo" ]
ports: [ "11000:80" ]
remserver:
image: anax/dev:apache
ports:
- "8090:80"
volumes: [ ".:/home/anax/repo" ]
php82:
image: anax/dev:php82
volumes: [ ".:/home/anax/repo" ]
php82-apache:
image: anax/dev:php82-apache
ports: [ "11082:80" ]
volumes: [ ".:/home/anax/repo" ]
php81:
image: anax/dev:php81
volumes: [ ".:/home/anax/repo" ]
php81-apache:
image: anax/dev:php81-apache
ports: [ "11081:80" ]
volumes: [ ".:/home/anax/repo" ]
php80:
image: anax/dev:php80
volumes: [ ".:/home/anax/repo" ]
php80-apache:
image: anax/dev:php80-apache
ports: [ "11080:80" ]
volumes: [ ".:/home/anax/repo" ]
php74:
image: anax/dev:php74
volumes: [ ".:/home/anax/repo" ]
php74-apache:
image: anax/dev:php74-apache
ports: [ "11074:80" ]
volumes: [ ".:/home/anax/repo" ]
php73:
image: anax/dev:php73
volumes: [ ".:/home/anax/repo" ]
php73-apache:
image: anax/dev:php73-apache
ports: [ "11073:80" ]
volumes: [ ".:/home/anax/repo" ]
php72:
image: anax/dev:php72
volumes: [ ".:/home/anax/repo" ]
php72-apache:
image: anax/dev:php72-apache
ports: [ "11072:80" ]
volumes: [ ".:/home/anax/repo" ]
php71:
image: anax/dev:php71
volumes: [ ".:/home/anax/repo" ]
php71-apache:
image: anax/dev:php71-apache
ports: [ "11071:80" ]
volumes: [ ".:/home/anax/repo" ]
php70:
image: anax/dev:php70
volumes: [ ".:/home/anax/repo" ]
php70:
image: anax/dev:php70-apache
ports: [ "11070:80" ]
volumes: [ ".:/home/anax/repo" ]
php56:
image: anax/dev:php56
volumes: [ ".:/home/anax/repo" ]
php56:
image: anax/dev:php56-apache
ports: [ "11056:80" ]
volumes: [ ".:/home/anax/repo" ]

View 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");
}
}

View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 B

19
features/img/dummy.json Normal file
View 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)"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 B

View 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
View 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"

View File

@@ -16,8 +16,7 @@ require_once __DIR__ . "/functions.php";
* @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);
}

View File

@@ -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>

View File

@@ -1,4 +1,7 @@
<?php
namespace Mos\CImage;
/**
* Create an ASCII version of an image.
*

View File

@@ -1,4 +1,7 @@
<?php
namespace Mos\CImage;
/**
* Deal with the cache directory and cached items.
*
@@ -51,15 +54,6 @@ class CCache
return $path;
}
if ($create && defined('WINDOWS2WSL')) {
// Special case to solve Windows 2 WSL integration
$path = $this->path . "/" . $subdir;
if (mkdir($path)) {
return realpath($path);
}
}
if ($create && is_writable($this->path)) {
$path = $this->path . "/" . $subdir;

View File

@@ -1,4 +1,7 @@
<?php
namespace Mos\CImage;
/**
* Enable a fast track cache with a json representation of the image delivery.
*

View File

@@ -1,4 +1,7 @@
<?php
namespace Mos\CImage;
/**
* Get a image from a remote server using HTTP GET and If-Modified-Since.
*
@@ -215,7 +218,7 @@ class CHttpGet
{
$type = isset($this->response['header']['Content-Type'])
? $this->response['header']['Content-Type']
: '';
: null;
return preg_match('#[a-z]+/[a-z]+#', $type)
? $type

View File

@@ -1,4 +1,7 @@
<?php
namespace Mos\CImage;
/**
* Resize and crop images on the fly, store generated images in a cache.
*
@@ -6,7 +9,6 @@
* @example http://dbwebb.se/opensource/cimage
* @link https://github.com/mosbth/cimage
*/
#[AllowDynamicProperties]
class CImage
{
@@ -224,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;
@@ -355,6 +357,7 @@ class CImage
/**
* Used with option area to set which parts of the image to use.
*/
private $area;
private $offset;
@@ -424,22 +427,20 @@ class CImage
/*
* Use interlaced progressive mode for JPEG images.
*/
private $interlace = false;
/*
* Image copy strategy, defaults to RESAMPLE.
*/
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.
@@ -471,10 +472,12 @@ 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.
*
@@ -680,9 +683,9 @@ class CImage
*
* @return string $extension as a normalized file extension.
*/
private function normalizeFileExtension($extension = "")
private function normalizeFileExtension($extension = null)
{
$extension = strtolower($extension ? $extension : $this->extension ?? "");
$extension = strtolower($extension ? $extension : $this->extension);
if ($extension == 'jpeg') {
$extension = 'jpg';
@@ -846,7 +849,6 @@ class CImage
'blur' => null,
'convolve' => null,
'rotateAfter' => null,
'interlace' => null,
// Output format
'outputFormat' => null,
@@ -965,11 +967,8 @@ class CImage
{
$file = $file ? $file : $this->pathToImage;
// Special case to solve Windows 2 WSL integration
if (!defined('WINDOWS2WSL')) {
is_readable($file)
or $this->raiseError('Image file does not exist.');
}
is_readable($file)
or $this->raiseError('Image file does not exist.');
$info = list($this->width, $this->height, $this->fileType) = getimagesize($file);
if (empty($info)) {
@@ -993,9 +992,11 @@ class CImage
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: " . $this->getMimeType());
@@ -1024,76 +1025,18 @@ class CImage
/**
* Init new width and height and do some sanity checks on constraints, before any
* processing can be done.
* 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
&& $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
&& $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;
}
@@ -1107,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}.");
@@ -1195,7 +1163,7 @@ class CImage
$this->newWidth = $width;
$this->newHeight = $height;
}
// Get image dimensions for pre-resize image.
if ($this->cropToFit || $this->fillToFit) {
@@ -1234,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;
}
@@ -1258,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;
@@ -1405,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;
@@ -1414,7 +1380,6 @@ class CImage
$rotateBefore = $this->rotateBefore ? "_rb{$this->rotateBefore}" : null;
$rotateAfter = $this->rotateAfter ? "_ra{$this->rotateAfter}" : null;
$lossy = $this->lossy ? "_l" : null;
$interlace = $this->interlace ? "_i" : null;
$saveAs = $this->normalizeFileExtension();
$saveAs = $saveAs ? "_$saveAs" : null;
@@ -1474,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 . $lossy . $interlace . $saveAs;
. $convolve . $copyStrat . $lossy . $saveAs;
return $this->setTarget($file, $base);
}
@@ -1524,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.
@@ -1625,7 +1589,6 @@ class CImage
}
switch ($pngType) {
case self::PNG_GREYSCALE:
$text = "PNG is type 0, Greyscale$transparent";
break;
@@ -1731,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;
}
@@ -1746,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 {
@@ -1764,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']);
@@ -1780,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']);
@@ -1797,7 +1781,6 @@ class CImage
}
if ($this->cropToFit) {
// Resize by crop to fit
$this->log("Resizing using strategy - Crop to fit");
@@ -1837,20 +1820,28 @@ class CImage
$imageResized = $this->CreateImageKeepTransparency($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");
@@ -1870,13 +1861,11 @@ class CImage
if (!$this->upscale
&& ($this->width < $this->newWidth && $this->height < $this->newHeight)
) {
$this->log("Resizing - smaller image, do not upscale.");
$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->width, $this->height);
} else {
$imgPreFill = $this->CreateImageKeepTransparency($this->fillWidth, $this->fillHeight);
$imageResized = $this->CreateImageKeepTransparency($this->newWidth, $this->newHeight);
@@ -1887,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");
@@ -1954,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;
@@ -2304,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'];
@@ -2317,7 +2301,6 @@ class CImage
}
return $color;
} else {
return 0;
}
@@ -2345,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.");
@@ -2444,23 +2424,14 @@ class CImage
return;
}
if (!defined("WINDOWS2WSL")) {
is_writable($this->saveFolder)
is_writable($this->saveFolder)
or $this->raiseError('Target directory is not writable.');
}
$type = $this->getTargetImageExtension();
$this->Log("Saving image as " . $type);
switch($type) {
switch ($type) {
case 'jpeg':
case 'jpg':
// Set as interlaced progressive JPEG
if ($this->interlace) {
$this->Log("Set JPEG image to be interlaced.");
$res = imageinterlace($this->image, true);
}
$this->Log("Saving image as JPEG to cache using quality = {$this->quality}.");
imagejpeg($this->image, $this->cacheFileName, $this->quality);
@@ -2578,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;
}
@@ -2599,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);
@@ -2610,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;
}
@@ -2730,7 +2701,6 @@ class CImage
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])
&& strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $lastModified) {
if ($this->verbose) {
$this->log("304 not modified");
$this->verboseOutput();
@@ -2741,9 +2711,7 @@ class CImage
if (CIMAGE_DEBUG) {
trace(__CLASS__ . " 304");
}
} else {
$this->loadImageDetails($file);
$mime = $this->getMimeType();
$size = filesize($file);
@@ -2799,18 +2767,18 @@ class CImage
$lastModified = filemtime($this->pathToImage);
$details['srcGmdate'] = gmdate("D, d M Y H:i:s", $lastModified);
$details['cache'] = basename($this->cacheFileName ?? "");
$lastModified = filemtime($this->cacheFileName ?? "");
$details['cache'] = basename($this->cacheFileName);
$lastModified = filemtime($this->cacheFileName);
$details['cacheGmdate'] = gmdate("D, d M Y H:i:s", $lastModified);
$this->load($file);
$details['filename'] = basename($file ?? "");
$details['filename'] = basename($file);
$details['mimeType'] = $this->getMimeType($this->fileType);
$details['width'] = $this->width;
$details['height'] = $this->height;
$details['aspectRatio'] = round($this->width / $this->height, 3);
$details['size'] = filesize($file ?? "");
$details['size'] = filesize($file);
$details['colors'] = $this->colorsTotal($this->image);
$details['includedFiles'] = count(get_included_files());
$details['memoryPeek'] = round(memory_get_peak_usage()/1024/1024, 3) . " MB" ;

View 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;
}
}

View File

@@ -1,4 +1,7 @@
<?php
namespace Mos\CImage;
/**
* Get a image from a remote server using HTTP GET and If-Modified-Since.
*

View File

@@ -1,4 +1,7 @@
<?php
namespace Mos\CImage;
/**
* Act as whitelist (or blacklist).
*

22
src/CImage/Exception.php Normal file
View 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);
}
}

View File

@@ -1,6 +1,6 @@
<?php
// Version of cimage and img.php
define("CIMAGE_VERSION", "v0.8.6 (2023-10-27)");
define("CIMAGE_VERSION", "v0.7.19* (2016-08-11)");
// For CRemoteImage
define("CIMAGE_USER_AGENT", "CImage/" . CIMAGE_VERSION);

View File

@@ -107,25 +107,6 @@ function getDefined($key, $defined, $undefined)
/**
* Get value of input from query string or else $undefined.
*
* @param mixed $key as string or array of string values to look for in $_GET.
* @param mixed $undefined value to return when $key has no, or empty value in $_GET.
*
* @return mixed value as or $undefined.
*/
function getValue($key, $undefined)
{
$val = get($key);
if (is_null($val) || $val === "") {
return $undefined;
}
return $val;
}
/**
* Get value from config array or default if key is not set in config array.
*
@@ -151,7 +132,7 @@ function getConfig($key, $default)
*
* @return void or array.
*/
function verbose($msg = null, $arg = "")
function verbose($msg = null)
{
global $verbose, $verboseFile;
static $log = array();
@@ -164,15 +145,7 @@ function verbose($msg = null, $arg = "")
return $log;
}
if (is_null($arg)) {
$arg = "null";
} elseif ($arg === false) {
$arg = "false";
} elseif ($arg === true) {
$arg = "true";
}
$log[] = $msg . $arg;
$log[] = $msg;
}

View File

@@ -1,4 +1,7 @@
<?php
namespace Mos\CImage;
/**
* A testclass
*

View File

@@ -1,4 +1,7 @@
<?php
namespace Mos\CImage;
/**
* A testclass
*

View File

@@ -1,4 +1,7 @@
<?php
namespace Mos\CImage;
/**
* A testclass
*

View 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.");
}
}

View 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.");
}
}

View 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.");
}
}

View 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.");
}
}

View 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.");
}
}

View 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
View 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.");
}
}

View File

@@ -1,4 +1,7 @@
<?php
namespace Mos\CImage;
/**
* A testclass
*

54
test/CImgTest.php Normal file
View 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";
}
}

View File

@@ -1,4 +1,7 @@
<?php
namespace Mos\CImage;
/**
* A testclass
*

13
test/Tests.txt Normal file
View 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.

View File

@@ -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
View 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
View 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
View 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
View 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
View 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',
);

View 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
View 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
View 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
View 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
View File

@@ -0,0 +1 @@
[]

View File

@@ -3,12 +3,6 @@
<head>
<style>
<?php
function e($str) {
return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
}
?>
body {
}
@@ -134,15 +128,15 @@ if (isset($_GET['input1'])) {
// Use incoming from querystring as defaults
?>
CImage.compare({
"input1": "<?=e($_GET['input1'])?>",
"input2": "<?=e($_GET['input2'])?>",
"input3": "<?=e($_GET['input3'])?>",
"input4": "<?=e($_GET['input4'])?>",
"input5": "<?=e($_GET['input5'])?>",
"input6": "<?=e($_GET['input6'])?>",
"json": <?=e($_GET['json'])?>,
"stack": <?=e($_GET['stack'])?>,
"bg": <?=e($_GET['bg'])?>
"input1": "<?=$_GET['input1']?>",
"input2": "<?=$_GET['input2']?>",
"input3": "<?=$_GET['input3']?>",
"input4": "<?=$_GET['input4']?>",
"input5": "<?=$_GET['input5']?>",
"input6": "<?=$_GET['input6']?>",
"json": <?=$_GET['json']?>,
"stack": <?=$_GET['stack']?>,
"bg": <?=$_GET['bg']?>
});
<?php
} elseif (isset($script)) {

View File

@@ -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.
#

View File

@@ -89,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);
}
@@ -186,7 +178,7 @@ $hotlinkingWhitelist = getConfig('hotlinking_whitelist', array());
$serverName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : null;
$referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;
$refererHost = parse_url($referer ?? "", PHP_URL_HOST);
$refererHost = parse_url($referer, PHP_URL_HOST);
if (!$allowHotlinking) {
if ($passwordMatch) {
@@ -208,7 +200,6 @@ if (!$allowHotlinking) {
} else {
errorPage("Hotlinking/leeching not allowed by whitelist. Referer: $referer.", 403);
}
} else {
errorPage("Hotlinking/leeching not allowed.", 403);
}
@@ -223,7 +214,7 @@ verbose("referer host = $refererHost");
/**
* Create the class for the image.
*/
$CImage = getConfig('CImage', 'CImage');
$CImage = getConfig('CImage', '\Mos\CImage\CImage');
$img = new $CImage();
$img->setVerbose($verbose || $verboseFile);
@@ -232,7 +223,7 @@ $img->setVerbose($verbose || $verboseFile);
/**
* Get the cachepath from config.
*/
$CCache = getConfig('CCache', 'CCache');
$CCache = getConfig('CCache', '\Mos\CImage\CCache');
$cachePath = getConfig('cache_path', __DIR__ . '/../cache/');
$cache = new $CCache();
$cache->setDir($cachePath);
@@ -254,7 +245,7 @@ verbose("use cache = $useCache");
$fastTrackCache = "fasttrack";
$allowFastTrackCache = getConfig('fast_track_allow', false);
$CFastTrackCache = getConfig('CFastTrackCache', 'CFastTrackCache');
$CFastTrackCache = getConfig('CFastTrackCache', '\Mos\CImage\CFastTrackCache');
$ftc = new $CFastTrackCache();
$ftc->setCacheDir($cache->getPathToSubdir($fastTrackCache))
->enable($allowFastTrackCache)
@@ -285,7 +276,7 @@ $allowRemote = getConfig('remote_allow', false);
if ($allowRemote && $passwordMatch !== false) {
$cacheRemote = $cache->getPathToSubdir("remote");
$pattern = getConfig('remote_pattern', null);
$img->setRemoteDownload($allowRemote, $cacheRemote, $pattern);
@@ -307,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);
@@ -319,11 +310,11 @@ if (isset($shortcut)
/**
* src - the source image file.
*/
$srcImage = urldecode(get('src', ""))
$srcImage = urldecode(get('src'))
or errorPage('Must set src-attribute.', 404);
// Get settings for src-alt as backup image
$srcAltImage = urldecode(get('src-alt', ""));
$srcAltImage = urldecode(get('src-alt', null));
$srcAltConfig = getConfig('src_alt', null);
if (empty($srcAltImage)) {
$srcAltImage = $srcAltConfig;
@@ -346,17 +337,12 @@ preg_match($validFilename, $srcImage)
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.
$remoteSource = true;
} else {
// Check if file exists on disk or try using src-alt
$pathToImage = realpath($imagePath . $srcImage);
@@ -440,7 +426,7 @@ if (isset($sizes[$newWidth])) {
}
// Support width as % of original width
if ($newWidth && $newWidth[strlen($newWidth)-1] == '%') {
if ($newWidth[strlen($newWidth)-1] == '%') {
is_numeric(substr($newWidth, 0, -1))
or errorPage('Width % not numeric.', 404);
} else {
@@ -465,7 +451,7 @@ if (isset($sizes[$newHeight])) {
}
// height
if ($newHeight && $newHeight[strlen($newHeight)-1] == '%') {
if ($newHeight[strlen($newHeight)-1] == '%') {
is_numeric(substr($newHeight, 0, -1))
or errorPage('Height % out of range.', 404);
} else {
@@ -496,7 +482,7 @@ $aspectRatioConstant = getConfig('aspect_ratio_constant', function () {
// Check to replace predefined aspect ratio
$aspectRatios = call_user_func($aspectRatioConstant);
$negateAspectRatio = ($aspectRatio && $aspectRatio[0] == '!') ? true : false;
$negateAspectRatio = ($aspectRatio[0] == '!') ? true : false;
$aspectRatio = $negateAspectRatio ? substr($aspectRatio, 1) : $aspectRatio;
if (isset($aspectRatios[$aspectRatio])) {
@@ -920,18 +906,6 @@ if ($cacheControl) {
/**
* interlace - Enable configuration for interlaced progressive JPEG images.
*/
$interlaceConfig = getConfig('interlace', null);
$interlaceValue = getValue('interlace', null);
$interlaceDefined = getDefined('interlace', true, null);
$interlace = $interlaceValue ?? $interlaceDefined ?? $interlaceConfig;
verbose("interlace (configfile) = ", $interlaceConfig);
verbose("interlace = ", $interlace);
/**
* Prepare a dummy image and use it as source image.
*/
@@ -1093,7 +1067,6 @@ if (is_callable($hookBeforeCImage)) {
'blur' => $blur,
'convolve' => $convolve,
'rotateAfter' => $rotateAfter,
'interlace' => $interlace,
// Output format
'outputFormat' => $outputFormat,
@@ -1149,8 +1122,7 @@ EOD;
/**
* Load, process and output the image
*/
$img->log("PHP version: " . phpversion())
->log("Incoming arguments: " . print_r(verbose(), 1))
$res = $img->log("Incoming arguments: " . print_r(verbose(), 1))
->setSaveFolder($cachePath)
->useCache($useCache)
->setSource($srcImage, $imagePath)
@@ -1183,7 +1155,6 @@ $img->log("PHP version: " . phpversion())
'blur' => $blur,
'convolve' => $convolve,
'rotateAfter' => $rotateAfter,
'interlace' => $interlace,
// Output format
'outputFormat' => $outputFormat,
@@ -1210,3 +1181,5 @@ $img->log("PHP version: " . phpversion())
->save()
->linkToCacheFile($aliasTarget)
->output();
return $res;

171
webroot/img/drawing.svg Normal file
View 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/round8.PNG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 B

BIN
webroot/img/tower.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

BIN
webroot/img/wider.JPEG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

BIN
webroot/img/wider.JPG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

View File

@@ -21,18 +21,9 @@ if (!defined("CIMAGE_DEBUG")) {
define("CIMAGE_DEBUG_FILE", "/tmp/cimage");
}
/**
* Set this if you work with a webserver in Windows and try to access files
* within WSL2.
* The issue seems to be with functions like `is_writable()` and
* `is_readable()`.
* When WINDOWS2WSL is defined (to any value) it ignores these functions.
*/
#define('WINDOWS2WSL', 1);
return array(
return [
/**
* Set mode as 'strict', 'production' or 'development'.
@@ -61,12 +52,14 @@ return array(
* Default values:
* autoloader: null
*/
'autoloader' => __DIR__ . '/../autoload.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:
@@ -76,7 +69,7 @@ return array(
*/
'image_path' => __DIR__ . '/img/',
'cache_path' => __DIR__ . '/../cache/',
'alias_path' => __DIR__ . '/img/alias/',
//'alias_path' => __DIR__ . '/img/alias/',
@@ -98,13 +91,13 @@ return array(
* the codebase.
*
* Default values:
* CImage: CImage
* CCache: CCache
* CFastTrackCache: CFastTrackCache
* CImage: \Mos\CImage\CImage
* CCache: \Mos\CImage\CCache
* CFastTrackCache: \Mos\CImage\CFastTrackCache
*/
//'CImage' => 'CImage',
//'CCache' => 'CCache',
//'CFastTrackCache' => 'CFastTrackCache',
//'CImage' => '\Mos\CImage\CImage',
//'CCache' => '\Mos\CImage\CCache',
//'CFastTrackCache' => '\Mos\CImage\CFastTrackCache',
@@ -125,7 +118,7 @@ return array(
* password_type: 'text' // use plain password, not encoded,
*/
//'password_always' => false, // always require password,
//'password' => "moped", // "secret-password",
//'password' => false, // "secret-password",
//'password_type' => 'text', // supports 'text', 'md5', 'hash',
@@ -150,13 +143,14 @@ 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$'
], */
@@ -191,18 +185,20 @@ 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
* 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 do this conversion for all images.
* 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.
*
@@ -350,7 +346,7 @@ 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',
@@ -362,7 +358,7 @@ return array(
'jpeg_optimize' => false,
'jpeg_optimize_cmd' => '/usr/local/bin/jpegtran -copy none -optimize',
),
],
*/
@@ -372,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',
),
],
*/
@@ -395,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$',
),
],
*/
@@ -409,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",
),*/
],*/
@@ -439,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;
@@ -465,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,
@@ -473,7 +469,7 @@ return array(
'16:10' => 16/10,
'16:9' => 16/9,
'golden' => 1.618,
);
];
},*/
@@ -489,23 +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,
), */
/**
* Default options for creating interlaced progressive JPEG images. Set
* to true to always render jpeg images as interlaced. This setting can
* be overridden by using `?interlace`, `?interlace=true` or
* `?interlace=false`.
*
* Default values are:
* interlace: false
*/
/*'interlace' => false,*/
);
);
],*/
];

View File

@@ -38,7 +38,7 @@ $config = array(
// Version of cimage and img.php
define("CIMAGE_VERSION", "v0.8.6 (2023-10-27)");
define("CIMAGE_VERSION", "v0.7.18 (2016-08-09)");
// For CRemoteImage
define("CIMAGE_USER_AGENT", "CImage/" . CIMAGE_VERSION);
@@ -118,6 +118,22 @@ function errorPage($msg, $type = 500)
/**
* Custom exception handler.
*/
set_exception_handler(function ($exception) {
errorPage(
"<p><b>img.php: Uncaught exception:</b> <p>"
. $exception->getMessage()
. "</p><pre>"
. $exception->getTraceAsString()
. "</pre>",
500
);
});
/**
* Get input from query string or return default value if not set.
*
@@ -158,25 +174,6 @@ function getDefined($key, $defined, $undefined)
/**
* Get value of input from query string or else $undefined.
*
* @param mixed $key as string or array of string values to look for in $_GET.
* @param mixed $undefined value to return when $key has no, or empty value in $_GET.
*
* @return mixed value as or $undefined.
*/
function getValue($key, $undefined)
{
$val = get($key);
if (is_null($val) || $val === "") {
return $undefined;
}
return $val;
}
/**
* Get value from config array or default if key is not set in config array.
*
@@ -202,7 +199,7 @@ function getConfig($key, $default)
*
* @return void or array.
*/
function verbose($msg = null, $arg = "")
function verbose($msg = null)
{
global $verbose, $verboseFile;
static $log = array();
@@ -215,15 +212,7 @@ function verbose($msg = null, $arg = "")
return $log;
}
if (is_null($arg)) {
$arg = "null";
} elseif ($arg === false) {
$arg = "false";
} elseif ($arg === true) {
$arg = "true";
}
$log[] = $msg . $arg;
$log[] = $msg;
}
@@ -465,7 +454,7 @@ class CHttpGet
{
$type = isset($this->response['header']['Content-Type'])
? $this->response['header']['Content-Type']
: '';
: null;
return preg_match('#[a-z]+/[a-z]+#', $type)
? $type
@@ -1143,7 +1132,6 @@ class CAsciiArt
* @example http://dbwebb.se/opensource/cimage
* @link https://github.com/mosbth/cimage
*/
#[AllowDynamicProperties]
class CImage
{
@@ -1561,13 +1549,6 @@ class CImage
/*
* Use interlaced progressive mode for JPEG images.
*/
private $interlace = false;
/*
* Image copy strategy, defaults to RESAMPLE.
*/
@@ -1817,9 +1798,9 @@ class CImage
*
* @return string $extension as a normalized file extension.
*/
private function normalizeFileExtension($extension = "")
private function normalizeFileExtension($extension = null)
{
$extension = strtolower($extension ? $extension : $this->extension ?? "");
$extension = strtolower($extension ? $extension : $this->extension);
if ($extension == 'jpeg') {
$extension = 'jpg';
@@ -1983,7 +1964,6 @@ class CImage
'blur' => null,
'convolve' => null,
'rotateAfter' => null,
'interlace' => null,
// Output format
'outputFormat' => null,
@@ -2102,11 +2082,8 @@ class CImage
{
$file = $file ? $file : $this->pathToImage;
// Special case to solve Windows 2 WSL integration
if (!defined('WINDOWS2WSL')) {
is_readable($file)
or $this->raiseError('Image file does not exist.');
}
is_readable($file)
or $this->raiseError('Image file does not exist.');
$info = list($this->width, $this->height, $this->fileType) = getimagesize($file);
if (empty($info)) {
@@ -2172,15 +2149,13 @@ class CImage
$this->log("Init dimension (before) newWidth x newHeight is {$this->newWidth} x {$this->newHeight}.");
// width as %
if ($this->newWidth
&& $this->newWidth[strlen($this->newWidth)-1] == '%') {
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
&& $this->newHeight[strlen($this->newHeight)-1] == '%') {
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}");
}
@@ -2332,7 +2307,7 @@ class CImage
$this->newWidth = $width;
$this->newHeight = $height;
}
// Get image dimensions for pre-resize image.
if ($this->cropToFit || $this->fillToFit) {
@@ -2551,7 +2526,6 @@ class CImage
$rotateBefore = $this->rotateBefore ? "_rb{$this->rotateBefore}" : null;
$rotateAfter = $this->rotateAfter ? "_ra{$this->rotateAfter}" : null;
$lossy = $this->lossy ? "_l" : null;
$interlace = $this->interlace ? "_i" : null;
$saveAs = $this->normalizeFileExtension();
$saveAs = $saveAs ? "_$saveAs" : null;
@@ -2618,7 +2592,7 @@ class CImage
. $quality . $filters . $sharpen . $emboss . $blur . $palette
. $optimize . $compress
. $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor
. $convolve . $copyStrat . $lossy . $interlace . $saveAs;
. $convolve . $copyStrat . $lossy . $saveAs;
return $this->setTarget($file, $base);
}
@@ -2938,7 +2912,7 @@ class CImage
// Resize by crop to fit
$this->log("Resizing using strategy - Crop to fit");
if (!$this->upscale
if (!$this->upscale
&& ($this->width < $this->newWidth || $this->height < $this->newHeight)) {
$this->log("Resizing - smaller image, do not upscale.");
@@ -3517,7 +3491,7 @@ class CImage
$this->jpegOptimizeCmd = null;
}
if (array_key_exists("png_lossy", $options)
if (array_key_exists("png_lossy", $options)
&& $options['png_lossy'] !== false) {
$this->pngLossy = $options['png_lossy'];
$this->pngLossyCmd = $options['png_lossy_cmd'];
@@ -3581,10 +3555,8 @@ class CImage
return;
}
if (!defined("WINDOWS2WSL")) {
is_writable($this->saveFolder)
is_writable($this->saveFolder)
or $this->raiseError('Target directory is not writable.');
}
$type = $this->getTargetImageExtension();
$this->Log("Saving image as " . $type);
@@ -3592,12 +3564,6 @@ class CImage
case 'jpeg':
case 'jpg':
// Set as interlaced progressive JPEG
if ($this->interlace) {
$this->Log("Set JPEG image to be interlaced.");
$res = imageinterlace($this->image, true);
}
$this->Log("Saving image as JPEG to cache using quality = {$this->quality}.");
imagejpeg($this->image, $this->cacheFileName, $this->quality);
@@ -3936,18 +3902,18 @@ class CImage
$lastModified = filemtime($this->pathToImage);
$details['srcGmdate'] = gmdate("D, d M Y H:i:s", $lastModified);
$details['cache'] = basename($this->cacheFileName ?? "");
$lastModified = filemtime($this->cacheFileName ?? "");
$details['cache'] = basename($this->cacheFileName);
$lastModified = filemtime($this->cacheFileName);
$details['cacheGmdate'] = gmdate("D, d M Y H:i:s", $lastModified);
$this->load($file);
$details['filename'] = basename($file ?? "");
$details['filename'] = basename($file);
$details['mimeType'] = $this->getMimeType($this->fileType);
$details['width'] = $this->width;
$details['height'] = $this->height;
$details['aspectRatio'] = round($this->width / $this->height, 3);
$details['size'] = filesize($file ?? "");
$details['size'] = filesize($file);
$details['colors'] = $this->colorsTotal($this->image);
$details['includedFiles'] = count(get_included_files());
$details['memoryPeek'] = round(memory_get_peak_usage()/1024/1024, 3) . " MB" ;
@@ -4146,15 +4112,6 @@ class CCache
return $path;
}
if ($create && defined('WINDOWS2WSL')) {
// Special case to solve Windows 2 WSL integration
$path = $this->path . "/" . $subdir;
if (mkdir($path)) {
return realpath($path);
}
}
if ($create && is_writable($this->path)) {
$path = $this->path . "/" . $subdir;
@@ -4461,22 +4418,6 @@ class CFastTrackCache
*
*/
/**
* Custom exception handler.
*/
set_exception_handler(function ($exception) {
errorPage(
"<p><b>img.php: Uncaught exception:</b> <p>"
. $exception->getMessage()
. "</p><pre>"
. $exception->getTraceAsString()
. "</pre>",
500
);
});
/**
* Get configuration options from file, if the file exists, else use $config
* if its defined or create an empty $config.
@@ -4639,7 +4580,7 @@ $hotlinkingWhitelist = getConfig('hotlinking_whitelist', array());
$serverName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : null;
$referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;
$refererHost = parse_url($referer ?? "", PHP_URL_HOST);
$refererHost = parse_url($referer, PHP_URL_HOST);
if (!$allowHotlinking) {
if ($passwordMatch) {
@@ -4738,7 +4679,7 @@ $allowRemote = getConfig('remote_allow', false);
if ($allowRemote && $passwordMatch !== false) {
$cacheRemote = $cache->getPathToSubdir("remote");
$pattern = getConfig('remote_pattern', null);
$img->setRemoteDownload($allowRemote, $cacheRemote, $pattern);
@@ -4772,11 +4713,11 @@ if (isset($shortcut)
/**
* src - the source image file.
*/
$srcImage = urldecode(get('src', ""))
$srcImage = urldecode(get('src'))
or errorPage('Must set src-attribute.', 404);
// Get settings for src-alt as backup image
$srcAltImage = urldecode(get('src-alt', ""));
$srcAltImage = urldecode(get('src-alt', null));
$srcAltConfig = getConfig('src_alt', null);
if (empty($srcAltImage)) {
$srcAltImage = $srcAltConfig;
@@ -4834,7 +4775,7 @@ if ($dummyEnabled && $srcImage === $dummyFilename) {
matching file exists on the filesystem.',
404
);
}
}
}
if ($imagePathConstraint && !$dummyImage && !$remoteSource) {
@@ -4893,7 +4834,7 @@ if (isset($sizes[$newWidth])) {
}
// Support width as % of original width
if ($newWidth && $newWidth[strlen($newWidth)-1] == '%') {
if ($newWidth[strlen($newWidth)-1] == '%') {
is_numeric(substr($newWidth, 0, -1))
or errorPage('Width % not numeric.', 404);
} else {
@@ -4918,7 +4859,7 @@ if (isset($sizes[$newHeight])) {
}
// height
if ($newHeight && $newHeight[strlen($newHeight)-1] == '%') {
if ($newHeight[strlen($newHeight)-1] == '%') {
is_numeric(substr($newHeight, 0, -1))
or errorPage('Height % out of range.', 404);
} else {
@@ -4949,7 +4890,7 @@ $aspectRatioConstant = getConfig('aspect_ratio_constant', function () {
// Check to replace predefined aspect ratio
$aspectRatios = call_user_func($aspectRatioConstant);
$negateAspectRatio = ($aspectRatio && $aspectRatio[0] == '!') ? true : false;
$negateAspectRatio = ($aspectRatio[0] == '!') ? true : false;
$aspectRatio = $negateAspectRatio ? substr($aspectRatio, 1) : $aspectRatio;
if (isset($aspectRatios[$aspectRatio])) {
@@ -5373,18 +5314,6 @@ if ($cacheControl) {
/**
* interlace - Enable configuration for interlaced progressive JPEG images.
*/
$interlaceConfig = getConfig('interlace', null);
$interlaceValue = getValue('interlace', null);
$interlaceDefined = getDefined('interlace', true, null);
$interlace = $interlaceValue ?? $interlaceDefined ?? $interlaceConfig;
verbose("interlace (configfile) = ", $interlaceConfig);
verbose("interlace = ", $interlace);
/**
* Prepare a dummy image and use it as source image.
*/
@@ -5546,7 +5475,6 @@ if (is_callable($hookBeforeCImage)) {
'blur' => $blur,
'convolve' => $convolve,
'rotateAfter' => $rotateAfter,
'interlace' => $interlace,
// Output format
'outputFormat' => $outputFormat,
@@ -5602,8 +5530,7 @@ EOD;
/**
* Load, process and output the image
*/
$img->log("PHP version: " . phpversion())
->log("Incoming arguments: " . print_r(verbose(), 1))
$img->log("Incoming arguments: " . print_r(verbose(), 1))
->setSaveFolder($cachePath)
->useCache($useCache)
->setSource($srcImage, $imagePath)
@@ -5636,7 +5563,6 @@ $img->log("PHP version: " . phpversion())
'blur' => $blur,
'convolve' => $convolve,
'rotateAfter' => $rotateAfter,
'interlace' => $interlace,
// Output format
'outputFormat' => $outputFormat,

View File

@@ -38,7 +38,7 @@ $config = array(
// Version of cimage and img.php
define("CIMAGE_VERSION", "v0.8.6 (2023-10-27)");
define("CIMAGE_VERSION", "v0.7.18 (2016-08-09)");
// For CRemoteImage
define("CIMAGE_USER_AGENT", "CImage/" . CIMAGE_VERSION);
@@ -118,6 +118,22 @@ function errorPage($msg, $type = 500)
/**
* Custom exception handler.
*/
set_exception_handler(function ($exception) {
errorPage(
"<p><b>img.php: Uncaught exception:</b> <p>"
. $exception->getMessage()
. "</p><pre>"
. $exception->getTraceAsString()
. "</pre>",
500
);
});
/**
* Get input from query string or return default value if not set.
*
@@ -158,25 +174,6 @@ function getDefined($key, $defined, $undefined)
/**
* Get value of input from query string or else $undefined.
*
* @param mixed $key as string or array of string values to look for in $_GET.
* @param mixed $undefined value to return when $key has no, or empty value in $_GET.
*
* @return mixed value as or $undefined.
*/
function getValue($key, $undefined)
{
$val = get($key);
if (is_null($val) || $val === "") {
return $undefined;
}
return $val;
}
/**
* Get value from config array or default if key is not set in config array.
*
@@ -202,7 +199,7 @@ function getConfig($key, $default)
*
* @return void or array.
*/
function verbose($msg = null, $arg = "")
function verbose($msg = null)
{
global $verbose, $verboseFile;
static $log = array();
@@ -215,15 +212,7 @@ function verbose($msg = null, $arg = "")
return $log;
}
if (is_null($arg)) {
$arg = "null";
} elseif ($arg === false) {
$arg = "false";
} elseif ($arg === true) {
$arg = "true";
}
$log[] = $msg . $arg;
$log[] = $msg;
}
@@ -465,7 +454,7 @@ class CHttpGet
{
$type = isset($this->response['header']['Content-Type'])
? $this->response['header']['Content-Type']
: '';
: null;
return preg_match('#[a-z]+/[a-z]+#', $type)
? $type
@@ -1143,7 +1132,6 @@ class CAsciiArt
* @example http://dbwebb.se/opensource/cimage
* @link https://github.com/mosbth/cimage
*/
#[AllowDynamicProperties]
class CImage
{
@@ -1561,13 +1549,6 @@ class CImage
/*
* Use interlaced progressive mode for JPEG images.
*/
private $interlace = false;
/*
* Image copy strategy, defaults to RESAMPLE.
*/
@@ -1817,9 +1798,9 @@ class CImage
*
* @return string $extension as a normalized file extension.
*/
private function normalizeFileExtension($extension = "")
private function normalizeFileExtension($extension = null)
{
$extension = strtolower($extension ? $extension : $this->extension ?? "");
$extension = strtolower($extension ? $extension : $this->extension);
if ($extension == 'jpeg') {
$extension = 'jpg';
@@ -1983,7 +1964,6 @@ class CImage
'blur' => null,
'convolve' => null,
'rotateAfter' => null,
'interlace' => null,
// Output format
'outputFormat' => null,
@@ -2102,11 +2082,8 @@ class CImage
{
$file = $file ? $file : $this->pathToImage;
// Special case to solve Windows 2 WSL integration
if (!defined('WINDOWS2WSL')) {
is_readable($file)
or $this->raiseError('Image file does not exist.');
}
is_readable($file)
or $this->raiseError('Image file does not exist.');
$info = list($this->width, $this->height, $this->fileType) = getimagesize($file);
if (empty($info)) {
@@ -2172,15 +2149,13 @@ class CImage
$this->log("Init dimension (before) newWidth x newHeight is {$this->newWidth} x {$this->newHeight}.");
// width as %
if ($this->newWidth
&& $this->newWidth[strlen($this->newWidth)-1] == '%') {
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
&& $this->newHeight[strlen($this->newHeight)-1] == '%') {
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}");
}
@@ -2332,7 +2307,7 @@ class CImage
$this->newWidth = $width;
$this->newHeight = $height;
}
// Get image dimensions for pre-resize image.
if ($this->cropToFit || $this->fillToFit) {
@@ -2551,7 +2526,6 @@ class CImage
$rotateBefore = $this->rotateBefore ? "_rb{$this->rotateBefore}" : null;
$rotateAfter = $this->rotateAfter ? "_ra{$this->rotateAfter}" : null;
$lossy = $this->lossy ? "_l" : null;
$interlace = $this->interlace ? "_i" : null;
$saveAs = $this->normalizeFileExtension();
$saveAs = $saveAs ? "_$saveAs" : null;
@@ -2618,7 +2592,7 @@ class CImage
. $quality . $filters . $sharpen . $emboss . $blur . $palette
. $optimize . $compress
. $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor
. $convolve . $copyStrat . $lossy . $interlace . $saveAs;
. $convolve . $copyStrat . $lossy . $saveAs;
return $this->setTarget($file, $base);
}
@@ -2938,7 +2912,7 @@ class CImage
// Resize by crop to fit
$this->log("Resizing using strategy - Crop to fit");
if (!$this->upscale
if (!$this->upscale
&& ($this->width < $this->newWidth || $this->height < $this->newHeight)) {
$this->log("Resizing - smaller image, do not upscale.");
@@ -3517,7 +3491,7 @@ class CImage
$this->jpegOptimizeCmd = null;
}
if (array_key_exists("png_lossy", $options)
if (array_key_exists("png_lossy", $options)
&& $options['png_lossy'] !== false) {
$this->pngLossy = $options['png_lossy'];
$this->pngLossyCmd = $options['png_lossy_cmd'];
@@ -3581,10 +3555,8 @@ class CImage
return;
}
if (!defined("WINDOWS2WSL")) {
is_writable($this->saveFolder)
is_writable($this->saveFolder)
or $this->raiseError('Target directory is not writable.');
}
$type = $this->getTargetImageExtension();
$this->Log("Saving image as " . $type);
@@ -3592,12 +3564,6 @@ class CImage
case 'jpeg':
case 'jpg':
// Set as interlaced progressive JPEG
if ($this->interlace) {
$this->Log("Set JPEG image to be interlaced.");
$res = imageinterlace($this->image, true);
}
$this->Log("Saving image as JPEG to cache using quality = {$this->quality}.");
imagejpeg($this->image, $this->cacheFileName, $this->quality);
@@ -3936,18 +3902,18 @@ class CImage
$lastModified = filemtime($this->pathToImage);
$details['srcGmdate'] = gmdate("D, d M Y H:i:s", $lastModified);
$details['cache'] = basename($this->cacheFileName ?? "");
$lastModified = filemtime($this->cacheFileName ?? "");
$details['cache'] = basename($this->cacheFileName);
$lastModified = filemtime($this->cacheFileName);
$details['cacheGmdate'] = gmdate("D, d M Y H:i:s", $lastModified);
$this->load($file);
$details['filename'] = basename($file ?? "");
$details['filename'] = basename($file);
$details['mimeType'] = $this->getMimeType($this->fileType);
$details['width'] = $this->width;
$details['height'] = $this->height;
$details['aspectRatio'] = round($this->width / $this->height, 3);
$details['size'] = filesize($file ?? "");
$details['size'] = filesize($file);
$details['colors'] = $this->colorsTotal($this->image);
$details['includedFiles'] = count(get_included_files());
$details['memoryPeek'] = round(memory_get_peak_usage()/1024/1024, 3) . " MB" ;
@@ -4146,15 +4112,6 @@ class CCache
return $path;
}
if ($create && defined('WINDOWS2WSL')) {
// Special case to solve Windows 2 WSL integration
$path = $this->path . "/" . $subdir;
if (mkdir($path)) {
return realpath($path);
}
}
if ($create && is_writable($this->path)) {
$path = $this->path . "/" . $subdir;
@@ -4461,22 +4418,6 @@ class CFastTrackCache
*
*/
/**
* Custom exception handler.
*/
set_exception_handler(function ($exception) {
errorPage(
"<p><b>img.php: Uncaught exception:</b> <p>"
. $exception->getMessage()
. "</p><pre>"
. $exception->getTraceAsString()
. "</pre>",
500
);
});
/**
* Get configuration options from file, if the file exists, else use $config
* if its defined or create an empty $config.
@@ -4639,7 +4580,7 @@ $hotlinkingWhitelist = getConfig('hotlinking_whitelist', array());
$serverName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : null;
$referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;
$refererHost = parse_url($referer ?? "", PHP_URL_HOST);
$refererHost = parse_url($referer, PHP_URL_HOST);
if (!$allowHotlinking) {
if ($passwordMatch) {
@@ -4738,7 +4679,7 @@ $allowRemote = getConfig('remote_allow', false);
if ($allowRemote && $passwordMatch !== false) {
$cacheRemote = $cache->getPathToSubdir("remote");
$pattern = getConfig('remote_pattern', null);
$img->setRemoteDownload($allowRemote, $cacheRemote, $pattern);
@@ -4772,11 +4713,11 @@ if (isset($shortcut)
/**
* src - the source image file.
*/
$srcImage = urldecode(get('src', ""))
$srcImage = urldecode(get('src'))
or errorPage('Must set src-attribute.', 404);
// Get settings for src-alt as backup image
$srcAltImage = urldecode(get('src-alt', ""));
$srcAltImage = urldecode(get('src-alt', null));
$srcAltConfig = getConfig('src_alt', null);
if (empty($srcAltImage)) {
$srcAltImage = $srcAltConfig;
@@ -4834,7 +4775,7 @@ if ($dummyEnabled && $srcImage === $dummyFilename) {
matching file exists on the filesystem.',
404
);
}
}
}
if ($imagePathConstraint && !$dummyImage && !$remoteSource) {
@@ -4893,7 +4834,7 @@ if (isset($sizes[$newWidth])) {
}
// Support width as % of original width
if ($newWidth && $newWidth[strlen($newWidth)-1] == '%') {
if ($newWidth[strlen($newWidth)-1] == '%') {
is_numeric(substr($newWidth, 0, -1))
or errorPage('Width % not numeric.', 404);
} else {
@@ -4918,7 +4859,7 @@ if (isset($sizes[$newHeight])) {
}
// height
if ($newHeight && $newHeight[strlen($newHeight)-1] == '%') {
if ($newHeight[strlen($newHeight)-1] == '%') {
is_numeric(substr($newHeight, 0, -1))
or errorPage('Height % out of range.', 404);
} else {
@@ -4949,7 +4890,7 @@ $aspectRatioConstant = getConfig('aspect_ratio_constant', function () {
// Check to replace predefined aspect ratio
$aspectRatios = call_user_func($aspectRatioConstant);
$negateAspectRatio = ($aspectRatio && $aspectRatio[0] == '!') ? true : false;
$negateAspectRatio = ($aspectRatio[0] == '!') ? true : false;
$aspectRatio = $negateAspectRatio ? substr($aspectRatio, 1) : $aspectRatio;
if (isset($aspectRatios[$aspectRatio])) {
@@ -5373,18 +5314,6 @@ if ($cacheControl) {
/**
* interlace - Enable configuration for interlaced progressive JPEG images.
*/
$interlaceConfig = getConfig('interlace', null);
$interlaceValue = getValue('interlace', null);
$interlaceDefined = getDefined('interlace', true, null);
$interlace = $interlaceValue ?? $interlaceDefined ?? $interlaceConfig;
verbose("interlace (configfile) = ", $interlaceConfig);
verbose("interlace = ", $interlace);
/**
* Prepare a dummy image and use it as source image.
*/
@@ -5546,7 +5475,6 @@ if (is_callable($hookBeforeCImage)) {
'blur' => $blur,
'convolve' => $convolve,
'rotateAfter' => $rotateAfter,
'interlace' => $interlace,
// Output format
'outputFormat' => $outputFormat,
@@ -5602,8 +5530,7 @@ EOD;
/**
* Load, process and output the image
*/
$img->log("PHP version: " . phpversion())
->log("Incoming arguments: " . print_r(verbose(), 1))
$img->log("Incoming arguments: " . print_r(verbose(), 1))
->setSaveFolder($cachePath)
->useCache($useCache)
->setSource($srcImage, $imagePath)
@@ -5636,7 +5563,6 @@ $img->log("PHP version: " . phpversion())
'blur' => $blur,
'convolve' => $convolve,
'rotateAfter' => $rotateAfter,
'interlace' => $interlace,
// Output format
'outputFormat' => $outputFormat,

File diff suppressed because one or more lines are too long

View File

@@ -18,43 +18,38 @@ $description = "Do not upscale image when original image (slice) is smaller than
$images = array(
'car.png',
'apple.jpg',
'tower.jpg',
);
// For each image, apply these testcases
$nc = "&bgc=660000"; //null; //"&nc"; //null; //&nc';
$nc = "&bgc=660000&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 . '&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=400&stretch',
$nc . '&w=250&h=400&no-upscale&stretch',
$nc . '&w=700&h=400&crop-to-fit',
$nc . '&w=700&h=400&no-upscale&crop-to-fit',
$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=400&crop-to-fit',
$nc . '&w=250&h=400&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=400&fill-to-fit',
$nc . '&w=250&h=400&no-upscale&fill-to-fit',
$nc . '&w=700&h=400&fill-to-fit',
$nc . '&w=700&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',
*/
$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',
);

View 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";

View 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";

View File

@@ -1,22 +0,0 @@
<?php
$links = [
"img.php?src=car.png&v",
"img.php?src=car.png&w=700&v",
];
?><!doctype html>
<html>
<head>
<title>Links to use for testing</title>
</head>
<body>
<h1>Links useful for testing</h1>
<p>A collection of linkt to use to test various aspects of the cimage process.</p>
<ul>
<?php foreach ($links as $link) : ?>
<li><a href="<?= $link ?>"><?= $link ?></a></li>
<?php endforeach; ?>
</ul>
</body>
</html>