imgscalr AsyncScalr的示例代码

时间:2012-03-17 19:26:24

标签: java image image-processing imgscalr

有人可以使用AsyncScalr分享imgscalr的示例代码以调整代码大小吗?我正在尝试使用imgscalr(Scalr类)进行图像处理。它是一个好的和易于使用的库,但是,经常给出OutOfMemoryException。我希望使用AsyncScalr可以解决我的低负载问题。

2 个答案:

答案 0 :(得分:3)

如果您熟悉Java Concurrent库,那么使用AsyncScalr类非常简单;如果您不熟悉新的并发库,那么要点是:

  1. 调用一种API方法,该方法在将来的某个未知点上工作;方法调用返回一个包含实际工作的Future
  2. 原始API调用实际上是在内部排队工作;如果它不忙,它可能会立即完成工作,但如果它很忙并且队列很大,那么工作可能需要一段时间才能完成(在这种情况下,“工作”是缩放的图像)。
  3. 需要结果的调用代码(您的代码)可以继续工作,直到Future.isDone()返回true表示工作已完成或者调用代码可以阻塞,直到操作完成后调用:{{ 3}} - 此方法返回工作的结果,在本例中是一个表示缩放结果的BufferedImage。
  4. 代码字面上看起来像这样:

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

    此代码与直接使用Future.get()之间的区别在于,在多线程系统中,如果从所有线程调用Scalr.resize()(或任何图像操作),则每一个这些线程将开始一个昂贵的映像操作,使你的CPU充满并发工作,并使系统速度变慢(阻塞其上运行的其他进程,如DB或Web服务器)。

    使用Scalr class,您可以安全地从任意数量的线程调用AsyncScalr.resize(或任何其他操作),而不用担心主机系统充满工作; AsyncScalr class确定一次可以同时发生的作业数量;您通常希望将其设置为主机上的核心数,或者如果主机还托管其他重要服务(如数据库或Web服务器),则将其设置为核心数(以确保不会阻塞其他服务)缩放变得繁忙时的处理。)

    您可以在启动时使用“imgscalr.async.threadCount”系统属性在应用程序的命令行上设置此线程值;默认情况下它是“2”,但如果您担心系统内存太低,可以将其设置为“1”。

    或者如果你在等待结果时你的线程可以做的工作,你可以做这样的事情来真正好好利用异步编程:

    // 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...
    

    如果您在等待缩放图像时可以进行大量其他工作,则只需循环result.isDone()并继续工作直到缩放操作完成;但是如果你只有一个离散/特定的工作量,不需要在isDone上循环,只需要做工作然后调用Future.get()来获得结果(或阻塞直到准备就绪)。

    希望有所帮助!

答案 1 :(得分:0)

这是一种调度图像大小调整的实用方法。关于这一点的好处是它返回一个ListenableFuture,允许你附加一个在调整图像大小后执行的回调。

/**
 * 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;
}

这就是你使用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 :-(");
  }
});

ListenableFutureFutureCallback都在Guava library中定义。