En Java, convertir une image en sRGB rend l'image trop lumineuse

j'ai plusieurs images avec un profil personnalisé intégré en eux et que vous voulez convertir l'image en sRGB pour le servir d'un navigateur. J'ai vu le code suivant:

BufferedImage image = ImageIO.read(fileIn);
ColorSpace ics = ColorSpace.getInstance(ColorSpace.CS_sRGB);
ColorConvertOp cco = new ColorConvertOp(ics, null);
BufferedImage result = cco.filter(image, null);
ImageIO.write(result, "PNG", fileOut);

fileIn et fileOut sont des objets de fichier représentant respectivement le fichier d'entrée et le fichier de sortie. Cela fonctionne dans une certaine mesure. Le problème est que l'image résultante est plus légère que l'originale. Si je devais convertir l'espace de couleur dans photoshop le couleurs semblent les mêmes. En fait, si je sors les deux images avec photoshop et que je prends un screen shot et que j'échantillonne les couleurs, elles sont identiques. Que fait photoshop pour que le code ci-dessus ne le soit pas et que puis-je faire pour corriger le problème?

il existe différents types d'images converties, y compris JPEG, PNG, et TIFF. J'ai essayé d'utiliser TwelveMonkeys pour lire dans les images JPEG et TIFF et j'obtiens toujours le même effet, où l'image est trop lumière. Le processus de conversion semble le plus mauvais lorsqu'il est appliqué à une image qui n'a pas de profil intégré en premier lieu.

Edit:

enter image description here enter image description here enter image description here

j'ai ajouté quelques exemples d'images pour expliquer le problème.

  1. Cette image est celle avec le profil de couleur incorporé. Vu sur certains navigateurs il n'y aura pas de différence notable entre celui-ci et le suivant mais vu dans Chrome sur Mac OSX et Windows, il apparaît actuellement plus sombre qu'il ne devrait. C'est là que mon problème provient en premier lieu. Je dois convertir l'image en quelque chose qui apparaîtra correctement dans Chrome.
  2. il s'agit d'une image convertie avec ImageMagick au profil couleur Adobe RGB 1998, que Chrome semble pouvoir afficher correctement.
  3. c'est l'image que j'ai convertie en utilisant le code ci-dessus et elle apparaît plus légère qu'elle ne devrait.

(notez que les images ci-dessus sont sur imgur donc pour les rendre plus grandes, il suffit de supprimer le " t " de la fin du nom du fichier, avant l'extension du fichier.)

2
demandé sur Michael Hogenson 2015-02-19 00:08:23

2 réponses

C'était ma solution initiale qui fonctionnait mais je n'aimais pas avoir à utiliser ImageMagick. J'ai créé une autre réponse basée sur la solution que j'ai finalement retenue.

j'ai cédé et j'ai fini par utiliser im4java , qui est un wrapper autour de l'outil en ligne de commande d'image magick. Quand j'utilise le code suivant pour obtenir un BufferedImage, ça marche vraiment bien.

IMOperation op = new IMOperation();
op.addImage(fileIn.getAbsolutePath());
op.profile(colorFileIn.getAbsolutePath());
op.addImage("png:-");

ConvertCmd cmd = new ConvertCmd();
Stream2BufferedImage s2b = new Stream2BufferedImage();
cmd.setOutputConsumer(s2b);
cmd.run(op);
BufferedImage image = s2b.getImage();

je peux aussi utilisez la bibliothèque pour appliquer un profil CMJN pour imprimer au besoin. Ce serait bien si ColorConvertOp de la conversion correctement, mais pour l'instant, au moins, c'est ma solution. Afin d'atteindre la parité avec ma question, le code im4java pour obtenir le même effet dans la question Est:

ConvertCmd cmd = new ConvertCmd();

IMOperation op = new IMOperation();
op.addImage(fileIn.getAbsolutePath());
op.profile(colorFileIn.getAbsolutePath());
op.addImage(fileOut.getAbsolutePath());

cmd.run(op);

colorFileIn.getAboslutePath() est l'emplacement du profil de couleur sRGB sur la machine. Comme im4java utilise la ligne de commande, ce n'est pas aussi simple d'effectuer des opérations, mais la Bibliothèque est expliquée en détail ici . J'avais initialement des problèmes avec image magick ne travaillant pas sur mon Mac comme expliqué dans la question. Je l'ai installé en utilisant brew mais il s'avère sur un Mac que vous devez l'installer comme brew install imagemagick --with-little-cms . Après cette image, magick a bien travaillé pour moi.

1
répondu Michael Hogenson 2015-03-06 20:40:23

j'ai trouvé une solution qui ne nécessite pas ImageMagick. Fondamentalement, Java ne respecte pas le profil lors du chargement de l'image, donc s'il y en a un, il doit être chargé. Voici un extrait de code de ce que j'ai fait pour accomplir ceci:

private BufferedImage loadBufferedImage(InputStream inputStream) throws IOException, BadElementException {
    byte[] imageBytes = IOUtils.toByteArray(inputStream);
    BufferedImage incorrectImage = ImageIO.read(new ByteArrayInputStream(imageBytes));

    if (incorrectImage.getColorModel() instanceof ComponentColorModel) {

        // Java does not respect the color profile embedded in a component based image, so if there is a color
        // profile, detected using iText, then create a buffered image with the correct profile.
        Image iTextImage = Image.getInstance(imageBytes);
        com.itextpdf.text.pdf.ICC_Profile iTextProfile = iTextImage.getICCProfile();

        if (iTextProfile == null) {
            // If no profile is present than the image should be processed as is.
            return incorrectImage;
        } else {
            // If there is a profile present then create a buffered image with the profile embedded.
            byte[] profileData = iTextProfile.getData();
            ICC_Profile profile = ICC_Profile.getInstance(profileData);
            ICC_ColorSpace ics = new ICC_ColorSpace(profile);

            boolean hasAlpha = incorrectImage.getColorModel().hasAlpha();
            boolean isAlphaPremultiplied = incorrectImage.isAlphaPremultiplied();
            int transparency = incorrectImage.getTransparency();
            int transferType = DataBuffer.TYPE_BYTE;
            ComponentColorModel ccm = new ComponentColorModel(ics, hasAlpha, isAlphaPremultiplied, transparency, transferType);
            return new BufferedImage(ccm, incorrectImage.copyData(null), isAlphaPremultiplied, null);
        }
    }
    else if (incorrectImage.getColorModel() instanceof IndexColorModel) {
        return incorrectImage;
    }
    else {
        throw new UnsupportedEncodingException("Unsupported color model type.");
    }
}

This answer does use iText , qui est généralement utilisé pour la création et la manipulation de PDF, mais il se trouve que le traitement des profils ICC correctement et je suis déjà dépendant pour mon projet donc il c'est un bien meilleur choix qu'ImageMagick.

le code de la question se termine alors comme suit:

BufferedImage image = loadBufferedImage(new FileInputStream(fileIn));
ColorSpace ics = ColorSpace.getInstance(ColorSpace.CS_sRGB);
ColorConvertOp cco = new ColorConvertOp(ics, null);
BufferedImage result = cco.filter(image, null);
ImageIO.write(result, "PNG", fileOut);

qui fonctionne très bien.

1
répondu Michael Hogenson 2015-03-06 20:50:22