Webp支持java

时间:2016-12-16 13:44:41

标签: java webp

由于我们基于网络的应用程序爱上了webp图像格式,我发现自己需要一个可以解码它的方法或lib,

我已经编写了这段代码,但它只是错过了原生解码器(我更喜欢它是一个jar lib):

public BufferedImage decodeWebP(byte[] encoded, int w, int h) {
    int[] width = new int[]{w};
    int[] height = new int[]{h};

    byte[] decoded = decodeRGBAnative(encoded);  //here is the missing part , 
    if (decoded.length == 0) return null;

    int[] pixels = new int[decoded.length / 4];
    ByteBuffer.wrap(decoded).asIntBuffer().get(pixels);

    BufferedImage bufferedImage = new BufferedImage(width[0], height[0], BufferedImage.TYPE_INT_RGB);

    //  bufferedImage.setRGB(x, y, your_value);

    int BLOCK_SIZE = 3;

    for(int r=0; r< height[0]; r++) {
        for (int c = 0; c < width[0]; c++) {
            int index = r * width[0] * BLOCK_SIZE + c * BLOCK_SIZE;
            int red = pixels[index] & 0xFF;
            int green = pixels[index + 1] & 0xFF;
            int blue = pixels[index + 2] & 0xFF;
            int rgb = (red << 16) | (green << 8) | blue;
            bufferedImage.setRGB(c, r, rgb);
        }
    }
    return bufferedImage;
}

4 个答案:

答案 0 :(得分:1)

在所有可能的搜索中,这一个是最好和最简单的:

https://bitbucket.org/luciad/webp-imageio

不是完整的java实现,但与其他实现相比非常容易

答案 1 :(得分:1)

原始答案的 bitbucket 链接不再可用,但可以找到来自原始存储库的 fork,例如:https://github.com/sejda-pdf/webp-imageio

我尝试使用上述 github 中的 webp-imageio 实现,但在生产中使用它 2 天后,我遇到了来自本机库的分段错误,导致整个服务器崩溃。

我在这里使用了 google 提供的编译工具:https://developers.google.com/speed/webp/download 并做了一个小的包装类来调用二进制文件。

就我而言,我需要从其他图像格式转换为 webp,所以我需要“cwebp”二进制文件。我写的包装器是:

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.concurrent.TimeUnit;

public class ImageWebpLibraryWrapper {

  private static final String CWEBP_BIN_PATH = "somepath/libwebp-1.1.0-linux-x86-64/bin/cwebp";

  public static boolean isWebPAvailable() {
    if ( CWEBP_BIN_PATH == null ) {
      return false;
    }
    return new File( CWEBP_BIN_PATH ).exists();
  }

  public static boolean convertToWebP( File imageFile, File targetFile, int quality ) {
    Process process;
    try {
      process = new ProcessBuilder( CWEBP_BIN_PATH, "-q", "" + quality, imageFile.getAbsolutePath(), "-o",
          targetFile.getAbsolutePath() ).start();
      process.waitFor( 10, TimeUnit.SECONDS );
      if ( process.exitValue() == 0 ) {
        // Success
        printProcessOutput( process.getInputStream(), System.out );
        return true;
      } else {
        printProcessOutput( process.getErrorStream(), System.err );
        return false;
      }
    } catch ( Exception e ) {
      e.printStackTrace();
      return false;
    }
  }
  
  private static void printProcessOutput( InputStream inputStream, PrintStream output ) throws IOException {
    try ( InputStreamReader isr = new InputStreamReader( inputStream );
        BufferedReader bufferedReader = new BufferedReader( isr ) ) {
      String line;
      while ( ( line = bufferedReader.readLine() ) != null ) {
        output.println( line );
      }
    }
  }

围绕 ImageIO 的实现更好,但我不能让生产服务器崩溃的分段错误。

示例用法:

public static void main( String args[] ) {
  if ( !isWebPAvailable() ) {
    System.err.println( "cwebp binary not found!" );
    return;
  }
  File file = new File( "/home/xxx/Downloads/image_11.jpg" );
  File outputFile = new File( "/home/xxx/Downloads/image_11-test.webp" );
  int quality = 80;
  if ( convertToWebP( file, outputFile, quality ) ) {
    System.out.println( "SUCCESS" );
  } else {
    System.err.println( "FAIL" );
  }
}

答案 2 :(得分:1)

请使用 OpenCV。我使用 maven 和 org.openpnp:opencv:4.5.1-2。对存储在 Mat 中的图像进行编码只需要:

public static byte [] encodeWebp(Mat image, int quality) {
    MatOfInt parameters = new MatOfInt(Imgcodecs.IMWRITE_WEBP_QUALITY, quality);
    MatOfByte output = new MatOfByte();
    if(Imgcodecs.imencode(".webp", image, output, parameters)) 
        return output.toArray();
    else
        throw new IllegalStateException("Failed to encode the image as webp with quality " + quality);
}

我将其转换为字节 [] 数组,因为我主要将它存储在 S3 和 DB 中,而很少存储在文件系统中。

答案 3 :(得分:0)

在 kotlin 中使用 OpenPnP OpenCV:

fun encodeToWebP(image: ByteArray): ByteArray {
        val matImage = Imgcodecs.imdecode(MatOfByte(*image), Imgcodecs.IMREAD_UNCHANGED)
        val parameters = MatOfInt(Imgcodecs.IMWRITE_WEBP_QUALITY, 100)
        val output = MatOfByte()
        if (Imgcodecs.imencode(".webp", matImage, output, parameters)) {
            return output.toArray()
        } else {
            throw IllegalStateException("Failed to encode the image as webp")
        }
    }