문제

사진을 Facebook에 업로드하는 오픈 소스 앱이 있습니다. 대역폭을 저장하기 위해 사진은 업로드하기 전에 자동으로 크기가 조정됩니다 (Facebook은 최대 크기 제한을 부과합니다). 몇몇 사람들은 사진 품질에 대해 불평했으며 실제로 차이점을 볼 수 있습니다 ( 이 문제 일부 데모 이미지의 경우).

제 질문은 품질을 잃지 않고 적어도 품질 손실 / 아티팩트가없는 자바에서 이미지 (예 : 사진)를 조정하는 "가장 좋은"방법은 무엇입니까?

내가 가진 현재 코드를 볼 수 있습니다 여기 (코드를 통해 크기를 조정하십시오 이 페이지).

도움이 되었습니까?

해결책

나는 트릭을 포함하여 모든 것을 시도했습니다 여기, 그리고 나는 당신이 인터페이스와 함께 Imagemagick을 사용하는 것이 더 낫다고 말할 수 있습니다. Javas 이미징 라이브러리는 이것에 관해서는 스너프에 달려 있지 않습니다. 올바르게 얻으려면 많은 형식과 알고리즘을 지원해야합니다.

다른 팁

Phil, 나는 당신이 결국 어떤 솔루션을 사용했는지는 모르겠지만, Java의 이미지를 스케일링하면 다음과 같이 보일 수 있습니다.

  • JDK에서 잘 지원되지 않는 완충학 유형을 피하십시오.
  • 증분 스케일링을 사용하십시오
  • 증분 스케일링을 사용할 때 Bicubic을 고수하십시오

나는 이러한 방법으로 테스트를 공평하게 공유했으며 잘 지원되는 이미지 유형을 고수하는 것과 함께 증분 스케일링이 핵심입니다. Alexander는 여전히 운이 좋지 않은 행운을 얻지 못했다고 언급했습니다.

나는 릴리스했다 IMGSCALR 라이브러리 (Apache 2) 약 6 개월 전에 "이 이미지의 잘 생긴 스케일링 사본을 원합니다. 지금하십시오!" 이와 같은 10 가지 질문을 읽은 후.

표준 사용법은 다음과 같습니다.

BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, 640);

두 번째 인수는 경계 너비와 높이 IMGSCALR이 이미지를 확장하는 데 사용할 것입니다. 유효하지 않은 치수로 전달하더라도 비율을 올바르게 유지합니다. 보다 자세한 방법, 그러나 그것은 가장 간단한 사용법입니다.

예를 들어 Facebook이 이미지를 800x600 픽셀로 제한하는 경우에 사용하는 유스 케이스는 다음과 같습니다.

BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, Method.QUALITY, 800, 600);

이는 이미지가 최상의 지원되는 이미지 유형에 머무르고 Java가 소집 할 수있는 최고 품질의 방법으로 확장 할 수 있도록합니다.

내 고해상도 테스트에서 나는 이미지가 이미지 로더에 의해 이미지가 제대로 지원되지 않은 이미지 유형에 넣는 경우를 제외 하고이 라이브러리/이러한 방법을 사용하여 스케일링 이미지를 사용하여 틈새 불일치를 보지 못했습니다. . 당신이 그들을 그렇게 떠나고 잘 지원되지 않는 유형에서 벗어나지 않으면, 그것은 정말로 디더링되고 끔찍하게 보입니다.

그 이유는 Java2D 팀이 실제로 JDK가 처리 할 수있는 모든 유형의 버퍼링이지에 대해 다른 하드웨어 가속 파이프 라인을 가지고 있기 때문입니다. java2d의 덮개로 인해 가난하고 때로는 완전히 잘못된 이미지가 생깁니다. 이것은 내가 그 논리를 도서관에 직접 썼다는 것을 설명하고 알아내는 PIA였습니다.

가장 잘 지원되는 두 가지 유형은 BufferedImage.type_int_rgb 및 _argb입니다. 궁금합니다.

Java의 이미지 크기 조정을 전문으로하는 가장 인기있는 두 개의 오픈 소스 Libs는 다음과 같습니다.

덧셈은 Java와 함께 JDK 방식이 있습니다 Graphics2D (이 질문을 수행하는 방법에 대한이 질문을 참조하십시오) 창조하기가 악명이 높습니다 특히 다운 스케일링에서 나쁜 결과. 또 한있다 Imagemagick에 대한 Java 인터페이스 외부 도구가 필요하기 때문에 여기에서 생략됩니다.

시각적 품질

다음은 크기 조정/다운 스케일링 결과의 비교입니다. 580x852 png to 145x213. 참조 Photoshop CS5 "Web for Web"크기 조정이 사용됩니다. 참고 : 결과는 1 : 1입니다. 줌은 필터링을 사용하지 않고 간단한 가장 가까운 이웃 알고리즘 만 사용합니다. 여기에서 원본 이미지를 찾을 수 있습니다.

comparison

  1. 기본 설정이 포함 된 Thumbnailator 0.4.8, 차원 조정이 없습니다
  2. Bicubic 알고리즘이있는 Photoshop CS5
  3. Ultra_quality 설정이있는 IMGSCALR 4.2, 차원 조정 없음
  4. 렌더 hints value_interpolation_bicubic, value_render_quality, value_antialias_on과 함께 Graphics2d (Java 8)

