Giter Club home page Giter Club logo

scrimage's Introduction

Scrimage

Scrimage is a Scala image library for manipulating and processing of images. The aim of the this library is to provide a quick and easy way to do the kinds of image operations that most people need, such as scaling, rotating, converting between formats and applying filters. It is not intended to provide functionality that might be required by a more "serious" image application - such as face recognition or movement tracking.

A typical use case for this library would be creating thumbnails of images uploaded by users in a web app, or resizing a set of images to have a consistent size, or optimizing PNG uploads by users to apply maximum compression, or applying a grayscale filter in a print application.

Scrimage has a consistent, idiomatic scala, and mostly immutable API that builds on the java.awt.Image methods. I say mostly immutable because for some operations creating a copy of the underlying image would prove expensive (think an in place filter on a 8000 x 6000 image where you do not care about keeping the original in memory). For these kinds of operations Scrimage supports a MutableImage instance where operations that can be performed in place mutate the original instead of returning a copy.

Build Status

API

Operation Description Example
resize Resizes the canvas to the given dimensions. This does not scale the image but simply changes the dimensions of the canvas on which the image is sitting. Specifying a larger size will pad the image with a background color and specifying a smaller size will crop the image. image.resizeTo(500,800) for an absolute resize or image.resize(0.5) for a percentage resize
scale Scales the image to given dimensions. This operation will change both the canvas and the image. This is what most people think of when they want a "resize" operation. image.scaleTo(x,y) to specify dimensions or image.scale(percentage) for a percentage scale
pad Resizes the canvas by adding a number of pixels around the image in a given color. image.pad(20, Color.Black) would add 20 pixels of black on each edge, increasing both canvas width and height by 40 pixels.
fit Resizes the canvas to the given dimensions and scales the original image so that it is the maximum possible size inside the canvas while maintaining aspect ratio.

This operation is useful if you want a group of images to all have the same canvas dimensions while maintaining the original aspect ratios. Think thumbnails on a site like amazon where they are padded with white background.
Given a 800x600 image then image.fit(200,200,Color.White) would result in a new image of 200x200 (as specified in the call) where the original image is now 200,150 as that is the largest it can be scaled to without overflowing the canvas bounds. The additional 'spare' height of 50 pixels would be set to the given background color, white in this case.
cover Resizes the canvas to the given dimensions and scales the original image so that it is the minimum size needed to cover the new dimensions without leaving any background visible.

This operation is useful if you want to generate an avatar/thumbnail style image from a larger image where having no background is more important than cropping part of the image. Think a facebook style profile thumbnail.
Given a 64x64 image then image.cover(128,96) would result in a new image of 128x96 where the original image is now 128,128 as that is the smallest it can be scaled to without leaving any visible background. 32 pixels of the height is lost as that is "off canvas"
bound Scales the image maintaining the aspect ratio so that it fits inside the given dimensions. There is no padding included so the resultant image might not have the exact dimensions specified, but it will be as large as possible without overflowing the bounds (hence the name).

This is useful when you want to ensure images do not exceed a certain size, but you don't any padding.
Given a 800x600 image then image.bound(200,200) would scale the image to 200x150 as that is the largest it can be without overflowing the 200x200 bounds whilst maintaining the same aspect ratio.
copy Creates a new clone of this image with a new pixel buffer. Any operations on the copy do not write back to the original. image.copy
empty Creates a new image but without initializing the data buffer to any specific values. image.empty on an existing instance to use the same dimensions or Image.empty(x,y) to create a new image with the given dimensions
filled Creates a new image and initializes the data buffer to the given color. image.filled(Color.Red)
rotate left Rotates the image anti clockwise. Results in width and height being flipped. image.rotateLeft
rotate right Rotates the image clockwise. Results in width and height being flipped. image.rotateRight
flip x Flips the image horizontally. Left becomes right. image.flipX
flip y Flips the image vertically. Top becomes bottom. image.flipY
filter Returns a new image with the given filter applied. See the filters section for examples of the filters available. Filters can be chained and are applied in sequence. image.filter(BlurFilter) or image.filter(GaussianBlur(5)).filter(SepiaFilter) Most filters can be created from companion objects with sensible default values.

Quick Examples

Reading an image, scaling it to 50% using the Bicubic method, and writing out as PNG

val in = ... // input stream
val out = ... // output stream
Image(in).scale(0.5, Bicubic).write(out) // Png is default

Reading an image from a java File, applying a blur filter, then flipping it on the horizontal axis, then writing out as a Jpeg

val inFile = ... // input File
val outFile = ... // output File
Image(inFile).filter(BlurFilter).flipX.write(outFile, Format.Jpeg) // specified Jpeg

Padding an image with a 20 pixel border around the edges in red

val in = ... // input stream
val out = ... // output stream
Image(in).pad(20, Color.Red)

Enlarging the canvas of an image without scaling the image (resize method changes canvas size, scale method scales image)

val in = ... // input stream
val out = ... // output stream
Image(in).resize(600,400)

Scaling an image to a specific size using a fast non-smoothed scale

val in = ... // input stream
val out = ... // output stream
Image(in).scale(300, 200, FastScale)

Writing out a heavily compressed Jpeg thumbnail

val in = ... // input stream
val out = ... // output stream
Image(in).fit(180,120).writer(Format.JPEG).withCompression(0.5).write(out)

Printing the sizes and ratio of the image

val in = ... // input stream
val out = ... // output stream
val image = Image(in)
println(s"Width: ${image.width} Height: ${image.height} Ratio: ${image.ratio}")

