Java TGA loader

2019-02-13 13:08发布

问题:

I am looking for a small and free TGA image loading class or library for java. Ideally the result is a BufferedImage.

Yes, I have already googled, but most results are outdated, or are quite big libraries that contain a lot of other stuff i dont need. I am looking for something small and simple that reads just TGA images.

Thanks!

回答1:

We use this class copied from some open source project to read TGA files. It's really old. It can only handle Targa files with most basic encoding. Give it a try.

public class TargaReader
{
        public static Image getImage(String fileName) throws IOException
        {
                File f = new File(fileName);
                byte[] buf = new byte[(int)f.length()];
                BufferedInputStream bis = new BufferedInputStream(new FileInputStream(f));
                bis.read(buf);
                bis.close();
                return decode(buf);
        }

        private static int offset;

        private static int btoi(byte b)
        {
                int a = b;
                return (a<0?256+a:a);
        }

        private static int read(byte[] buf)
        {
                return btoi(buf[offset++]);
        }

        public static Image decode(byte[] buf) throws IOException
        {
                offset = 0;

                // Reading header
                for (int i=0;i<12;i++)
                        read(buf);
                int width = read(buf)+(read(buf)<<8);
                int height = read(buf)+(read(buf)<<8);
                read(buf);
                read(buf);

                // Reading data
                int n = width*height;
                int[] pixels = new int[n];
                int idx=0;

                while (n>0)
                {
                        int nb = read(buf);
                        if ((nb&0x80)==0)
                        {
                                for (int i=0;i<=nb;i++)
                                {
                                        int b = read(buf);
                                        int g = read(buf);
                                        int r = read(buf);
                                        pixels[idx++] = 0xff000000 | (r<<16) | (g<<8) | b;
                                }
                        }
                        else
                        {
                                nb &= 0x7f;
                                int b = read(buf);
                                int g = read(buf);
                                int r = read(buf);
                                int v = 0xff000000 | (r<<16) | (g<<8) | b;
                                for (int i=0;i<=nb;i++)
                                        pixels[idx++] = v;
                        }
                        n-=nb+1;
                }

                BufferedImage bimg = new BufferedImage(width,height,BufferedImage.TYPE_INT_ARGB);
                bimg.setRGB(0,0,width,height,pixels,0,width);
                return bimg;
        }
}


回答2:

I had uncompressed targa images, so had to tweak example code. Here is my edit it should support uncompressed targa 24bit BGR and 32bit BGRA

// http://paulbourke.net/dataformats/tga/
// little endian multi-byte integers: "low-order byte,high-order byte"
//          00,04 -> 04,00 -> 1024
class TargaReader {
        public static BufferedImage getImage(String fileName) throws IOException {
                File f = new File(fileName);
                byte[] buf = new byte[(int)f.length()];
                BufferedInputStream bis = new BufferedInputStream(new FileInputStream(f));
                bis.read(buf);
                bis.close();
                return decode(buf);
        }

        private static int offset;

        private static int btoi(byte b) {
                int a = b;
                return (a<0?256+a:a);
        }

        private static int read(byte[] buf) {
                return btoi(buf[offset++]);
        }

        public static BufferedImage decode(byte[] buf) throws IOException {
                offset = 0;

                // Reading header bytes
                // buf[2]=image type code 0x02=uncompressed BGR or BGRA
                // buf[12]+[13]=width
                // buf[14]+[15]=height
                // buf[16]=image pixel size 0x20=32bit, 0x18=24bit 
                // buf{17]=Image Descriptor Byte=0x28 (00101000)=32bit/origin upperleft/non-interleaved
                for (int i=0;i<12;i++)
                        read(buf);
                int width = read(buf)+(read(buf)<<8);   // 00,04=1024
                int height = read(buf)+(read(buf)<<8);  // 40,02=576
                read(buf);
                read(buf);

                int n = width*height;
                int[] pixels = new int[n];
                int idx=0;

                if (buf[2]==0x02 && buf[16]==0x20) { // uncompressed BGRA
                    while(n>0) {
                        int b = read(buf);
                        int g = read(buf);
                        int r = read(buf);
                        int a = read(buf);
                        int v = (a<<24) | (r<<16) | (g<<8) | b;
                        pixels[idx++] = v;
                        n-=1;
                    }
                } else if (buf[2]==0x02 && buf[16]==0x18) {  // uncompressed BGR
                    while(n>0) {
                        int b = read(buf);
                        int g = read(buf);
                        int r = read(buf);
                        int a = 255; // opaque pixel
                        int v = (a<<24) | (r<<16) | (g<<8) | b;
                        pixels[idx++] = v;
                        n-=1;
                    }
                } else {
                    // RLE compressed
                    while (n>0) {
                        int nb = read(buf); // num of pixels
                        if ((nb&0x80)==0) { // 0x80=dec 128, bits 10000000
                            for (int i=0;i<=nb;i++) {
                                int b = read(buf);
                                int g = read(buf);
                                int r = read(buf);
                                pixels[idx++] = 0xff000000 | (r<<16) | (g<<8) | b;
                            }
                        } else {
                            nb &= 0x7f;
                            int b = read(buf);
                            int g = read(buf);
                            int r = read(buf);
                            int v = 0xff000000 | (r<<16) | (g<<8) | b;
                            for (int i=0;i<=nb;i++)
                                pixels[idx++] = v;
                        }
                        n-=nb+1;
                    }
                }

                BufferedImage bimg = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
                bimg.setRGB(0, 0, width,height, pixels, 0,width);
                return bimg;
        }
}


