2012-02-20 8 views
5

Utilizzo immagini Java swt con colori a 32 bit e canali alfa completi (org.eclipse.swt.graphics.Image). Ho bisogno di estrarre un rettangolo dell'immagine come una nuova immagine, incluse le informazioni complete del canale alfa.Copia di porzioni di immagini swt Java con alpha

Ad esempio, potrei avere un'immagine 100 × 100, e ho bisogno di creare una nuova immagine con solo 50 × 50 pixel in alto a sinistra esattamente come sono nell'immagine 100 × 100. (Sto tagliando, non riscalando.)

Il mio tentativo originale era quello di creare un'immagine vuota della dimensione di cui ho bisogno (50 × 50 in questo esempio), quindi ottenere un GC per la nuova immagine, quindi disegnare il corretto porzione della vecchia immagine sulla nuova immagine. Il problema era che la trasparenza non veniva preservata. Se la mia nuova immagine iniziata opaca, il risultato dopo un pareggio sarebbe completamente opaco. Se la mia nuova immagine iniziava a essere trasparente, il risultato dopo un'estrazione sarebbe completamente trasparente (con tutti i colori RGB corretti, ma invisibile perché l'alpha sarebbe zero per tutti i pixel).

La mia soluzione attuale è goffo: utilizzo un GC per disegnare l'immagine, quindi copio manualmente il canale alfa riga per riga.

/** 
* 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); 
    } 
} 

Cosa mi manca qui? Sono nuovo di Java, quindi potrei fare qualcosa di sbagliato. Il canale alfa è davvero un ripensamento per la classe Image di swt? Sicuramente c'è un modo più semplice e veloce per farlo. Sono tentato di utilizzare direttamente gli oggetti ImageData e di escludere completamente l'utilizzo di GC.

risposta

0

Quindi una cosa che potrebbe mancare è che ci sono più tipi di trasparenza per un'immagine. http://help.eclipse.org/kepler/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/swt/graphics/ImageData.html#getTransparencyType()

Nel codice di ridimensionamento che usiamo per le immagini SWT, prima creiamo una nuova immagine e otteniamo i suoi ImageData. Poi in base al tipo di trasparenza di ImageData dell'immagine originale, facciamo una delle seguenti cose:

  • Se SWT.TRANSPARENCY_ALPHA, quindi applicando un alfa, come nel tuo esempio dovrebbe fare il trucco.
  • Se SWT.TRANSPARENCY_PIXEL, quindi impostiamo la proprietà transparentPixel di ImageData in modo che corrisponda al ImageData dell'immagine originale.
  • Se SWT.TRANSPARENCY_MASK, quindi impostiamo le proprietà maskData e maskPad del nuovo ImageData in modo che corrispondano al ImageData dell'immagine originale.

Quindi utilizziamo ImageData per creare una nuova immagine (smaltire la prima) e disegnarla utilizzando GC.

Speriamo che quanto sopra possa aiutarti ad avvicinarti a risolvere il problema.