这样的代码执行读取图片的时间有点长


// 将图像转成字节流
 ByteArrayOutputStream baos = new ByteArrayOutputStream();
 // 将图像转为jpeg而是的流数据
 ImageIO.write(bufferedImage,"jpeg", baos);
 byte[] image_bytes = baos.toByteArray();

运行结果:
image

这样的代码生成一张像素256x256的jpg图像需要消耗时间150毫秒左右,我认为时间还是太慢了,因为我需要大量且频繁的生成这样的图像。这样的代码是否能优化,或者采用什么组件?

 /**
     * Tile图像生成接口
      * @param slideName   切片名
      * @param level       获取指定WSI level图像
      * @param row         获取WSI图像X轴坐标
      * @param column      获取WSI图像Y轴坐标
      * @return
      * @throws IOException
      */
     @GetMapping(value = "/getTile/{slideName}/{level}/{row}_{column}.jpg", produces = MediaType.IMAGE_JPEG_VALUE)
     @Async("wsiImage")
     public CompletableFuture<byte[]> getTile(@PathVariable String slideName, @PathVariable Integer level,
                                              @PathVariable Integer row, @PathVariable Integer column) throws IOException {
         // 函数执行时间
         long begin_time = System.currentTimeMillis();
         // 加载WSI图像
         String wsiPath = WSIRootPath.getFileRootPath() + slideName;
         File wsi_file = new File(wsiPath);
         // 调用OpenSlide组件,操作WSI图像
         OpenSlide openSlide = new OpenSlide(wsi_file);
         // 画图
         openSlide.paintRegionOfLevel(graphics, 0, 0, row*256, column*256, TILE_WIDTH, TILE_HEIGHT, level);
         openSlide.dispose();
         // 将图像转成字节流
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         ImageIO.write(bufferedImage,"jpeg", baos);
         byte[] image_bytes = baos.toByteArray();
         // 释放内存
         openSlide.close();
         // 函数结束时间
        long end_time = System.currentTimeMillis();
         log.info("客户端已经请求第"+ (++times) +"次,消耗时间为:" + (end_time-begin_time) + "ms, Tile = "+ level +"_"+row+"_"+column);
         // 返回图像
         return CompletableFuture.completedFuture(image_bytes);
    }

这是完整源码,其中OpenSlide为第三方组件,用于读取金字塔图像的工具,时间上是否有可以优化的空间,这里我已经开启多线程。

这里直接就可以往response.getOutPutStream 写入数据了。而不用先写入内存,在copy一次。

该怎么写,大佬!

我纯手打的,你试试看。

	
	/**
     * Tile图像生成接口
      * @param slideName   切片名
      * @param level       获取指定WSI level图像
      * @param row         获取WSI图像X轴坐标
      * @param column      获取WSI图像Y轴坐标
      * @return
      * @throws IOException
      */
     @GetMapping(value = "/getTile/{slideName}/{level}/{row}_{column}.jpg", produces = MediaType.IMAGE_JPEG_VALUE)
     public void getTile(@PathVariable String slideName, @PathVariable Integer level,
                                              @PathVariable Integer row, @PathVariable Integer column,
                                              	HttpServletResponse response) throws IOException {
         // 函数执行时间
         long begin_time = System.currentTimeMillis();
         // 加载WSI图像
         String wsiPath = WSIRootPath.getFileRootPath() + slideName;
         File wsi_file = new File(wsiPath);
         // 调用OpenSlide组件,操作WSI图像
         OpenSlide openSlide = new OpenSlide(wsi_file);
         // 画图
         openSlide.paintRegionOfLevel(graphics, 0, 0, row*256, column*256, TILE_WIDTH, TILE_HEIGHT, level);
         openSlide.dispose();
         // 将图像转成字节流
//         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         
         // 把图片IO到客户端
         response.setContentType(MediaType.IMAGE_JPEG_VALUE);
         ImageIO.write(bufferedImage,"jpeg", response.getOutputStream());
//         byte[] image_bytes = baos.toByteArray();
//         // 释放内存
//         openSlide.close();
//         // 函数结束时间
//        long end_time = System.currentTimeMillis();
//         log.info("客户端已经请求第"+ (++times) +"次,消耗时间为:" + (end_time-begin_time) + "ms, Tile = "+ level +"_"+row+"_"+column);
//         // 返回图像
    }

核心就是:

  1. 不要用异步,这个没多大效果。
  2. ImageIO 可以直接把图片数据响应到客户端,避免多余的复制。

如果还是慢,那么你要看DEBUG日志,看调用栈,看看到底是慢在了哪里。

好的,谢谢 :smiley: