2011-01-20 12 views
6

Ứng dụng của tôi cần thay đổi kích thước ImageData. Thật không may, tôi đã không nhận được kết quả tôi muốn với GC (với antialias trên và nội suy trên cao), hoặc ImageData.scaledTo(). Hình ảnh kết quả có chất lượng quá thấp để có thể chấp nhận được. Cách tốt nhất để thực hiện thay đổi kích thước ImageData chất lượng cao là gì?SWT: Cách thực hiện Thay đổi kích thước hình ảnh chất lượng cao

Chỉnh sửa:Tôi đang giảm tỷ lệ.

+2

Bạn đang mở rộng quy mô lên hoặc xuống? – horatio

+0

Ah có, quên chỉ định. Xuống. – Jonah

Trả lời

9

AWT cung cấp chia tỷ lệ hình ảnh với các chế độ khác nhau. Để giảm kích thước, Diện tích trung bình mang lại chất lượng tốt nhất. Người ta có thể tất nhiên tái triển khai các khu vực trung bình rộng thuật toán cho SWT, hoặc, đối với một giải pháp nhanh chóng mà thường cũng đủ:

  • convert các SWT ảnh để một AWT ảnh
  • rescale nó bằng cách sử dụng chế độ thích hợp (khu vực tính trung bình nếu downscaling, bilinerar nếu không)
  • chuyển đổi lại thành hình ảnh SWT

Mã để chuyển đổi giữa hình ảnh SWT và AWT có thể được tìm thấy here.

/** 
* Resizes an image, using the given scaling factor. Constructs a new image resource, please take care of resource 
* disposal if you no longer need the original one. This method is optimized for quality, not for speed. 
* 
* @param image source image 
* @param scale scale factor (<1 = downscaling, >1 = upscaling) 
* @return scaled image 
*/ 
public static org.eclipse.swt.graphics.Image resize (org.eclipse.swt.graphics.Image image, float scale) { 
    int w = image.getBounds().width; 
    int h = image.getBounds().height; 

    // convert to buffered image 
    BufferedImage img = convertToAWT(image.getImageData()); 

    // resize buffered image 
    int newWidth = Math.round(scale * w); 
    int newHeight = Math.round(scale * h); 

    // determine scaling mode for best result: if downsizing, use area averaging, if upsizing, use smooth scaling 
    // (usually bilinear). 
    int mode = scale < 1 ? BufferedImage.SCALE_AREA_AVERAGING : BufferedImage.SCALE_SMOOTH; 
    java.awt.Image scaledImage = img.getScaledInstance(newWidth, newHeight, mode); 

    // convert the scaled image back to a buffered image 
    img = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB); 
    img.getGraphics().drawImage(scaledImage, 0, 0, null); 

    // reconstruct swt image 
    ImageData imageData = convertToSWT(img); 
    return new org.eclipse.swt.graphics.Image(Display.getDefault(), imageData); 
} 

public static BufferedImage convertToAWT (ImageData data) { 
    ColorModel colorModel = null; 
    PaletteData palette = data.palette; 
    if (palette.isDirect) { 
     colorModel = new DirectColorModel(data.depth, palette.redMask, palette.greenMask, palette.blueMask); 
     BufferedImage bufferedImage = new BufferedImage(colorModel, colorModel.createCompatibleWritableRaster(data.width, data.height), 
      false, null); 
     WritableRaster raster = bufferedImage.getRaster(); 
     int[] pixelArray = new int[3]; 
     for (int y = 0; y < data.height; y++) { 
      for (int x = 0; x < data.width; x++) { 
       int pixel = data.getPixel(x, y); 
       RGB rgb = palette.getRGB(pixel); 
       pixelArray[0] = rgb.red; 
       pixelArray[1] = rgb.green; 
       pixelArray[2] = rgb.blue; 
       raster.setPixels(x, y, 1, 1, pixelArray); 
      } 
     } 
     return bufferedImage; 
    } else { 
     RGB[] rgbs = palette.getRGBs(); 
     byte[] red = new byte[rgbs.length]; 
     byte[] green = new byte[rgbs.length]; 
     byte[] blue = new byte[rgbs.length]; 
     for (int i = 0; i < rgbs.length; i++) { 
      RGB rgb = rgbs[i]; 
      red[i] = (byte) rgb.red; 
      green[i] = (byte) rgb.green; 
      blue[i] = (byte) rgb.blue; 
     } 
     if (data.transparentPixel != -1) { 
      colorModel = new IndexColorModel(data.depth, rgbs.length, red, green, blue, data.transparentPixel); 
     } else { 
      colorModel = new IndexColorModel(data.depth, rgbs.length, red, green, blue); 
     } 
     BufferedImage bufferedImage = new BufferedImage(colorModel, colorModel.createCompatibleWritableRaster(data.width, data.height), 
      false, null); 
     WritableRaster raster = bufferedImage.getRaster(); 
     int[] pixelArray = new int[1]; 
     for (int y = 0; y < data.height; y++) { 
      for (int x = 0; x < data.width; x++) { 
       int pixel = data.getPixel(x, y); 
       pixelArray[0] = pixel; 
       raster.setPixel(x, y, pixelArray); 
      } 
     } 
     return bufferedImage; 
    } 
} 

