Question Conversion de gif / png transparent en jpeg en utilisant java


Je voudrais convertir des images gif en jpeg en utilisant Java. Cela fonctionne très bien pour la plupart des images, mais j'ai une image gif transparente simple:

Image gif d'entrée http://img292.imageshack.us/img292/2103/indexedtestal7.gif

[Si l'image est manquante: il s'agit d'un cercle bleu avec des pixels transparents autour d'elle]

Lorsque je convertis cette image en utilisant le code suivant:

File file = new File("indexed_test.gif");
BufferedImage image = ImageIO.read(file);
File f = new File("indexed_test.jpg");
ImageIO.write(image, "jpg", f);

Ce code fonctionne sans lancer d'exception, mais génère une image JPEG non valide:

Image jpeg de sortie http://img297.imageshack.us/img297/3493/indexedtest1qe5.jpg

[Si l'image est manquante: IE ne peut pas afficher le jpeg, Firefox affiche l'image avec des couleurs non valides.]

J'utilise Java 1.5.

J'ai également essayé de convertir l'exemple gif en png avec gimp et d'utiliser le png comme entrée pour le code Java. Le résultat est le même.

Est-ce un bug dans le JDK? Comment puis-je convertir les images correctement, de préférence sans bibliothèques tierces?

METTRE À JOUR:

Les réponses indiquent que la conversion JPEG ne peut pas gérer correctement la transparence (je pense toujours qu’il s’agit d’un bogue) et propose une solution pour remplacer les pixels transparents par une couleur prédéfinie. Les deux méthodes suggérées sont assez complexes et j'ai donc mis en œuvre une méthode plus simple (qui sera publiée en tant que réponse). J'accepte la première réponse publiée avec cette solution de contournement (par Markus). Je ne sais pas quelle mise en œuvre est la meilleure. Je vais pour le plus simple encore j'ai trouvé un gif où il ne fonctionne pas.


19
2018-01-21 10:58


origine


Réponses:


Pour Java 6 (et 5 aussi, je pense):

BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_RGB);
g = bufferedImage.createGraphics();
//Color.WHITE estes the background to white. You can use any other color
g.drawImage(image, 0, 0, bufferedImage.getWidth(), bufferedImage.getHeight(), Color.WHITE, null);

41
2017-10-09 18:39



Comme déjà mentionné dans la mise à jour de la question, j'ai implémenté un moyen plus simple de remplacer les pixels transparents par une couleur prédéfinie:

public static BufferedImage fillTransparentPixels( BufferedImage image, 
                                                   Color fillColor ) {
    int w = image.getWidth();
    int h = image.getHeight();
    BufferedImage image2 = new BufferedImage(w, h, 
        BufferedImage.TYPE_INT_RGB);
    Graphics2D g = image2.createGraphics();
    g.setColor(fillColor);
    g.fillRect(0,0,w,h);
    g.drawRenderedImage(image, null);
    g.dispose();
    return image2;
}

et j'appelle cette méthode avant la conversion JPEG de cette façon:

if( inputImage.getColorModel().getTransparency() != Transparency.OPAQUE) {
    inputImage = fillTransparentPixels(inputImage, Color.WHITE);
}

8
2018-01-22 09:08



Le problème (au moins avec la conversion png-jpg) est que le schéma de couleurs n'est pas le même, car le jpg ne supporte pas la transparence.

Ce que nous avons fait avec succès est quelque chose dans ce sens (ceci est tiré de différents bouts de code - veuillez donc pardonner la grossièreté du formatage):

File file = new File("indexed_test.gif");
BufferedImage image = ImageIO.read(file);
int width = image.getWidth();
int height = image.getHeight();
BufferedImage jpgImage;

