Giter Club home page Giter Club logo

imgscalr's Introduction

imgscalr - Java Image-Scaling Library

Changelog
---------
4.2
	* Added support for a new Method.ULTRA_QUALITY scaling method.
	
	This new method uses 3.5x more incremental steps when scaling an image down
	than the QUALITY method, providing a much more accurate result. This is
	especially noticeable in thumbnails that have diagonal lines that get jagged
	during down-sizing with QUALITY or lower methods.
	
	The quality of the ULTRA_QUALITY scaling method is almost on par with the
	image resize functionality built into Mac OS X; that is to say it is better
	than GIMP's Lancsoz3 and Windows 7 built-in resize.
	
	#61
	
	* Fixed subtle bug with incremental scaling and Mode.FIT_EXACT causing the
	incremental scaling to stop too soon resulting in the wrong-sized result
	image.
	
	The stop-condition for incremental scaling assumed that in every case the
	width AND height would be shrinking each iteration; when using 
	Mode.FIT_EXACT this is not necessarily true as one dimension may not change
	at all or stop changing before another.
	
	#65 

4.1
	* Fixed NullPointerException that occurred when debugging was enabled
	#60
	
	Required a patch-release due to the show-stopping nature of the bug.

4.0
	* [BREAKING] Package has changed from com.thebuzzmedia.imgscalr to 
	org.imgscalr - I am sorry for the inconvenience of this, but this is
	necessary. There will be a family of imgscalr-based Java utilities coming
	out in the future (ExifTool is next) that will all be under this umbrella.
	
	* [BREAKING] Java 6 is now required for using imgscalr. 
	
	The reason for this is because imgscalr includes specific types of 
	ResizeOp and ColorConvertOps that actually segfault the latest Java 5 VM 
	when applied, but run fine in Java 6 and 7.
	
	imgscalr cannot knowingly ship VM-segfaulting code that could would 
	introduce a potentially	devastating situation into client applications.
	
	This decision was not made lightly, but with Java 5 end-of-lifed and Java 6
	being out for 5 years, it seemed like a reasonable requirement.

	* [BREAKING] Rotation enum was totally redefined. All rotations were 
	redefined in terms of 90,180,270 quadrant rotations as well as h/v FLIP.
	
	* [BREAKING] All resize(...) methods that accepted Rotation enums are 
	removed. All graphic operations are now separate and discrete, but can be
	easily combined when multiple effects are wanted.
	
	* Added apply() support for applying an arbitrary list of BufferedImageOps
	SAFELY and efficiently working around all the bugs in the JDK pertaining
	to BufferedImageOps (also used internally when applying any optionally 
	specified ops).
	
	* Added crop() support.
	
	* Added pad() support.
	
	* Added rotate() support.
	
	* All graphic operations (even new ones) were modified to allow the 
	application of 1 or more BufferedImageOps to a final image result before
	returning it for convenience.
	
	* Support for all the new operations (apply, crop, pad, rotate) were all 
	added to AsyncScalr so these operations can all be asynchronously performed 
	as well.
	
	* Added support for horizontal and vertical flipping of the image via the
	Rotation enum and new rotate() method.
	
	* Added pre-defined OP_DARKER and OP_BRIGHTER operations that can be applied
	to any image to make them darker or brighter (respectively) by 10%.
	
	* Added Mode.FIT_EXACT to support (for the first time) scaling images 
	forced into a specific given dimension instead of honoring the image's
	orientation and proportions automatically. 
	
	* AsyncScalr's use of ExecutorService was rewritten; no more support for
	passing in custom ExecutorService implementations or modifying existing ones
	on the fly and having the class do something magic to them under the
	covers (that was bad) -- just extend the class and specify your own logic.
	
	* AsyncScalr can be easily customized now through a single method:
	
		- createService()
		  OR
		- createService(ThreadFactory)
		
	* AsyncScalr provides two custom ThreadFactory implementations for subclasses
	to use if they want to customize the types of Threads generated and used 
	internally for async scale operations.
	
		- DefaultThreadFactory creates default threads with all default settings.
		- ServerThreadFactory generates threads that are optimized to execute in
		  a server environment (daemon threads w/ LOW_PRIORITY).
	
	* AsyncScalr.DEFAULT_THREAD_COUNT was removed and replaced with THREAD_COUNT
	that can be customized and set via system properties.
	
	* AsyncScalr.THREAD_COUNT's property name was separated into a String constant
	to make it easier to work with.
	
	* Simplified the resize() calls as a result of making all operations discrete;
	8 duplicate methods accepting "rotation" arguments were removed.
	
	* Optimized the application of BufferedImageOps.
	
	* Fixed a bug in the application of BufferedImageOps which could have led
	to an ImagingOpException bubbling up from native Java2D or a corrupt (black)
	image for poorly supported image types.
	
	* Memory optimized the application of 2 or more BufferedImageOps (interim
	images are explicitly cleaned up just like in incremental scaling).
	
	* Optimized log() implementation to avoid StringBuilder creation and string
	concatenation. Should be significant run-time savings over time if you are
	running in an environment with debugging turned on.
	
	* Removed the identity-return functionality in each method to throw an 
	exception instead of silently returning "src" unchanged.
	
	This was done intentionally to avoid users getting caught in the situation
	where they have code that automatically calls flush() on "src" after an
	imgscalr method has returned (assuming they NOW have a modified copy to work
	with). 
	
	In the case of sending in invalid or null arguments, previously imgscalr
	would return "src" unchanged, which means the caller would be calling
	flush() on a perfectly good image they still needed and not a copy as was
	assumed by using imgscalr (And there would be no way to tell if imgscalr had
	created a copy or not without using an == check with EVERY returned image
	result).
	
	Instead, invalid or missing arguments passed to any imgscalr method are
	now considered an exception so the caller knows IMMEDIATELY when something
	is wrong and won't get magically different/unexpected behavior.
	
	* Exposed the potential for every method to fire an ImagingOpException if
	one of the BufferedImageOps fails to apply using the hardware-accelerated
	underlying Java2D code path. These exceptions were previously hidden in the
	guts of Java2D and could bubble up unexpectedly, now they are clearly defined
	directly on the imgscalr API so they can be cause and handled IF the caller
	wants or needs to do that when using custom BufferedImageOps.
	
	* Detailed notations about performance optimizations the caller can make to
	ensure their handling of images are as performant as possible were added to
	all the methods as a convenience.
	
	* Defined DEBUG system property name as a public constant that can be used
	to help avoid misspellings when trying to set debugging on.
	
	* Modified LOG_PREFIX so it can now be set via the "imgscalr.logPrefix" 
	system property value now.
	
	* Rewrote imgscalr test suite to specifically test all discrete operations
	and all variations of the operations as well.
	
	* Added AllTests test suite so all tests can be easily run at one time to
	verify the release.
	
	* Rewrote Javadoc covering a lot of the return and exception conditions for
	all the methods to more clearly communicate what is happening inside the
	method and to the original images.
	

