corona  1.0.2
OpenTGA.cpp
Go to the documentation of this file.
00001 #include <algorithm>
00002 #include <string.h>
00003 #include "Debug.h"
00004 #include "Open.h"
00005 #include "SimpleImage.h"
00006 #include "Utility.h"
00007 
00008 
00009 namespace corona {
00010 
00011   Image* OpenTGA(File* file) {
00012     COR_GUARD("OpenTGA");
00013 
00014     // read header
00015     byte header[18];
00016     if (file->read(header, 18) != 18) {
00017       return 0;
00018     }
00019 
00020     // decode header
00021     int id_length        = header[0];
00022     int cm_type          = header[1];
00023     int image_type       = header[2];
00024     //int cm_first         = read16_le(header + 3);
00025     int cm_length        = read16_le(header + 5);
00026     int cm_entry_size    = header[7];  // in bits
00027     //int x_origin         = read16_le(header + 8);
00028     //int y_origin         = read16_le(header + 10);
00029     int width            = read16_le(header + 12);
00030     int height           = read16_le(header + 14);
00031     int pixel_depth      = header[16];
00032     int image_descriptor = header[17];
00033     
00034     bool mirrored = (image_descriptor & (1 << 4)) != 0;  // left-to-right?
00035     bool flipped  = (image_descriptor & (1 << 5)) == 0;  // bottom-to-top?
00036 
00037     /*
00038      * image types
00039      * 0  = no image data
00040      * 1  = uncompressed, color-mapped
00041      * 2  = uncompressed, true-color
00042      * 3  = uncompressed, black and white
00043      * 9  = RLE, color-mapped
00044      * 10 = RLE, true-color
00045      * 11 = RLE, black and white
00046      */
00047 
00048     // make sure we support the image
00049     if (image_type != 2 || (pixel_depth != 24 && pixel_depth != 32)) {
00050       return 0;
00051     }
00052 
00053     // skip image id
00054     byte unused[255];
00055     if (file->read(unused, id_length) != id_length) {
00056       return 0;
00057     }
00058 
00059     // skip color map
00060     if (cm_type != 0) {
00061       // allocate color map
00062       int cm_entry_bytes = (cm_entry_size + 7) / 8;
00063       int cm_size = cm_entry_bytes * cm_length;
00064       auto_array<byte> color_map(new byte[cm_size]);
00065       if (file->read(color_map, cm_size) != cm_size) {
00066         return 0;
00067       }
00068     }
00069 
00070     // read image data
00071     PixelFormat format;
00072     auto_array<byte> pixels;
00073     if (pixel_depth == 24) {
00074 
00075       COR_LOG("24-bit image");
00076 
00077       format = PF_B8G8R8;
00078       int image_size = width * height * 3;
00079       pixels = new byte[image_size];
00080       if (file->read(pixels, image_size) != image_size) {
00081         return 0;
00082       }
00083 
00084     } else if (pixel_depth == 32) {
00085 
00086       COR_LOG("32-bit image");
00087 
00088       format = PF_B8G8R8A8;
00089       int image_size = width * height * 4;
00090       pixels = new byte[image_size];
00091       if (file->read(pixels, image_size) != image_size) {
00092         return 0;
00093       }
00094 
00095     } else {
00096       return 0;
00097     }
00098 
00099     // reverse each row
00100     if (mirrored) {
00101       COR_LOG("Image is mirrored");
00102 
00103       const int bpp = pixel_depth / 8;  // bytes per pixel
00104       for (int y = 0; y < height; ++y) {
00105 
00106         // points to the first pixel of the row
00107         byte* start = pixels.get() + y * width * bpp;
00108         // points to the last pixel of the row
00109         byte* end   = start + (width - 1) * bpp;
00110 
00111         while (start < end) {
00112           for (int b = 0; b < bpp; ++b) {
00113             std::swap(start[b], end[b]);
00114           }
00115           start += bpp;
00116           end   -= bpp;
00117         }
00118       }
00119     }
00120 
00121     // reverse rows as a whole
00122     if (flipped) {
00123       COR_LOG("Image is flipped");
00124 
00125       const int bpp = pixel_depth / 8;  // bytes per pixel
00126       const int row_size = width * bpp;
00127       auto_array<byte> temp(new byte[row_size]);  // for the swap
00128 
00129       // points to the beginning of the first row
00130       byte* start = pixels.get();
00131 
00132       // points to the beginning of the last row
00133       byte* end   = start + (height - 1) * width * bpp;
00134 
00135       while (start < end) {
00136         memcpy(temp.get(), start,      row_size);
00137         memcpy(start,      end,        row_size);
00138         memcpy(end,        temp.get(), row_size);
00139 
00140         start += row_size;
00141         end   -= row_size;
00142       }
00143     }
00144 
00145     return new SimpleImage(width, height, format, pixels.release());
00146   }
00147 
00148 }