2012-02-20 14 views
5

Estoy usando imágenes swt de Java con canales de color y alfa completos de 32 bits (org.eclipse.swt.graphics.Image). Necesito extraer un rectángulo de la imagen como una nueva imagen, incluida la información completa del canal alfa.Copiando porciones de imágenes swt de Java con alpha

Por ejemplo, podría tener una Imagen con un tamaño de 100 × 100, y necesito crear una nueva Imagen con solo los 50 × 50 píxeles de la parte superior exactamente como están en la imagen de 100 × 100. (Estoy cortando, no volviendo a escalar.)

Mi intento original fue crear una imagen en blanco del tamaño que necesito (50 × 50 en este ejemplo), obtener un GC para la nueva imagen y dibujar la imagen correcta porción de la imagen anterior en la nueva imagen. El problema era que la transparencia no se conservaba. Si mi nueva imagen comenzó opaca, el resultado después de un sorteo sería completamente opaco. Si mi nueva imagen comenzaba transparente, el resultado después de un dibujo sería completamente transparente (con todos los colores RGB correctos, pero invisible porque el alfa sería cero para todos los píxeles).

Mi solución actual es torpe: utilizo un GC para dibujar la imagen, luego copio manualmente sobre el canal alfa fila por fila.

/** 
* Returns a sub-rectangle from the image, preserving alpha transparency. 
* @param source The image from which to copy a portion 
* @param sourceData The ImageData of the source image 
* @param xInSource The x-coordinate in the source image from which to start copying 
* @param yInSource The y-coordinate in the source image from which to start copying 
* @param widthInSource The width (in pixels) of the copied image portion 
* @param heightInSource The height (in pixels) of the copied image portion 
* @param disp The display to use for the new image, or null for the current display 
* @return New image copied from a portion of the source. 
*/ 
private static Image getRectHelper(final Image source, final ImageData sourceData, 
     final int xInSource, final int yInSource, final int widthInSource, final int heightInSource, final Display disp) 
{ 
    // In cases like extracting multiple frames at once, we need both the Image and its ImageData without 
    // having to extract the ImageData over and over. That’s why this helper takes both parameters. 

    // New up an image of the appropriate size 
    final Display d = disp==null ? Display.getDefault() : disp; 
    final Image dest = new Image(d, widthInSource, heightInSource); 

    // This draws the colors from the original image, but does not set the destination alphas 
    // (For the Image class, alpha transparency doesn’t work well – it seems to have been tacked on as an afterthought.) 
    final GC g = new GC(dest); 
    g.drawImage(source, xInSource, yInSource, widthInSource, heightInSource, 0, 0, widthInSource, heightInSource); 
    g.dispose(); 

    // Get a copy of the dest image data, then sets the destination alphas from the source image 
    final ImageData destData = dest.getImageData(); 
    copyAlpha(sourceData, destData, xInSource, yInSource, widthInSource, heightInSource, 0, 0); 

    // Construct a new image with the modified image data 
    final Image ret = new Image(d, destData); 
    dest.dispose(); 

    return ret; 
} 

/** 
* Copies a block of alpha channel information from the sourceData to the destaData. 
* 
* @param sourceData The source image data from which to copy alpha information 
* @param destData The destination image data to modify with new alpha information 
* @param xInSource The x-coordinate from which the alpha information should be copied 
* @param yInSource The y-coordinate from which the alpha information should be copied 
* @param width The width (in pixels) of the alpha information to copy 
* @param height The height (in pixels) of the alpha information to copy 
* @param xInDest The x-coordinate to which the alpha information should be copied 
* @param yInDest The y-coordinate to which the alpha information should be copied 
*/ 
private static void copyAlpha(final ImageData sourceData, final ImageData destData, 
     final int xInSource, final int yInSource, final int width, final int height, 
     final int xInDest, final int yInDest) 
{ 
    final byte[] alphas = new byte[width]; 
    for (int ySrc = yInSource, yDst = yInDest; ySrc < yInSource+height; ++ySrc, ++yDst) { 
     sourceData.getAlphas(xInSource, ySrc, width, alphas, 0); 
     destData.setAlphas(xInDest, yDst, width, alphas, 0); 
    } 
} 

¿Qué es lo que falta aquí? Soy nuevo en Java, así que puedo estar haciendo algo mal. ¿Es el canal alfa realmente una idea de último momento para la clase de imagen swt? Seguramente hay una manera más simple y más rápida de hacer esto. Estoy tentado de usar objetos ImageData directamente, y omitir el uso de GC por completo.

Respuesta

0

Así que una cosa que puede estar perdiendo es que hay múltiples tipos de transparencia para una imagen. http://help.eclipse.org/kepler/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/swt/graphics/ImageData.html#getTransparencyType()

En el código de cambio de tamaño que usamos para imágenes SWT, primero creamos una nueva imagen y obtenemos su ImageData. A continuación, en función del tipo de transparencia ImageData de la imagen original, hacemos una de las siguientes cosas:

  • Si SWT.TRANSPARENCY_ALPHA, a continuación, aplicar un alfa como en su ejemplo debe hacer el truco.
  • Si SWT.TRANSPARENCY_PIXEL, establecemos la propiedad transparentPixel de ImageData para que coincida con ImageData de la imagen original.
  • Si SWT.TRANSPARENCY_MASK, establecemos las propiedades maskData y maskPad del nuevo ImageData para que coincida con ImageData de la imagen original.

A continuación, utilizamos ImageData para crear una nueva imagen (disponer de la primera) y dibujar sobre ella utilizando GC.

Afortunadamente, lo anterior puede ayudarlo a acercarse a la solución del problema.