Question

Comme le dit le titre, je suis en train d'utiliser des tables de quantification pour compresser une image au format JPEG.Mon problème est le fichier qui en résulte ne peut pas être ouvert et l'erreur est:

Quantization table 0x00 was not defined

C'est de cette façon que mon code ressemble à ceci:

        JPEGImageWriteParam params = new JPEGImageWriteParam(null);
        if (mQMatrix != null) {
            JPEGHuffmanTable[] huffmanDcTables = {JPEGHuffmanTable.StdDCLuminance, JPEGHuffmanTable.StdDCChrominance};
            JPEGHuffmanTable[] huffmanAcTables = {JPEGHuffmanTable.StdACLuminance, JPEGHuffmanTable.StdACChrominance};
            dumpMatrices(mQMatrix);
            params.setEncodeTables(mQMatrix, huffmanDcTables, huffmanAcTables);
        }

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

        Iterator writers = ImageIO.getImageWritersByFormatName("JPEG");
        ImageWriter imageWriter = (ImageWriter) writers.next();

        ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(outputStream);
        imageWriter.setOutput(imageOutputStream);
        imageWriter.write(null, new IIOImage(mSourceImage, null, null), params);

        mCompressedImageSize = outputStream.size();

        try (FileOutputStream fileOutputStream = new FileOutputStream(mOutFileName)) {
            fileOutputStream.write(outputStream.toByteArray());

        }
        mCompressedImage = ImageIO.read(new ByteArrayInputStream(outputStream.toByteArray()));

Ma conjecture est qu'il a quelque chose à voir avec les métadonnées, mais je n'avais aucune chance de trouver une solution.

Merci, R.

Mise à JOUR:À l'aide d'un hex viewer j'ai déterminé que la quantification de la table (DQT - 0xFF, 0xDB l'article) n'est pas écrit dans le fichier de sortie.Je suis en supposant que j'ai pour le forcer à être écrite en quelque sorte.

Mise à JOUR 2:Donc après avoir fait le débogage de l'exécution, ce que j'ai trouvé est que si les tables sont définies dans les paramètres de l'objet, puis les métadonnées ne sont pas générés ni la quantification pas les tables de Huffman.Si les métadonnées sont manquants, les tables ne sont pas écrites dans le fichier.Le truc c'est que je ne vois aucune façon de personnaliser le contenu des métadonnées.

Était-ce utile?

La solution

Question très intéressante, et malheureusement non négligeable...Voici ce que j'ai trouvé:

Tout d'abord, à l'aide de JPEGImageWriteParam.setEncodeTables(...) ne fait pas.À partir de la JavaDoc:

Jeux de la quantification et de Huffman tables à utiliser dans l'encodage abrégé des flux.

De plus en plus de JPEG Format de Métadonnées de Spécification et de Notes d'Utilisation:

Cette commande met en œuvre la conception de l'intention que les tables doivent être inclus dans JPEGImageWriteParams seulement comme un moyen de spécifier les tables lorsque aucune autre source n'est disponible, et cela ne peut se produire que lors de la rédaction d'une présentation abrégée de flux sans tables à l'aide des non-tableaux standard pour la compression.

I. e., le param option peut seulement être utilisé pour l'écriture de "l'abrégé des flux" (douanes Jpeg, sans tables, en supposant que les tableaux seront fournis lors de la lecture à l'arrière).Conclusion:La seule façon que nous pouvons spécifier les tables à être codé avec le JPEG, est à passer dans les méta-données.

De la même document mentionné ci-dessus, les tableaux dans les métadonnées seront ignorés et remplacé, à moins que mode de compression est MODE_COPY_FROM_METADATA, nous avons donc besoin de préciser que.

Voir la Les Métadonnées de l'Image DTD pour la documentation sur la structure des métadonnées.Les parties importantes sont la dqt et dht les nœuds avec des sous-nœuds, et leur "objet Utilisateur"s (à ne pas confondre avec DOM normal "userData").Nous avons besoin de mettre à jour ces nœuds, avec les nouvelles tables que nous voulons utiliser.

Voici le code, je suis venu avec:

// Obtain qtables
mQMatrix = ...;

// Read source image
ImageInputStream imageInputStream = ImageIO.createImageInputStream(...);
ImageReader reader = ImageIO.getImageReaders(imageInputStream).next();
reader.setInput(imageInputStream);

mSourceImage = reader.read(0);
IIOMetadata metadata = null;

// We need the imageWriter to create the default JPEG metadata
ImageWriter imageWriter = ImageIO.getImageWritersByFormatName("JPEG").next();

if (mQMatrix != null) {
    dumpMatrices(mQMatrix);

    // Obtain default image metadata data, in native JPEG format
    metadata = imageWriter.getDefaultImageMetadata(ImageTypeSpecifier.createFromRenderedImage(m‌​SourceImage), null);
    IIOMetadataNode nativeMeta = (IIOMetadataNode) metadata.getAsTree("javax_imageio_jpeg_image_1.0");

    // Update dqt to values from mQMatrix
    NodeList dqtables = nativeMeta.getElementsByTagName("dqtable");
    for (int i = 0; i < dqtables.getLength(); i++) {
        IIOMetadataNode dqt = (IIOMetadataNode) dqtables.item(i);
        int dqtId = Integer.parseInt(dqt.getAttribute("qtableId"));
        dqt.setUserObject(mQMatrix[dqtId]);
    }

    // For some reason, we need dht explicitly defined, when using MODE_COPY_FROM_METADATA...
    NodeList dhtables = nativeMeta.getElementsByTagName("dhtable");

    // Just use defaults for dht
    JPEGHuffmanTable[] huffmanDcTables = {JPEGHuffmanTable.StdDCLuminance, JPEGHuffmanTable.StdDCChrominance};
    JPEGHuffmanTable[] huffmanAcTables = {JPEGHuffmanTable.StdACLuminance, JPEGHuffmanTable.StdACChrominance};

    // Update dht
    for (int i = 0; i < dhtables.getLength(); i++) {
        IIOMetadataNode dht = (IIOMetadataNode) dhtables.item(i);
        int dhtClass = Integer.parseInt(dht.getAttribute("class")); // 0: DC, 1: AC
        int dhtId = Integer.parseInt(dht.getAttribute("htableId"));

        dht.setUserObject(dhtClass == 0 ? huffmanDcTables[dhtId] : huffmanAcTables[dhtId]);
    }

    // Merge updated tree back (important!)
    metadata.mergeTree("javax_imageio_jpeg_image_1.0", nativeMeta);
}

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(outputStream);
imageWriter.setOutput(imageOutputStream);

// See http://docs.oracle.com/javase/6/docs/api/javax/imageio/metadata/doc-files/jpeg_metadata.html#tables
JPEGImageWriteParam params = new JPEGImageWriteParam(null);
params.setCompressionMode(metadata == null ? MODE_DEFAULT : MODE_COPY_FROM_METADATA); // Unless MODE_COPY_FROM_METADATA, tables will be created!

imageWriter.write(null, new IIOImage(mSourceImage, null, metadata), params);
imageOutputStream.close();

mCompressedImageSize = outputStream.size();

try (FileOutputStream fileOutputStream = new FileOutputStream(mOutFileName)) {
    fileOutputStream.write(outputStream.toByteArray());
}

mCompressedImage = ImageIO.read(new ByteArrayInputStream(outputStream.toByteArray()));
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top