Sample code for imgscalr AsyncScalr

Can anyone post the imgscalr example code using AsyncScalr to resize the code? I am trying to use imgscalr (Scalr class) for image processing. It's a nice and easy-to-use library, but throws OutOfMemoryException too often. I hope that using AsyncScalr will solve my problem at low loads.

+3


source to share


2 answers


If you are familiar with Java Concurrent libs, using the AsyncScalr class is really straight forward; if you are not familiar with new parallel libraries, then the gist is:

  • Call an API method that works to some degree in an unknown location; the method call returns a Future , which completes the actual work.
  • The original API call actually queues up the work internally; if it is not busy, it will most likely do the job right away, but if it is busy and the queue is huge, it may take some time to complete the job (in this case, the "job" is the image scaling).
  • The calling code (your code) that wants the result can continue to do the work until Future.isDone () returns true to indicate the work has finished OR the calling code can simply block until the operation is completed by calling: Future .get () - This method returns the result of the work, in this case, a BufferedImage, which represents the scaled result.

The code literally ends like this:

// Block until result is done
BufferedImage result = AsyncScalr.resize(origImage, 125).get();

      

The difference between this code and using the Scalr class is that on multithreaded systems, if you call Scalr.resize () (or any of the image operations) from ALL of your threads, each of those threads will start a costly image operation, guiding your the processor is running in parallel and slowing down the system to bypass (clogging up other processes running on it, like a DB or a web server).

By using the AsyncScalr class , you can safely call AsyncScalr.resize (or any other operation) from any number of threads and never worry about flooding the host system with work; AsyncScalr.THREAD_COUNT determines how many concurrent jobs can happen at one time; you usually want to set this to the number of cores on the host machine, or less than the number of cores if the host machine also hosts other essential services like a database or web server (so you don't stub other processes when scaling gets busy) ...



You can set this thread value on the command line at startup time for your application with the "imgscalr.async.threadCount" system property; the default is "2", but you can set it to "1" if you are worried about too low memory.

Alternatively, if you have a job that your thread can do while you wait for the result, you can do something like this to actually use asynchronous programming:

// Queue up the scaling operation (or any other op)
Future<BufferedImage> result = AsyncScalr.resize(origImage, 125);

/*
 * You can do other work here that doesn't need 'result', like making
 * DB calls, cleaning up temp files or anything else you might need to
 * do.
 */

// Now we are all done and need the resulting image, so we wait for it.
BufferedImage scaledImage = result.get();

// Do something with the image...

      

If you had a significant amount of other work that you could do while waiting for the image to be scaled, you can simply loop on result.isDone()

and continue working until the scale operation is complete; but if you only have a discrete / specific amount of work, you don't have to loop on isDone, just do the work, then call Future.get()

to get the result (or block until it's ready).

Hope it helps!

+3


source


This uses a utility method that resizes the image. The best part is that it returns ListenableFuture

, allowing you to attach a callback to be executed after the image is resized.

/**
 * Schedules the asynchronous resizing of an image.
 * <p>
 * Uses all available processors to do so.
 * 
 * @param pathToImage
 *            the path to the image we want to resize
 * @param quality
 *            the quality we want the output image to have. One of {@link Method}.
 * @param desiredSize
 *            the resulting image will not have a bigger height or width than this
 * @return
 *         a {@link ListenableFuture} of the resulting image. You can add a callback to it using {@link Futures#addCallback(ListenableFuture, FutureCallback)}
 * @throws IOException
 *             if the image at {@code pathToImage} couldn't be read
 */
public static ListenableFuture<BufferedImage> resize(String pathToImage, Method quality, int desiredSize) throws IOException {

    // Configure AsyncScalr to use all available processors for resizing the images
    String nrOfProcessors = String.valueOf(Runtime.getRuntime().availableProcessors());
    System.setProperty(AsyncScalr.THREAD_COUNT_PROPERTY_NAME, nrOfProcessors);

    BufferedImage image = ImageIO.read(new File(pathToImage));
    Future<BufferedImage> ordinaryFuture = AsyncScalr.resize(image, quality, desiredSize);
    ListenableFuture<BufferedImage> futureImage = JdkFutureAdapters.listenInPoolThread(ordinaryFuture);
    image.flush();
    return futureImage;
}

      

And this is how you use resize

:



ListenableFuture<BufferedImage> futureImage = resize("/path/to/img.png", Method.SPEED, 250);

Futures.addCallback(futureImage, new FutureCallback<BufferedImage>() {
  @Override
  public void onSuccess(BufferedImage result) {
          System.out.println("Your resized image is ready :-)");
  }
  @Override
  public void onFailure(Throwable t) {
          System.out.println("Couldn't resize image :-(");
  }
});

      

ListenableFuture

and FutureCallback

both are defined in the Guava library .

0


source







All Articles