Converting a byte array in JPEG to a byte array in PNG

val in : Array[Byte] = ... // array of bytes in JPEG say
val out = Image(in).write // default is PNG
val out2 = Image(in).write(Format.PNG) // to be explicit about the output format

Coverting an input stream to a maximum compressed PNG

val in : InputStream = ... // some input stream
val out : OutputStream = ... // some output stream
val compressed = Image(in).writer(Format.PNG).withMaxCompression.write(out)

Input / Output

Scrimage supports loading and saving of images in the common web formats (currently png, jpeg, gif, tiff). In addition it extends jav'sa image.io support by giving you an easy way to compress / optimize / interlace the images when saving.

To load an image simply use the Image apply methods on an input stream, file, filepath (String) or a byte array. The format does not matter as the underlying reader will determine that. Eg,

val in = ... // a handle to an input stream
val image = Image(in)

To save a method, Scrimage provides an ImageWriter for each format it supports. An ImageWriter supports saving to a File, filepath (String), byte array, or OutputStream. The quickest way to use an ImageWriter is to call write() on an image, which will get a handle to an ImageWriter with the default configuration and use it for you. Eg,

val image = ... // some image
image.write(new File("/home/sam/spaghetti.png"))

If you want to override the configuration for a writer then you will need to get a handle to the writer itself using the writer() method which returns an ImageWriter instance. From here you can then configure it before writing. A common example would be optimising a PNG to use compression (uses a modified version of PngTastic behind the scenes). Eg,

val image = ... // some image
image.writer(Format.PNG).withCompression(9).write(new File("/home/sam/compressed_spahgetti.png"))

Note the writers are immutable and are created per image.

Async

In version 1.1.0 support for asynchronous operations was added. This is achieved using the AsyncImage class. First, get an instance of AsyncImage from an Image or other source:

val in = ... // input stream
val a = AsyncImage(in)

Then any operations that act on that image return a Future[Image] instead of a standard Image. They will operate on the scala.concurrent implicit execution context.

... given an async image
val filtered = a.filter(VintageFilter) // filtered has type Future[Image]

A more complicated example would be to load all images instead a directory, apply a grayscale filter, and then re-save them out as optimized PNGs.

val dir = new File("/home/sam/images")
dir.listFiles().foreach(file => AsyncImage(file).filter(GrayscaleFilter).onSuccess {
case image => image.writer(Format.PNG).withMaxCompression.write(file)
})

Benchmarks

Some noddy benchmarks comparing the speed of rescaling an image. I've compared the basic getScaledInstance method in java.awt.Image with ImgScalr and Scrimage. ImgScalr delegates to awt.Graphics2D for its rendering. Scrimage adapts the methods implemented by Morten Nobel.

The code is inside src/test/scala/com/sksamuel/scrimage/ScalingBenchmark.scala.

The results are for 100 runs of a resize to a fixed width / height.

Library Fast High Quality (Method)
java.awt.Image.getScaledInstance 11006ms 17134ms (Area Averaging)
ImgScalr 57ms 5018ms (ImgScalr.Quality)
Scrimage 113ms 2730ms (Bicubic)

As you can see, ImgScalr is the fastest for a simple rescale, but Scrimage is much faster than the rest for a high quality scale.

Including Scrimage in your project

Scrimage is available on maven central. There are two dependencies. One is the core library, and one is the image filters. They are split because the image filters is a large jar, and most people just want the basic resize/scale/load/save functionality. Only include the filters dependency if you need the image filters, otherwise just the core one is needed.

Maven:

<dependency>
    <groupId>com.sksamuel.scrimage</groupId>
    <artifactId>scrimage-core_2.10</artifactId>
    <version>1.3.5</version>
</dependency>
<dependency>
    <groupId>com.sksamuel.scrimage</groupId>
    <artifactId>scrimage-filters_2.10</artifactId>
    <version>1.3.5</version>
</dependency>

If using SBT then you want:

libraryDependencies += "com.sksamuel.scrimage" % "scrimage-core_2.10" % "1.3.5"

libraryDependencies += "com.sksamuel.scrimage" % "scrimage-filters_2.10" % "1.3.5"

Filters

Scrimage comes with a wide array (or Iterable ;) of filters. Most of these filters I have not written myself, but rather collected from other open source imaging libraries (for compliance with licenses and / or attribution - see file headers), and either re-written them in Scala, wrapped them in Scala, fixed bugs or improved them.

Some filters have options which can be set when creating the filters. All filters are immutable. Most filters have sensible default options as default parameters.

Click on the small images to see an enlarged example.

Filter Example 1 Example 2 Example 3
blur
border
brightness
bump
chrome
color_halftone
contour
contrast
despeckle
diffuse
dither
edge
emboss
errordiffusion
gamma
gaussian
glow
grayscale
hsb
invert
lensblur
lensflare
minimum
maximum
motionblur
noise
offset
oil
pixelate
pointillize_square
posterize
prewitt
quantize
rays
ripple
roberts
rylanders
sepia
smear_circles
snow
sobels
solarize
sparkle
summer
swim
television
threshold
tritone
twirl
unsharp
vignette
vintage

License

This software is licensed under the Apache 2 license, quoted below.

Copyright 2013 Stephen Samuel

Licensed under the Apache License, Version 2.0 (the "License"); you may not
use this file except in compliance with the License. You may obtain a copy of
the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations under
the License.

scrimage's People

Contributors

emchristiansen avatar sksamuel avatar

Watchers

 avatar

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.