回答3:

I've added a standalone copy of Reality Interactive's ImageIO TGA library here (LGPL):

https://github.com/tmyroadctfig/com.realityinteractive.imageio.tga


Just add the the jar file to your classpath and register with ImageIO:

IIORegistry registry = IIORegistry.getDefaultInstance();
registry.registerServiceProvider(
    new com.realityinteractive.imageio.tga.TGAImageReaderSpi());


回答4:

Just in case anyone is looking for the Android version of this (I had to replace BufferedImage with Bitmap).

class TargaReader {
    public static Bitmap getImage(String fileName) throws IOException {
        File f = new File(fileName);
        byte[] buf = new byte[(int) f.length()];
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(f));
        bis.read(buf);
        bis.close();
        return decode(buf);
    }

    private static int offset;

    private static int btoi(byte b) {
        int a = b;
        return (a < 0 ? 256 + a : a);
    }

    private static int read(byte[] buf) {
        return btoi(buf[offset++]);
    }

    public static Bitmap decode(byte[] buf) throws IOException {
        offset = 0;

        // Reading header bytes
        // buf[2]=image type code 0x02=uncompressed BGR or BGRA
        // buf[12]+[13]=width
        // buf[14]+[15]=height
        // buf[16]=image pixel size 0x20=32bit, 0x18=24bit
        // buf{17]=Image Descriptor Byte=0x28 (00101000)=32bit/origin 
        //         upperleft/non-interleaved
        for (int i = 0; i < 12; i++)
            read(buf);
        int width = read(buf) + (read(buf) << 8);   // 00,04=1024
        int height = read(buf) + (read(buf) << 8);  // 40,02=576
        read(buf);
        read(buf);

        int n = width * height;
        int[] pixels = new int[n];
        int idx = 0;

        if (buf[2] == 0x02 && buf[16] == 0x20) { // uncompressed BGRA
            while (n > 0) {
                int b = read(buf);
                int g = read(buf);
                int r = read(buf);
                int a = read(buf);
                int v = (a << 24) | (r << 16) | (g << 8) | b;
                pixels[idx++] = v;
                n -= 1;
            }
        } else if (buf[2] == 0x02 && buf[16] == 0x18) {  // uncompressed BGR
            while (n > 0) {
                int b = read(buf);
                int g = read(buf);
                int r = read(buf);
                int a = 255; // opaque pixel
                int v = (a << 24) | (r << 16) | (g << 8) | b;
                pixels[idx++] = v;
                n -= 1;
            }
        } else {
            // RLE compressed
            while (n > 0) {
                int nb = read(buf); // num of pixels
                if ((nb & 0x80) == 0) { // 0x80=dec 128, bits 10000000
                    for (int i = 0; i <= nb; i++) {
                        int b = read(buf);
                        int g = read(buf);
                        int r = read(buf);
                        pixels[idx++] = 0xff000000 | (r << 16) | (g << 8) | b;
                    }
                } else {
                    nb &= 0x7f;
                    int b = read(buf);
                    int g = read(buf);
                    int r = read(buf);
                    int v = 0xff000000 | (r << 16) | (g << 8) | b;
                    for (int i = 0; i <= nb; i++)
                        pixels[idx++] = v;
                }
                n -= nb + 1;
            }
        }

        Bitmap bimg = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        bimg.setPixels(pixels, 0, width, 0, 0, width, height);
        return bimg;
    }
}


回答5:

Thanks for sharing it!

I've made some changes to improve performance. I'm only doing BGRA 32 Bits file decrypt, but it can help others people.

public static BufferedImage createTGAImage(byte[] buff) throws IOException {
    int offset = 0, width = 0, height = 0;
    int[] tgaBuffer = null;

    if (buff[2] == 0x02) { // BGRA File

        offset = 12;
        width = (buff[offset + 1] << 8 | buff[offset]);

        offset = 14;
        height = (buff[offset + 1] << 8 | buff[offset]);

        int colorDepth = buff[offset + 2];

        if (colorDepth == 0x20) { // 32 bits depth
            offset = 18;

            int count = width * height;
            tgaBuffer = new int[count];

            for (int i = 0; i < count; i++) {
                byte b = buff[offset++]; //This is for didatic prupose, you can remove it and make inline covert.
                byte g = buff[offset++];
                byte r = buff[offset++];
                byte a = buff[offset++];

                tgaBuffer[i] = ((a & 0xFF) << 24 | (r & 0xFF) << 16 | (g & 0xFF)<< 8 | b & 0xFF);
            }
        }
    }

    BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    result.setRGB(0, 0, width, height, tgaBuffer, 0, width);

    return result;
}