corona  1.0.2
Convert.cpp
Go to the documentation of this file.
00001 
00006 #include <map>
00007 #include <utility>
00008 #include <string.h>
00009 #include "corona.h"
00010 #include "Debug.h"
00011 #include "SimpleImage.h"
00012 #include "Utility.h"
00013 
00014 
00015 namespace corona {
00016 
00017   Image* ExpandPalette(Image* image) {
00018     COR_GUARD("ExpandPalette()");
00019 
00020     // assert isPalettized(image->getFormat())
00021 
00022     const int width                  = image->getWidth();
00023     const int height                 = image->getHeight();
00024     const byte* in                   = (byte*)image->getPixels();
00025     const PixelFormat palette_format = image->getPaletteFormat();
00026     const int pixel_size             = GetPixelSize(palette_format);
00027     const byte* palette              = (byte*)image->getPalette();
00028 
00029     byte* pixels = new byte[width * height * pixel_size];
00030     byte* out = pixels;
00031     for (int i = 0; i < width * height; ++i) {
00032       memcpy(out, palette + (*in) * pixel_size, pixel_size);
00033       out += pixel_size;
00034       ++in;
00035     }
00036     delete image;
00037     return new SimpleImage(width, height, palette_format, pixels);
00038   }
00039 
00040 
00041   struct FormatDesc {
00042     FormatDesc(int r, int g, int b, int a, bool ha) {
00043       r_shift = r;
00044       g_shift = g;
00045       b_shift = b;
00046       a_shift = a;
00047       has_alpha = ha;
00048     }
00049 
00050     // shifts are in bytes from the right
00051     // In the case of RGBA, r_shift is 0, g_shift is 1, ...
00052     int r_shift;
00053     int g_shift;
00054     int b_shift;
00055     int a_shift;
00056     bool has_alpha;
00057   };
00058 
00059 
00060   #define DEFINE_DESC(format, desc)          \
00061     case format: {                           \
00062       COR_LOG(#format);                      \
00063       static FormatDesc format##_desc desc;  \
00064       return &format##_desc;                 \
00065     }
00066 
00067   FormatDesc* GetDescription(PixelFormat format) {
00068     // assert isDirect(image->getFormat())
00069 
00070     switch (format) {
00071       DEFINE_DESC(PF_R8G8B8A8, (0, 1, 2, 3, true));
00072       DEFINE_DESC(PF_R8G8B8,   (0, 1, 2, 0, false));
00073       DEFINE_DESC(PF_B8G8R8A8, (2, 1, 0, 3, true));
00074       DEFINE_DESC(PF_B8G8R8,   (2, 1, 0, 0, false));
00075       default: return 0;
00076     }
00077   }
00078 
00079 
00080   bool ConvertPixels(byte* out, PixelFormat out_format,
00081                      const byte* in,  PixelFormat in_format,
00082                      int pixel_count)
00083   {
00084     const FormatDesc* out_desc = GetDescription(out_format);
00085     const FormatDesc* in_desc  = GetDescription(in_format);
00086     if (!out_desc || !in_desc) {
00087       return false;
00088     }
00089 
00090     const int out_size = GetPixelSize(out_format);
00091     const int in_size  = GetPixelSize(in_format);
00092 
00093     for (int i = 0; i < pixel_count; ++i) {
00094       out[out_desc->r_shift] = in[in_desc->r_shift];
00095       out[out_desc->g_shift] = in[in_desc->g_shift];
00096       out[out_desc->b_shift] = in[in_desc->b_shift];
00097 
00098       if (out_desc->has_alpha) {
00099         if (in_desc->has_alpha) {
00100           out[out_desc->a_shift] = in[in_desc->a_shift];
00101         } else {
00102           out[out_desc->a_shift] = 255;
00103         }
00104       }
00105 
00106       in  += in_size;
00107       out += out_size;
00108     }
00109 
00110     return true;
00111   }
00112 
00113 
00114   Image* DirectConversion(Image* image, PixelFormat target_format) {
00115     COR_GUARD("DirectConversion()");
00116 
00117     // assert isDirect(image->getFormat())
00118 
00119     const int width                 = image->getWidth();
00120     const int height                = image->getHeight();
00121     const PixelFormat source_format = image->getFormat();
00122     const byte* in                  = (byte*)image->getPixels();
00123 
00124     if (source_format == target_format) {
00125         return image;
00126     }
00127 
00128     const int target_size = GetPixelSize(target_format);
00129     byte* out_pixels = new byte[width * height * target_size];
00130     if (!ConvertPixels(out_pixels, target_format,
00131                        in, source_format,
00132                        width * height))
00133     {
00134       delete[] out_pixels;
00135       delete image;
00136       return 0;
00137     }
00138 
00139     delete image;
00140     return new SimpleImage(width, height, target_format, out_pixels);
00141   }
00142 
00143 
00144   namespace hidden {
00145 
00146     COR_EXPORT(Image*) CorConvertImage(
00147       Image* image,
00148       PixelFormat target_format)
00149     {
00150       COR_GUARD("CorConvertImage");
00151 
00152       // if we don't have an image, user doesn't care about format, or
00153       // the formats match, don't do any conversion.
00154       if (!image ||
00155           target_format == PF_DONTCARE ||
00156           target_format == image->getFormat())
00157       {
00158         return image;
00159       }
00160 
00161       COR_LOG("Doing the conversion...");
00162 
00163       // if we have a palettized image, convert it to a direct color
00164       // image and then convert that
00165       if (IsPalettized(image->getFormat())) {
00166         image = ExpandPalette(image);
00167       }
00168 
00169       return DirectConversion(image, target_format);
00170     }
00171 
00172 
00173     COR_EXPORT(Image*) CorConvertPalette(
00174       Image* image,
00175       PixelFormat palette_format)
00176     {
00177       // do we need to convert?
00178       if (!image ||
00179           palette_format == PF_DONTCARE ||
00180           image->getPaletteFormat() == palette_format)
00181       {
00182         return image;
00183       }
00184 
00185       // do we have invalid data?
00186       if (!IsPalettized(image->getFormat()) ||
00187           !IsDirect(palette_format))
00188       {
00189         delete image;
00190         return 0;
00191       }
00192 
00193       const int width  = image->getWidth();
00194       const int height = image->getHeight();
00195       const PixelFormat format = image->getFormat();
00196       const int palette_size = image->getPaletteSize();
00197 
00198       // the palette indices don't change, so just make a copy
00199       const int image_size = width * height * GetPixelSize(format);
00200       byte* pixels = new byte[image_size];
00201       memcpy(pixels, image->getPixels(), image_size);
00202 
00203       byte* new_palette = new byte[
00204         palette_size * GetPixelSize(palette_format)];
00205 
00206       if (!ConvertPixels(new_palette, palette_format,
00207                          (byte*)image->getPalette(), image->getPaletteFormat(),
00208                          palette_size))
00209       {
00210         delete image;
00211         delete[] pixels;
00212         delete[] new_palette;
00213         return 0;
00214       }
00215 
00216       delete image;
00217       return new SimpleImage(
00218         width, height, format, pixels,
00219         new_palette, palette_size, palette_format);
00220     }
00221 
00222     COR_EXPORT(Image*) CorFlipImage(
00223       Image* image,
00224       int coordinate_axis)
00225     {
00226       COR_GUARD("CorFlipImage");
00227 
00228       // if we don't have an image, don't flip.
00229       if (!image) {
00230         return 0;
00231       }
00232 
00233       COR_LOG("Doing the flip...");
00234 
00235       const int width                = image->getWidth();
00236       const int height               = image->getHeight();
00237       byte* pixels                   = (byte*)image->getPixels();
00238       const PixelFormat pixel_format = image->getFormat();
00239       const int pixel_size           = GetPixelSize(pixel_format);
00240 
00241       // flip about the X axis
00242       if (coordinate_axis & CA_X) {
00243 
00244         byte* row = new byte[width * pixel_size];
00245         for (int h = 0; h < height / 2; ++h) {
00246           byte* top = pixels + h                * width * pixel_size;
00247           byte* bot = pixels + (height - h - 1) * width * pixel_size;
00248           memcpy(row, top, width * pixel_size);
00249           memcpy(top, bot, width * pixel_size);
00250           memcpy(bot, row, width * pixel_size);
00251         }
00252         delete[] row;
00253 
00254       }
00255 
00256       // flip about the Y axis
00257       if (coordinate_axis & CA_Y) {
00258 
00259         for (int h = 0; h < height; ++h) {
00260           byte* row = pixels + h * width * pixel_size;
00261           for (int w = 0; w < width / 2; ++w) {
00262             byte* left  = row + w               * pixel_size;
00263             byte* right = row + (width - w - 1) * pixel_size;
00264             for (int b = 0; b < pixel_size; ++b) {
00265               std::swap(left[b], right[b]);
00266             }
00267           }
00268         }
00269 
00270       }
00271 
00272       return image;
00273     }
00274   }
00275 
00276 }