//you can probably do this without the headless check if you just use the first block
if (GraphicsEnvironment.isHeadless()) {
  if (image.getType() == BufferedImage.TYPE_CUSTOM) {
      //coerce it to  TYPE_INT_ARGB and cross fingers -- PNGs give a    TYPE_CUSTOM and that doesn't work with
      //trying to create a new BufferedImage
     jpgImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_ARGB);
  } else {
     jpgImage = new BufferedImage(width, height, image.getType());
  }
} else {
     jgpImage =   GraphicsEnvironment.getLocalGraphicsEnvironment().
        getDefaultScreenDevice().getDefaultConfiguration().
        createCompatibleImage(width, height, image.getTransparency()); 
}

//copy the original to the new image
Graphics2D g2 = null;
try {
 g2 = jpg.createGraphics();

 g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, 
                    RenderingHints.VALUE_INTERPOLATION_BICUBIC);
 g2.drawImage(image, 0, 0, width, height, null);
}
finally {
   if (g2 != null) {
       g2.dispose();
   }
}

File f = new File("indexed_test.jpg");

ImageIO.write(jpgImage, "jpg", f);

Cela fonctionne pour png à jpg et gif à jpg. Et vous aurez un fond blanc où se trouvaient les bits transparents. Vous pouvez changer cela en faisant en sorte que g2 remplisse l'image avec une autre couleur avant l'appel drawImage.


4
2018-01-21 16:58



3 mois de retard, mais j'ai un problème très similaire (bien que ne pas même charger un gif, mais simplement générer une image transparente - disons, pas d'arrière-plan, une forme colorée - où en enregistrant en JPEG, toutes les couleurs sont gâchées, non seulement l'arrière-plan)

Trouvé ce bit de code dans ce fil plutôt vieux de la liste java2d-interest, je pensais partager, car après un test rapide, il est beaucoup plus performant que votre solution:

        final WritableRaster raster = img.getRaster();
        final WritableRaster newRaster = raster.createWritableChild(0, 0, img.getWidth(), img.getHeight(), 0, 0, new int[]{0, 1, 2});

        // create a ColorModel that represents the one of the ARGB except the alpha channel
        final DirectColorModel cm = (DirectColorModel) img.getColorModel();
        final DirectColorModel newCM = new DirectColorModel(cm.getPixelSize(), cm.getRedMask(), cm.getGreenMask(), cm.getBlueMask());

        // now create the new buffer that we'll use to write the image
        return new BufferedImage(newCM, newRaster, false, null);

Malheureusement, je ne peux pas dire que je comprends exactement ce qu'il fait ;)


4
2018-05-13 16:37



Si vous créez un BufferedImage de type BufferedImage.TYPE_INT_ARGB et que vous enregistrez au format JPEG, des choses étranges se produiront. Dans mon cas, les couleurs sont colorées en orange. Dans d'autres cas, l'image produite peut être invalide et d'autres lecteurs refusent de la charger.

Mais si vous créez une image de type BufferedImage.TYPE_INT_RGB, l'enregistrez au format JPEG fonctionne correctement.

Je pense que ceci est donc un bogue dans le graveur d’images Java JPEG - il ne devrait écrire que ce qu’il peut sans transparence (comme le fait .NET GDI +). Ou, dans le pire des cas, lancer une exception avec un message significatif, par ex. "ne peut pas écrire une image qui a de la transparence".


3
2018-01-05 10:14



JPEG ne prend pas en charge la transparence. Donc, même si vous obtenez la couleur du cercle correctement, vous aurez toujours un arrière-plan noir ou blanc, selon votre encodeur et / ou votre moteur de rendu.


2
2018-01-21 11:01



BufferedImage originalImage = ImageIO.read(getContent());
BufferedImage newImage = new BufferedImage(originalImage.getWidth(), originalImage.getHeight(), BufferedImage.TYPE_3BYTE_BGR);

    for (int x = 0; x < originalImage.getWidth(); x++) {
        for (int y = 0; y < originalImage.getHeight(); y++) {
            newImage.setRGB(x, y, originalImage.getRGB(x, y));
        }
    }

1
2018-03-07 18:41