3.2
	* Added support for asynchronous & rate-limited scaling operations via the
	AsyncScalr class.
	
	The AsyncScalr class wraps the parent Scalr class and submits scale jobs to
	an internal ExecutorService. The executor service can be used to serialize
	and queue up scaling operations to avoid blowing the heap and overloading the
	underlying host on a busy, multi-user system (e.g. a web app running imgscalr).
	
	AsyncScalr by default uses a fixed-size ThreadPoolExecutor that can be modified
	at run time to any tuned level of threads the caller desires (default 2). The
	default settings are intended to be safe/efficient to use out of the box on 
	most all systems.
	
	Additionally, AsyncScalr can be configured to use *any* ExecutorService 
	implementation passed to it so callers have ultimate control over how the 
	AsyncScalr processes jobs if they need/want it.
	
	Typically it is a good idea to roughly map # of Scaling Threads to the # of 
	Cores on the server, especially on a server with plenty of memory and a large
	heap for the VM.
	
	If you are running inside of a smaller VM heap or lower-memory server (regardless
	of core count) you will want to limit the number of simultaneous scale operations
	so as not to saturate the heap during scaling when the images are read into
	internal BufferedImage instances in VM memory.

	* Added support for Rotation to the library. You can now specify the following
	rotations to be applied to your image:
	
	Rotation.NONE - No rotation.
	Rotation.CLOCKWISE - Clockwise (90 degrees to the right) rotation.
	Rotation.COUNTER_CLOCKWISE - Counter-clockwise (90 degrees to the left) rotation.
	Rotation.FLIP - Flip the image (180 degrees rotation).
	
	The rotation is performed as tightly and efficiently as possible, explicitly
	cleaning up temporary resources created during the operation.
	
	* API was simplified as duplicate methods without the vararg parameter were
	removed (these were effectively duplicates of the vararg methods make the
	API longer than it needed to be).
	
	* Corrected a multitude of incorrect Javadoc comments pertaining to @throws
	conditions.
	
	* Rewrote the method Javadoc. Manually reviewing uncovered too many copy-paste
	discrepancies that left out important information that would be helpful in
	a  Javadoc popup in an IDE while using imgscalr.
	
	* All new code heavily commented.