public static ImageData convertToSWT (BufferedImage bufferedImage) { 
    if (bufferedImage.getColorModel() instanceof DirectColorModel) { 
     DirectColorModel colorModel = (DirectColorModel) bufferedImage.getColorModel(); 
     PaletteData palette = new PaletteData(colorModel.getRedMask(), colorModel.getGreenMask(), colorModel.getBlueMask()); 
     ImageData data = new ImageData(bufferedImage.getWidth(), bufferedImage.getHeight(), colorModel.getPixelSize(), palette); 
     WritableRaster raster = bufferedImage.getRaster(); 
     int[] pixelArray = new int[3]; 
     for (int y = 0; y < data.height; y++) { 
      for (int x = 0; x < data.width; x++) { 
       raster.getPixel(x, y, pixelArray); 
       int pixel = palette.getPixel(new RGB(pixelArray[0], pixelArray[1], pixelArray[2])); 
       data.setPixel(x, y, pixel); 
      } 
     } 
     return data; 
    } else if (bufferedImage.getColorModel() instanceof IndexColorModel) { 
     IndexColorModel colorModel = (IndexColorModel) bufferedImage.getColorModel(); 
     int size = colorModel.getMapSize(); 
     byte[] reds = new byte[size]; 
     byte[] greens = new byte[size]; 
     byte[] blues = new byte[size]; 
     colorModel.getReds(reds); 
     colorModel.getGreens(greens); 
     colorModel.getBlues(blues); 
     RGB[] rgbs = new RGB[size]; 
     for (int i = 0; i < rgbs.length; i++) { 
      rgbs[i] = new RGB(reds[i] & 0xFF, greens[i] & 0xFF, blues[i] & 0xFF); 
     } 
     PaletteData palette = new PaletteData(rgbs); 
     ImageData data = new ImageData(bufferedImage.getWidth(), bufferedImage.getHeight(), colorModel.getPixelSize(), palette); 
     data.transparentPixel = colorModel.getTransparentPixel(); 
     WritableRaster raster = bufferedImage.getRaster(); 
     int[] pixelArray = new int[1]; 
     for (int y = 0; y < data.height; y++) { 
      for (int x = 0; x < data.width; x++) { 
       raster.getPixel(x, y, pixelArray); 
       data.setPixel(x, y, pixelArray[0]); 
      } 
     } 
     return data; 
    } 
    return null; 
} 
+0

Đó là những gì tôi đã làm cuối cùng. – Jonah

+2

Điều này dường như chuyển sang màu đen trong suốt. Điều đó có thể được thay đổi sao cho độ trong suốt trở nên trắng, hay tốt hơn, được giữ lại? –

1

Chúng tôi đã thành công với ImageMagick/JMagick. http://www.jmagick.org/index.html

Vấn đề duy nhất là nếu hình ảnh là tải lên của người dùng và bạn có cơ sở người dùng lớn, bạn sẽ bị rò rỉ bộ nhớ do tệp hình ảnh không hợp lệ, v.v.

+0

Thực ra, đây là ứng dụng dành cho máy tính để bàn nên không có vấn đề gì. Vậy có nghĩa là tôi sẽ phải phân phối ImageMagick bằng ứng dụng của tôi? – Jonah

+0

Có. Bạn cũng sẽ phải phân phối imageMagick. Tôi không chắc nó sẽ như thế nào nếu người dùng của bạn sử dụng nhiều nền tảng. Tùy chọn khác là tạo một webservice và ứng dụng máy tính để bàn sử dụng dịch vụ từ xa. Tôi đặt cược bạn có thể tìm thấy một dịch vụ thực hiện điều này và bỏ qua vấn đề hoàn toàn. – Zeki

+0

Nhiều nền tảng sẽ không sao, nó chỉ là Windows, Linux và Apple. Tôi sẽ chỉ đảm bảo rằng tôi có được bản dựng đúng cho nền tảng phù hợp, chỉ 32 bit. Tôi không nghĩ rằng bằng cách sử dụng một webservice sẽ là một giải pháp khả thi trong trường hợp này: nó thay đổi kích thước một hàng đợi rất lớn. – Jonah

4

Giải pháp được chấp nhận không giải quyết được sự minh bạch. Dưới đây là một đoạn tôi đã đi qua mà không hi-chất lượng thay đổi kích thước và bảo tính minh bạch cũng như:

public static Image resize(Image image, int width, int height) { 
    Image scaled = new Image(Display.getDefault(), width, height); 
    GC gc = new GC(scaled); 
    gc.setAntialias(SWT.ON); 
    gc.setInterpolation(SWT.HIGH); 
    gc.drawImage(image, 0, 0,image.getBounds().width, image.getBounds().height, 0, 0, width, height); 
    gc.dispose(); 
    image.dispose(); // don't forget about me! 
    return scaled; 
} 

tôi đã tìm thấy nó ở đây:

http://aniszczyk.org/2007/08/09/resizing-images-using-swt/