Search code examples
javax.imageiotwelvemonkeys

Convert a PNG to PPM using ImageIO TwelveMonkey extension


I have a requirement to convert a PNG file to PPM file. In the same project, I have used TwelveMonkey extension to convert a PPM to PNG and it results perfectly. But when trying the other way round, it results in error.

The output PPM file will always have height=16 and Width=60, so I also need to figure out a way to scale down the PNG without losing on quality drastically.

Dependencies :

        <dependency>
            <groupId>com.twelvemonkeys.imageio</groupId>
            <artifactId>imageio-jpeg</artifactId>
            <version>3.9.3</version>
        </dependency>
        <dependency>
            <groupId>com.twelvemonkeys.imageio</groupId>
            <artifactId>imageio-tiff</artifactId>
            <version>3.9.3</version>
        </dependency>
        <dependency>
            <groupId>com.twelvemonkeys.imageio</groupId>
            <artifactId>imageio-pnm</artifactId>
            <version>3.9.3</version>
        </dependency>

Code :

public static File convertPngToPPM(File pngFile, String fileName) {

        File ppmFile=new File(fileName.concat(".ppm"));

        try {
            BufferedImage inputImage=ImageIO.read(pngFile);
            
            int imageHeight=inputImage.getHeight()==16 ? inputImage.getHeight() : 16;
            int imageWidth=inputImage.getWidth() == 60 ? inputImage.getWidth() : 60;

            BufferedImage resizedImage=resizeImage(inputImage, imageWidth, imageHeight);

            ImageIO.write(resizedImage, "ppm", ppmFile);

        } catch (Exception e){
            log.error(e.getMessage());
            log.error("Error reading the PPM file");
        }
        return null;
    }

private static BufferedImage resizeImage(BufferedImage originalImage, int targetWidth, int targetHeight) {
        Image resultingImage = originalImage.getScaledInstance(targetWidth, targetHeight, Image.SCALE_SMOOTH);
        BufferedImage outputImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB);
        outputImage.getGraphics().drawImage(resultingImage, 0, 0, null);
        return outputImage;
    }

Error:

2022-11-10 17:42:31.438 ERROR 17389 --- [  XNIO-1 task-1] com.mycompany.utilities.ImageUtilities   : Unsupported data type: 3

Solution

  • The error message just prints the exception message out of context, which isn't really that useful. If you instead print the full stack trace, you'll see that it points to a place in the code which says:

    // TODO: Support TYPE_INT through conversion, if number of channels is 3 or 4 (TYPE_INT_RGB, TYPE_INT_ARGB)
    

    In other words, BufferedImage.TYPE_INT_RGB isn't currently supported.

    This is easy to fix, just convert your image to TYPE_3BYTE_BGR instead of TYPE_INT_RGB, and your code works fine. In resizeImage:

    BufferedImage outputImage = 
                  new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_3BYTE_BGR);
    

    PS: Throwing this exception is not really good behavior from the PNM plugin, as it should instead just report that it doesn't support this input, and ImageIO.write should return false. So I think this could be classified as a bug.