3.1
	* You can now specify Mode.FIT_TO_WIDTH or Mode.FIT_TO_HEIGHT behaviors
	when resizing an image to get imgscalr to treat one dimension as the primary
	and recalculate the other dimension to best fit it, regardless of the image's
	orientation. Previously this was decided automatically for you by the
	orientation of the image.
	
	* resize methods now accept 0 or more BufferedImageOps as var-arg arguments.
	
	* Workaround for a 10-year-old JDK bug that causes RasterExceptions to get
	thrown from inside of Java2D when using BufferedImageOps was built directly
	into imgscalr so you don't have to worry about RasterExceptions. More
	info here: https://github.com/rkalla/imgscalr/issues/closed#issue/23
	
	* API was made more strict and an IAE is thrown if 'src' is null to any of
	the resize operations; a user reported that he spent a while debugging why
	"imgscalr wasn't working" only to find out it was silently returning due to
	a null source image. Would have been helpful if imgscalr had notified him of
	the issue immediately.

3.0
	* Big thanks to Magnus Kvalheim from http://www.movellas.com/ for help with
	this release!
	
	* Support for hardware-accelerated BufferedImageOp's was added to the library.
	You can now provide an optional BufferedImageOp to many of the methods in the
	imgscalr library and it will be applied to the resultant image before returning
	it. 
	
	* Most common request was for imgscalr to apply an "anti-aliasing" filter to
	results before returning them; this was achieved by adding support for
	BufferedImageOps and providing a hand-tuned ConvolveOp to provide a good
	default that can be applied easily by folks that want the effect but don't
	want to learn all about BufferedImageOps and what "convolve" even means.
	
	* Speed/Balance/Quality THRESHOLD values were adjusted for more optimal results
	when relying on Method.AUTOMATIC to give good-looking results.
	
	* Javadoc was updated to clarify hardware acceleration behaviors.

2.1
	* Scaling of certain image types (and byte layouts) could result in very poor
	looking scaled images ("pixelated" look, discolored dithering, etc.). This was
	corrected by imgscalr forcibly scaling all source images into the most well-supported
	image types by Java2D, resulting in excellent scale result quality regardless
	of the Method specified.
	
	* The issue of scaling of poorly supported (by Java2D) image-types can lead 
	to unexpectedly poor performance was also corrected as a side-effect of this
	because all source images are converted to the most commonly supported image
	type for Java2D.

