2010-03-09 22 views
1

Y a-t-il une possibilité dans J2ME de convertir une image (chargée à partir d'un fichier png avec alpha) en une nouvelle image en niveaux de gris transparent?J2ME: Convertir une image PNG transparente en niveaux de gris

Jusqu'à présent, je n'avais que les valeurs rgb, mais pas l'alpha.

Merci.

Éditer: oui, il devrait être en niveaux de gris 32 bits.

+0

Les images en niveaux de gris ne sont-elles pas supposées n'utiliser que 8 bits par pixel sans espace pour la transparence? essayez-vous de transformer votre image en niveaux de gris 32 bits? vous pourriez vouloir afficher le code de conversion de couleur. –

+0

Peut-être qu'il est possible d'extraire la couche alpha et de la réappliquer après la conversion en niveaux de gris? Cela semble plus pratique que la conversion pixel par pixel. – Nyerguds

Répondre

4

je trouve la solution et voici le code:

public Image getGrayScaleImage() { 
    int[] rgbData = new int[getWidth() * getHeight()]; 
    image.getRGB(rgbData, 0, getWidth(), 0, 0, getWidth(), getHeight()); 
    for (int x = 0; x < getWidth() * getHeight(); x++) { 
     rgbData[x] = getGrayScale(rgbData[x]); 
    } 
    Image grayImage = Image.createRGBImage(rgbData, getWidth(), getHeight(), true); 
    return grayImage; 
} 

private int getGrayScale(int c) { 
    int[] p = new int[4]; 
    p[0] = (int) ((c & 0xFF000000) >>> 24); // Opacity level 
    p[1] = (int) ((c & 0x00FF0000) >>> 16); // Red level 
    p[2] = (int) ((c & 0x0000FF00) >>> 8); // Green level 
    p[3] = (int) (c & 0x000000FF); // Blue level 

    int nc = p[1]/3 + p[2]/3 + p[3]/3; 
    // a little bit brighter 
    nc = nc/2 + 127; 

    p[1] = nc; 
    p[2] = nc; 
    p[3] = nc; 

    int gc = (p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]); 
    return gc; 
} 

getRGB renvoie la valeur de couleur, qui comprend également le canal alpha. Donc je n'ai eu qu'à changer chaque valeur dans le tableau et créer une image à partir de cela.

J'ai trouvé un document utile dans le forum nokia: MIDP 2.0: Working with Pixels and drawRGB()

0

Merci pour le code sur la conversion en niveaux de gris. Cependant, j'ai remarqué que, sur les appareils Nokia Series 40, ce code fonctionne assez lentement.

Il existe 2 optimisations. Le principal est de supprimer toute création d'objet dans getGrayScale(). Actuellement, un objet tableau est créé pour chaque pixel. Pour une moyenne, disons QVGA, afficher 76800 objets de tableau créés, ce qui est beaucoup d'ordures, et invoquera probablement GC. Définir int [4] comme un champ dans la classe supprime cette création d'objet. Le compromis ici est une petite quantité de RAM supplémentaire utilisée pour la classe.

La seconde consiste à mettre en cache la largeur et la hauteur dans getGrayScaleImage(). Sur certains périphériques, les appels de méthode à getWidth() et getHeight() seront appelés de façon répétée sans optimisations (un compilateur JIT sera OK mais certains périphériques interprétés ne le seront pas). Donc, encore une fois pour QVGA, getWidth() et getHeight() seront appelés entre eux> 150000 entre eux.

En tout, je trouve cette version modifiée a couru beaucoup plus rapide :-)

public Image getGrayScaleImage(Image screenshot) { 
    int width = getWidth(); 
    int height = getHeight(); 
    int screenSizeInPixels = (width * height); 

    int[] rgbData = new int[width * height]; 

    image.getRGB(rgbData, 0, width, 0, 0, width, height); 
    for (int x = 0; x < screenSizeInPixels ; x++) { 
     rgbData[x] = getGrayScale(rgbData[x]); 
    } 

    Image grayImage = Image.createRGBImage(rgbData, width, height, true); 
    return grayImage; 
} 

static int[] p = new int[4]; 
private int getGrayScale(int c) { 

    p[0] = (int) ((c & 0xFF000000) >>> 24); // Opacity level 
    p[1] = (int) ((c & 0x00FF0000) >>> 16); // Red level 
    p[2] = (int) ((c & 0x0000FF00) >>> 8); // Green level 
    p[3] = (int) (c & 0x000000FF); // Blue level 

    int nc = p[1]/3 + p[2]/3 + p[3]/3; 
    // a little bit brighter 
    nc = nc/2 + 127; 

    p[1] = nc; 
    p[2] = nc; 
    p[3] = nc; 

    int gc = (p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]); 
    return gc; 
} 

(Si vous ne voulez vraiment pas d'utiliser l'espace de données de classe, il suffit de remplacer l'int [] avec quatre int locale séparée variables qui vivraient sur la pile)