주관적이므로 최상의 결과를 선택하기 위해 독자에게 맡깁니다. 일반적으로, 모두는 제외하고는 좋은 출력을 가지고 있습니다 Graphics2D. Thumbnailator는 Photoshop 출력과 매우 유사한 선명한 이미지를 생성하는 반면 IMGSCALR의 출력은 상당히 부드럽습니다. 아이콘/텍스트 등의 경우 더 선명한 출력을 원합니다. 사진의 경우 더 부드러운 출력을 원할 수 있습니다.

계산 시간

다음은 이것을 사용하는 비 과학적 벤치 마크입니다 도구 그리고 약 114 개의 이미지가있는 이미지 96x96 까지 2560x1440 425% 이미지로 취급 : 100%, 150%, 200%, 300% 및 400% 스케일링 버전 (SO 114 * 5 스케일링 작업). 모든 LIB는 품질 비교에서와 동일한 설정을 사용합니다 (가능한 최고 품질). 시간은 전체 프로세스가 아닌 스케일링입니다. 8GB RAM과 5 런으로 I5-2520M에서 수행됩니다.

  • 썸네일 레이터: 7003.0ms | 6581.3ms | 6019.1ms | 6375.3ms | 8700.3ms
  • IMGSCALR: 25218.5ms | 25786.6ms | 25095.7ms | 25790.4ms | 29296.3ms
  • 그래픽 2D: 7387.6ms | 7177.0ms | 7048.2ms | 7132.3ms | 7510.3ms

다음은이 벤치 마크에 사용 된 코드입니다.

재미있게 Thumbnailator는 평균 6.9 초로 가장 빠릅니다. 그 뒤에 7.2 초의 Java2d 퇴거 가난한 26.2 초의 Imgscalr. IMGSCALR이 ULTRA_QUALITY 매우 비싼 것 같습니다. 이랑 QUALITY 더 경쟁력있는 11.1 초에서 평균 설정.

사용자 정의 품질로 이미지를 크기를 조정하려면 Thumbnailator.jar.

예제 코드 http://code.google.com/p/thumbnailator/wiki/examples

어떤 렌더링 힌트를 사용하고 있습니까? 일반적으로 이분치 리 샘플링이 최고입니다. 사진에서 당신이 그것들과 연결하고있는 사진에서 매우 엉망이므로 가장 가까운 이웃을 힌트로 사용하고 있다고 생각합니다.

에서 Picturescaler 당신이 링크하는 클래스에서 paintComponent 메소드는 이미지 크기 조정의 6 가지 다른 수단을 사용합니다. 최상의 결과를 제공하는 6 가지를 모두 시도해 보셨습니까?

몇 번의 실망스러운 실험 후에 나는 다음을 발견했다 평가 크기를 조정하십시오, 내 프로젝트에서 멀티 패스 접근법을 사용했습니다.

이를 위해 getScaledInstance () 메소드를 내 썸네일 생성기 클래스에 복사하고 이미지 읽기 접근 방식을 변경하여 imageio (BufferedImage를 반환합니다) 아주 기쁜!

결과를 Photoshop CS3에서 수행 한 크기와 비교했으며 결과는 매우 동일합니다.

나는 종횡비가 보존 된 최고 품질의 크기를 원했습니다. 몇 가지를 시도하고 몇 가지 항목을 읽었습니다. 이틀을 잃었고 결국 나는 일반 Java 방법으로 최고의 결과를 얻었습니다 (Imagemagick 및 Java-Image-Scaling Libraries 시도) :

public static boolean resizeUsingJavaAlgo(String source, File dest, int width, int height) throws IOException {
  BufferedImage sourceImage = ImageIO.read(new FileInputStream(source));
  double ratio = (double) sourceImage.getWidth()/sourceImage.getHeight();
  if (width < 1) {
    width = (int) (height * ratio + 0.4);
  } else if (height < 1) {
    height = (int) (width /ratio + 0.4);
  }

  Image scaled = sourceImage.getScaledInstance(width, height, Image.SCALE_AREA_AVERAGING);
  BufferedImage bufferedScaled = new BufferedImage(scaled.getWidth(null), scaled.getHeight(null), BufferedImage.TYPE_INT_RGB);
  Graphics2D g2d = bufferedScaled.createGraphics();
  g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
  g2d.drawImage(scaled, 0, 0, width, height, null);
  dest.createNewFile();
  writeJpeg(bufferedScaled, dest.getCanonicalPath(), 1.0f);
  return true;
}


/**
* Write a JPEG file setting the compression quality.
*
* @param image a BufferedImage to be saved
* @param destFile destination file (absolute or relative path)
* @param quality a float between 0 and 1, where 1 means uncompressed.
* @throws IOException in case of problems writing the file
*/
private static void writeJpeg(BufferedImage image, String destFile, float quality)
      throws IOException {
  ImageWriter writer = null;
  FileImageOutputStream output = null;
  try {
    writer = ImageIO.getImageWritersByFormatName("jpeg").next();
    ImageWriteParam param = writer.getDefaultWriteParam();
    param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
    param.setCompressionQuality(quality);
    output = new FileImageOutputStream(new File(destFile));
    writer.setOutput(output);
    IIOImage iioImage = new IIOImage(image, null, null);
    writer.write(null, iioImage, param);
  } catch (IOException ex) {
    throw ex;
  } finally {
    if (writer != null) {
      writer.dispose();
    }
    if (output != null) {
      output.close();
    }
  }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top