2.0
	* API-break: resize(BufferedImage, Method, int, int, boolean, boolean) was removed and
	replaced by resize(BufferedImage, Method, int, int).
	
	* DEBUG system variable added; set 'imgscalr.debug' to true to trigger debugging output
	in the console. The boolean debug and elapsedTime arguments to the resize method
	have been removed.
	
	* New BALANCED method added. Provides a better result than SPEED faster than QUALITY.
	
	* Added 2 optimized thresholds (in pixels) that the API uses to select the best Method
	for scaling when the user specifies AUTOMATIC (or doesn't specify a method). This helps
	provide much better results out of the box by default and tightens up the performance of the
	API a bit more.
	
	* Image comparison generator utility (ComparisonGenerator test class) added.
	
	* Functional portions of API broken into static protected methods that can be
	easily overridden by implementors to customize the API without needing to rewrite
	the resize methods.
	
	* Consolidated 5 locations of duplicated rendering code into a single method (scaleImage).
	
	* Tightened up image scaling operation to do everything possible to avoid memory leaks (every native
	resource is disposed or released explicitly)
	
	* Detailed logging information integrated. If the 'imgscalr.debug' system property is
	true, the API outputs exactly what it's doing, what argument values it is processing and
	how long it is taking to do each scale operation.
	
	* When AUTOMATIC method is specified, the API is more intelligent about selecting
	SPEED, BALANCED or QUALITY based on the images primary dimension only (more accurate).
	
	* Copious amounts of Javadoc added to new methods, new code and existing code. 
	
	Issues Resolved in 2.0:
	https://github.com/rkalla/imgscalr/issues/closed

1.2
	* Default proportional-scaling logic is more straight forward. If an image is
	landscape then width is the preferred dimension and the given height is ignored
	(and recalculated) and visa-versa if the image is portrait oriented. This gives
	much better "default behavior" results.
	
	* Added new convenience method resize(BufferedImage,int,int)
	
	* Modified build.xml to output Maven-friendly artifact names.
	
	Issues Resolved in 1.2:
	https://github.com/rkalla/imgscalr/issues/closed

1.1
	* Initial public release.


License
-------
This library is released under the Apache 2 License. See LICENSE.


Description
-----------
A class implementing performant (hardware accelerated), good-looking and 
intelligent image-scaling algorithms in pure Java 2D. This class implements the 
Java2D "best practices" when it comes to scaling images as well as Chris 
Campbell's incremental scaling algorithm proposed as the best method for 
down-sizes images for use as thumbnails (along with some additional minor 
optimizations).

imgscalr also provides support for applying arbitrary BufferedImageOps against
resultant images directly in the library.

TIP: imgscalr provides a default "anti-aliasing" Op that will very lightly soften
an image; this was a common request. Check Scalr.OP_ANTIALIAS

TIP: All resizing operations maintain the original images proportions.

TIP: You can ask imgscalr to fit an image to a specific width or height regardless 
of its orientation using a Mode argument.

This class attempts to make scaling images in Java as simple as possible by providing
a handful of approaches tuned for scaling as fast as possible or as best-looking 
as possible and the ability to let the algorithm choose for you to optionally create 
the best-looking scaled image as fast as possible without boring you with the details 
if you don't want them.


Example
-------
In the simplest use-case where an image needs to be scaled to proportionally fit 
a specific width (say 150px for a thumbnail) and the class is left to decide which 
method will look the best, the code would look like this:

  BufferedImage srcImage = ImageIO.read(...); // Load image
  BufferedImage scaledImage = Scalr.resize(srcImage, 150); // Scale image

You could even flatten that out further if you simply wanted to scale the image 
and write out the scaled result immediately to a single line:

  ImageIO.write(Scalr.resize(ImageIO.read(...), 150));


Working with GIFs
-----------------
Java's support for writing GIF is... terrible. In Java 5 is was patent-encumbered
which made it mostly totally broken. In Java 6 the quantizer used to downsample
colors to the most accurate 256 colors was fast but inaccurate, yielding 
poor-looking results. The handling of an alpha channel (transparency) while writing
out GIF files (e.g. ImageIO.write(...)) was non-existent in Java 5 and in Java 6
would remove the alpha channel completely and replace it with solid BLACK.

In Java 7, support for writing out the alpha channel was added but unfortunately
many of the remaining image operations (like ConvoleOp) still corrupt the
resulting image when written out as a GIF.

NOTE: Support for scaling animated GIFs don't work at all in any version.

My recommendation for working with GIFs is as follows in order of preference:

1. Save the resulting BufferedImage from imgscalr as a PNG; it looks
better as no quantizer needs to be used to cull down the color space and 
transparency is maintained. 

2. If you mostly need GIF, check the resulting BufferedImage.getType() to see
if it is TYPE_INT_RGB (no transparency) or TYPE_INT_ARGB (transparency); if the
type is ARGB, then save the image as a PNG to maintain the alpha channel, if not,
you can safely save it as a GIF.

3. If you MUST have GIF, upgrade your runtime to Java 7 and save your images as
GIF. If you run Java 6, any GIF using transparency will have the transparent
channel replaced with BLACK and in Java 5 I think the images will most all be
corrupt/invalid.

REMINDER: Even in Java 7, applying some BufferedImageOps (like ConvolveOp) to
the scaled GIF before saving it totally corrupts it; so you would need to avoid
that if you didn't want to save it as a PNG. If you decide to save as a PNG, you
can apply any Ops you want.
 

Troubleshooting
---------------
Image-manipulation in Java can take more memory than the size of the source image
because the image has to be "decoded" into raw ARGB bytes when loaded into the
BufferedImage instance; fortunately on most platforms this is a hardware-accelerated
operation by the video card.

If you are running into OutOfMemoryExceptions when using this library (e.g. if you
dealing with 10+ MB source images from an ultra-high-MP DSLR) try and up the 
heap size using the "-Xmx" command line argument to your Java process.

An example of how to do this looks like:

  java -Xmx128m com.site.MyApp
  

Reference
---------
Chris Campbell Incremental Scaling - http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html


Related Projects
----------------
ExifTool for Java - https://github.com/rkalla/exiftool

imgscalr's People

Contributors

elygre avatar poxu avatar rkalla avatar rtteal avatar sidheshenator avatar silvpol avatar tc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

imgscalr's Issues

Discrete access to specific image operations

Right now all the image operations (resize, rotate and in the future crop/pad/etc.) are done by calling one of the resize methods.

It could be helpful to have direct access to that functionality without invoking a resize. For example, if you just want to crop an image.

At first glance it seems like simple crop(), flip(), rotate(), etc. methods added to Scalr would be the way to go (and then the matching methods added to AsyncScalr).

If the methods are all simple single-definitions, this is the way to go. If they can cause many different variations, may need to consider a separate Opr, Ops, ImageOps (whatever) class to include those in.

This will likely cause the removal of rotation-enabled methods on Scalr already which will be a breaking change for 4.0

Scaling of landscape-oriented images not honor dimensions

When scaling an image in a landscape orientation (320x240) the library does not honor the primary dimension of width (320) and instead scales the image based on the smallest dimension (240) resulting in an image that is 240xnew-height.

Research performance in highly-threaded environments

Need to do some in-depth testing of the library in highly threaded (e.g. server) environments and see what kinds of behaviors the library will exhibit when the heap is exhausted.

Will include a configurable test-class in the code for anyone else that wants to try it.

imgscalr does not support blur/convolve/anti-aliasing resultant images

Besides scaling down smoothly, in the case where an image is scaled down drastically (1/10th or 1/20th its original size) smoothing of the result can become important.

Current imgscalr does not support this type of operation natively; the user would have to apply additional operations to the resulting BufferedImage to get the effect.

Add ability to resize image from source InputStream

Allowing imgscalr to resize images directly from InputStreams would allow the library to be more easily integrated into additional usage scenarios and do more of the boilerplate work for users not wanting to work with ImageIO at all and "just resize the damn file".

Would make integration into file-based scenarios, DB-storage scenarios or even cloud-based scenarios much easier.

ExifTool.Tag does not add a type hint

In the current implementation of ExifTool.Tag, no type information is stored along side the Tag or it's name; it might be handy for users if a type is stored along with the name to make parsing for them easier.

If -n is not passed to ExifTool, then the long-form/friendly names for values are used instead which will no longer make the type valid.

To account for that flexibility in a safe way, the type provided should be used more as a hint and not a defactor do-or-die type conversion. This will allow people working with custom tags or custom types (maybe an older or newer version of ExifTool down the road?) to account for changes and parse things themselves without the tool exploding in a heap of fire.

Basically, plan and design for flexibility so the world doesn't melt if the ExifTool behavior changes in the future.

AUTOMATIC mode doesn't take image orientation into consideration

In AUTOMATIC mode the API uses the size of the image as an indicator of if it should choose SPEED or QUALITY (or other modes).

Right now the code is written to compare BOTH the width and height to the threshold before selecting SPEED or QUALITY, this doesn't take into consideration the orientation (portrait or landscape) of the image.

This means that images who's dimensions are quite large in their primary orientation but smaller in others are not getting the higher-quality scaling operation selected for them.

For example, an image that is scaled to 1024x400 is always getting the SPEED method selected because not both of the dimensions are less than the threshold.

Research method for ExifTool to forcibly kill stray processes

So far during development and testing the ExifTool wrapper has not left daemon ExifTool threads laying around after exit, but in preparation for potentially needing a solution to this in the future I have found some interesting notes that I want to remember in case I need to implement this in the future, in some common library.

Approach

The only universal approach that seems to work is to get a process list before launching, then right after and then record the PID of the diff process. There is a nasty potential for mis-identifying the wrong process here in the case of a very busy system spawning processes.

On windows the command 'tasklist' can be used and on Unix/Linux/Mac "ps -ax | grep exiftool" will do the trick.

Killing Processes

'kill -9' on *nix and on Windows 'taskkill' is available.

Again, this is not a bug that will be addressed, just some notes with a potential nasty side effect (of killing the wrong child process) so not something I want to jump into right now.

resize should throw an IAE if src is null

Reported by Robert Rees

All other arguments in the API cause an IllegalArgumentException to be thrown if they are null or empty and shouldn't be, except src.

This was originally done to make the API no-op on a null src and be more "exception-friendly", but as Robert's bug report shows, he spent a decent amount of time trying to figure out why imgscalr was breaking and returning null only to find out that his 'src' argument going in was null because it wasn't loading right.

The API should be pedantic and correct, not loosey-goosey.

Fit to Exact

Consider a fitto-exact mode that will stretch the picture to exactly the dimensions requested regardless of orientation or aspect ratio of the original.

ExifTool needs a way to report to caller if a feature is supported or not.

Since ExifTool will at least be integrated into imgscalr proper and possibly used by a number of external code bases directly, it would be nice if there was a mechanism by which that a caller can determine if a feature they want to use (e.g. stay_open) is supported BEFORE attempting the EXIF pull and then trying to handle a mish-mash of exceptions.

Create an imgscalr Service for use in highly-scalable apps

Scaling images, in any language, is a memory and CPU intensive operation. In highly-scalable/threaded environments, firing off MANY scale operations at the same time (e.g. a 100 users upload images that need thumbnails generated at the same time to your web app) can result in unexpected failures with a particular sub-set of the image operations as the VM will eventually run out of memory to hold all that decoded image data in ram at the same time.

imgscalr shines on the server and to make it's use easier/safer, consider creating a ScalrService that can control for this.

Based on the research from Issue #27 (#27) and what I assume will end up being fairly bad behavior once the heap is blown, the addition of a Singleton, ThreadPoolExecutor-based ScalrService that can easily be used in heavily mulit-threaded environments to more easily trim down the number of simultaneous scale operations to avoid blowing the VM heap

In a heavily multi-threaded app, it might be easier than expected to initiate so many simultaneous scale operations at the same time, that all that image data is decided and pulled into the VM simultaneously, possibly leading to the VM heap size running out of room to grow and some of the scaling operations failing while others would succeed.

The purpose of the service is to create a simple, user-configurable, intentional "choke point" to control a worst-case scenario ceiling.

For example, for a webapp that processes image uploads, if your average image upload is (say) 1MB in size, and your heap is 64MB... you may want to set the ScalrService to never do more than 2 simultaneous scale operations as fully decoded image data is typically much larger than the compressed source files. By limiting simultaneous scale ops in your app to 2 at a time, you don't need any more complex code in your app to control this.

If you have a monster dedicated image-scaling server with 72GB of ram and some hellacious dual-CPU, quad-core, HT-enabled CPU setup, you could up the ScalrService to do 100s or 1000s of scale operations simultaneously, but in your code you wouldn't need to change anything, simply call ScalrService.resize... and it will do the right thing for you.

This design also has the added advantage of taking advantage of multi-core/multi-threaded CPUs for scaling operations as the threads in the thread pool can be scheduled onto different cores/threads by the OS as they are executed.

Another advantage is the Threads are not created/destroyed every time a call is made; they would be created at service initialization time, or lazily created at first-use, but otherwise will stay around until the app is shut down.

OPTIONAL: An asynchronous approach may be considered with the core design, returning a Future object; if the caller wants an synchronous execution pattern, they can just immediately call future.getValue which will block anyway.

To keep the API simple/consistent, the async design may be the approach; it is not worth polluting the API to double up the methods and have sync ones and async ones all on the same class; ugggg

AsyncScalr.setServiceThreadCount adjustment calls are out of order

Inside the call to AsyncScalr.setServiceThreadCount the min and max thread count sizes for the ThreadPoolExecutor are called out of order.

coreSize is upped first then maxSize is uppped -- the upper bound (max) should be adjusted first THEN core (the lower bound).

Common image FX buffered image ops

Might be nice to predefine common image filters in bufferedimage ops like the anti alising one.

Black and white
Sepia
And other common filters might be handy.

Extract out the robust application of BufferedImageOps to its own method

BufferedImageOps actually have an 8-year old bug in the JDK that can cause the application of certain types of manipulations to fail with an exception or return a black/empty picture and no exception.

It is maddening.

Fortunately imgscalr works around this internally so all the BufferedImageOps passed in are handled correctly and avoid that failure case in the JDK.

This functionality should be extracted out into its own discrete method so anyone can safely (and efficiently) apply BufferedImageOps against their images even if they aren't performing a resize operation.

This is in the same vein as Issue #49: #49

User cannot demand imgscalr honor 1 dimension over the other.

Right now when an image is scaled, the width or height is preferred by the API based on the orientation of the image; there is currently no way to have the API prefer one of the dimensions over the other by force.

A common use-case would be working with portraits, like for a company profile page, where every image should be 200px wide no matter how tall it is; currently you would have to pre-calculate the right dims to ask for before calling imgscalr because it will always prefer the height of the image over the width since they are all portrait orientation and given you back different width images if their heights vary, making your life harder.

The API should provide a mechanism by which someone can specify a mode of resizing.

Support for running imgscalr from the command line

This has been asked for a few times by folks trying to integrate imgscalr into scripts or call it easily from other languages. The ability to run imgscalr from the command line could be very handy.

imgscalr does not support Flip/Rotate operations

A common operation when dealing with images is rotation; it is not uncommon for images coming off of a digital camera or cell phone to need to be flipped or rotated.

As a "best practices" image API, imgscalr should provide these simple operations in a performant way making it easy to start with 1 image and end up with a scaled/rotated/whatever image that you want.

Library doesn't support logging to non System.out streams

Currently the library only outputs to the console via System.out -- great for simple debugging purposes in simple apps, but in the case of more complex apps that need to be profiled or watched for debugging or performance metrics (like web apps) it can make it harder than necessary to find and view the output that you want to view, especially if custom logging configurations are being used by the web app.

Would be handy if the library used a standard logging mechanism that in addition to giving simple output in simple cases, can be configured to output in more complex configurations.

Ability to honor rotation of scaled images by reading EXIF data

Perfect example of why imgscalr should support this:
http://stackoverflow.com/questions/6841313/portrait-image-resizing-in-java-with-imgscalr-but-the-final-output-is-landscape

There are a handful of libraries I've evaluated for adding this support, Drew's being the most likely one. It would add a new dependency library to imgscalr unfortunately, but given the "surprise" of getting an incorrectly oriented resultant image, it can be worth it.

This isn't as simple as adding an if-condition as efficient rotation logic has to be added into imgscalr to perform the correct manipulation without burning up objects on every resize operation if avoidable.

When -stay_open support is used ExifTool checks version on every instance

As a safety check against dead-locking I/O streams, the ExifTool class actually verifies that the native ExifTool process is the required version for us with certain features (like -stay_open).

Right now the logic executes every time a new class of type ExifTool is created USING that feature.

Instead this version confirmation should be done once (in a static way) and never done again for the class in the VM because the external process that is being run to be checked is defined by the static EXIF_TOOL_PATH argument, which won't change.

The check should be run at the same level.

imgscalr does not crop sub-pixel sizes when scaling.

When scaling an image, say 600x800, down, it is possible to cause imgscalr to calculate a partial-pixel result.

For example, handing a 600x800 portrait picture to imgscalr and asking it to scale it down to 10x10 will calculate the correct dimension of 7.5x10 and SHOULD scale it to 7x10, but because of the use of Math.round, it scales it up to 8x10; resulting in a portion of image that won't be rendered to when the underlying Java2D drawImage call is made.

The fractional portion should be cropped to avoid the resulting image containing pixels that are not rendered to by the underlying operation.

No easy way to test the difference in quality/speed between the different modes

There are no test cases or generators that can be used to quickly and easily generate a directories worth of images generating results in different sizes using the different methods so users of the API can make up their own minds about which method to use.

Would also be handy to have such a generator when tweaking the different thresholds for the most effective values that the API should auto-tune for.

More fine-tuned thresholds for auto-selecting the scaling mode do not exist

Right now there is a single threshold (800px) that exists to decide if an image should be scaled using QUALITY or SPEED. More testing of the optimal threshold should be done and possibly additional thresholds to help decide between SPEED, BALANCED or QUALITY to ensure better-looking (and performing) operations from scale operations done with the AUTOMATIC method.

This was first noticed when scaling some text-heavy screenshots and noticing that the text is unreadable at average-large sizes because of the corruption the nearest-neighbor algorithm introduces.

This is not a good result for an "AUTOMATIC" mode -- people would expect a better result than this by default.

Java2D image-scaling can be slow on very rare image types

REF: http://www.mail-archive.com/[email protected]/msg05621.html

It seems when using Java2D to process rare image types (BufferedImage.TYPE_*) the pipeline used to execute operations like scaling can be very un-optimized.

The recommendation from the Java2D team is to copy the source BufferedImage contents into a new BufferedImage instance with a well-supported type (e.g. RGB or ARGB) and then process the image.

It might be worth looking into which image types are not well-supported and implement that behavior for folks, abstracting away any performance issues.

NOTE: This seems to only be an issue with the rarest of image-types and is likely a non-existent issue for 95% of use-cases. This is meant as a future research TODO.

Provide way to quickly determine image MIME type and dimensions

A common operation for an image library (especially one integrated into a file-management sequence) is to discover the MIME type of an image file (by looking at header bytes and not just the file extension) as well as the dimensions of the image as quickly as possible.

Unfortunately the only way to do this now is to decode and load the image completely into a BufferedImage (to get the dimensions) and guess at the mime type via the image type and file extension.

Fortunately there is a super-simple class written by Jaimon Mathew that can read the first handful of bytes from a file and determine exactly this information:
http://blog.jaimon.co.uk/simpleimageinfo/SimpleImageInfo.java.html

This functionality should be integrated into imgscalr directly (original license is Apache 2, so it's compatible).

Javadoc doesn't clarify performance behaviors, namely hardware-accelerated ops

With any library it is important to know, up-front, what the cost of certain ops are. Most methods in the JDK require you read through the source code to find out, in imgscalr because so much time has been taking reading through JDK classes to ensure the fastest routes were taken, it would be handy to add this to the Javadoc so users of the API know.

JPEG metadata is lost for resized images

When a JPEG image contains metadata (e.g. off of a digital or cell phone camera) and the original image is resized with imgscalr, the metadata is not retained from the original to the scaled copies. This is because reading and writing metadata, in all the formats used by camera companies, is a complex topic and no well-tested libraries exist that do both.

When the time is right, considering integrating a solution that maintains at least some (preferably all) of the metadata from the original to the resized copies.

Crop support

It may be handy to have a tightened up crop function built into imgscalr.

Has been requested in the past.

imgscalr should allow application of more than 1 BufferedImageOp

In the 3.0 release the BufferedImageOp argument is a single optional argument; there is no reason this shouldn't be a var-arg that allows multiple ops to be applied to an image.

For example, blur & rotate, or crop & blur & rotate.

It makes imgscalr more flexible both to users with custom Ops they want to provide as well as imgscalr providing good default Ops that can be easily used by the caller.

Support for utilizing the power of ExifTool

The core issue with ANY of the exif-enabled features of imgscalr is utilizing a library that is able to correctly pull that data from most all image file types.

Looking into the issue of EXIF data in image files and you find a litany of half-finished libraries or good libraries (like Drew Noakes's Metadata Extractor) that add a large dependency footprint to the simple imgscalr library.

After researching this topic for about a month, I found that Phil Harvey's ExifTool looks to be hands down the most complete and functional image (and video) metadata file library available. The project is about 10 years old and supports not only every file format know to man but reading AND writing most every scrap of metadata a file can contain.

Given that a few of the feature enhancements requested of imgscalr pertain to maintaining EXIF data in scaled copies of images (would requiring writing metadata) I think it would be best to try and provide support for ExifTool.

While ExifTool is written in Perl, it does run on all major platforms.

Consider adding rotation functionality in the library

Discussions with Michael Harris and the pain point that is resizing original JPEGs that loose their "Orientation" EXIF data after scaling... it might be worth re-investigating adding rotation of images keyed off of the image metadata using something like the metadata-extractor library.

Something like:
// Makes an attempt to figure out the rotation degree from the image's metadata.
Image i = Scalr.resize(Method.AUTOMATIC, Rotation.AUTOMATIC, 150);

or

Image i = Scalr.resize(Method.AUTOMATIC, Rotation.90_CW, 150);

or some such equivalent... could become very handy.

What killed this original impl was making it pre-defined rotation BufferedImageOps defined as constants on the class because of the origin re-homing required to get a good rotation and the immutable nature of the AffineTransform instances wrapped by the AffineTransformOps.

Might justify a custom AffineTransformOp impl that allows for the wrapped AffineTransform to be manipulated.

NOTES:
AffineTransformOp xform ref is private (can't get to it through subclassing) and getTransform returns a clone... damn it all.

Pad function

As a compliment to the crop function being considered it may be helpful to offer a simple pad function that resizes the image but fills in the new space with a solid color (provided by the caller)

May also be helpful to consider allowing anchoring of the image, but this can open up a can of enum-worms as there are 9 potential anchor points.

Will likely just default to centering the image.

Overriding default behavior of library is not easy

Right now all the logic and functionality is contained in a single static method -- if any implementors wanted to extend the library and replace certain portions of the logic inside the library it would be impossible without reimplementing the single master resize method completely.

Would be nice if logical functions were broken out into protected methods which could be easily overriden where appropriate.

Method between SPEED and QUALITY doesn't exist

There is no way to get slightly nicer looking images than available from the SPEED method without incurring the much higher cost of using QUALITY mode.

This was most notable when scaling some screenshots with text on them and noticing in SPEED mode, at any resolution, they look like total garbage, but simply applying a BILINEAR algorithm to them made them look immediately better.

There is no way to do that from the API right now.

Debug messages cannot be enabled from a system variable.

Using a method argument (debug) as the trigger to enable debugging messages leaves the API's debug functionality up to the mercy of any wrapping convenience APIs that may build ontop of this.

It is much more flexible to allow the debugging flag to be set by a system variable.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.