// File: crn_freeimage_image_utils.h
// See Copyright Notice and license at the end of inc/crnlib.h
// Note: This header file requires FreeImage/FreeImagePlus.

#include "crn_image_utils.h"

#include "freeImagePlus.h"

namespace crnlib
{
   namespace freeimage_image_utils
   {
      inline bool load_from_file(image_u8& dest, const wchar_t* pFilename, int fi_flag)
      {
         fipImage src_image;

         if (!src_image.loadU(pFilename, fi_flag))
            return false;
         
         const uint orig_bits_per_pixel = src_image.getBitsPerPixel();

         const FREE_IMAGE_COLOR_TYPE orig_color_type = src_image.getColorType();
         
         if (!src_image.convertTo32Bits())
            return false;

         if (src_image.getBitsPerPixel() != 32)
            return false;

         uint width = src_image.getWidth();
         uint height = src_image.getHeight();

         dest.resize(src_image.getWidth(), src_image.getHeight(), src_image.getWidth());

         color_quad_u8* pDst = dest.get_ptr();

         bool grayscale = true;
         bool has_alpha = false;
         for (uint y = 0; y < height; y++)
         {
            const BYTE* pSrc = src_image.getScanLine((WORD)(height - 1 - y));
            color_quad_u8* pD = pDst;

            for (uint x = width; x; x--)
            {
               color_quad_u8 c;
               c.r = pSrc[FI_RGBA_RED];
               c.g = pSrc[FI_RGBA_GREEN];
               c.b = pSrc[FI_RGBA_BLUE];
               c.a = pSrc[FI_RGBA_ALPHA];
               
               if (!c.is_grayscale())
                  grayscale = false;
               has_alpha |= (c.a < 255);

               pSrc += 4;
               *pD++ = c;
            }

            pDst += width;
         }

         dest.reset_comp_flags();
         
         if (grayscale)
            dest.set_grayscale(true);
         
         dest.set_component_valid(3, has_alpha || (orig_color_type == FIC_RGBALPHA) || (orig_bits_per_pixel == 32));

         return true;
      }
            
      const int cSaveLuma = -1;
      
      inline bool save_to_grayscale_file(const wchar_t* pFilename, const image_u8& src, int component, int fi_flag)
      {
         fipImage dst_image(FIT_BITMAP, (WORD)src.get_width(), (WORD)src.get_height(), 8);

         RGBQUAD* p = dst_image.getPalette();
         for (uint i = 0; i < dst_image.getPaletteSize(); i++)
         {
            p[i].rgbRed = (BYTE)i;
            p[i].rgbGreen = (BYTE)i;
            p[i].rgbBlue = (BYTE)i;
            p[i].rgbReserved = 255;
         }

         for (uint y = 0; y < src.get_height(); y++)
         {
            const color_quad_u8* pSrc = src.get_scanline(y);

            for (uint x = 0; x < src.get_width(); x++)
            {
               BYTE v;
               if (component == cSaveLuma)
                  v = (BYTE)(*pSrc).get_luma();
               else
                  v = (*pSrc)[component];
               dst_image.setPixelIndex(x, src.get_height() - 1 - y, &v);

               pSrc++;
            } 
         }

         if (!dst_image.saveU(pFilename, fi_flag))
            return false; 

         return true;
      }

      inline bool save_to_file(const wchar_t* pFilename, const image_u8& src, int fi_flag, bool ignore_alpha = false)
      {
         const bool save_alpha = src.is_component_valid(3);
         uint bpp = (save_alpha && !ignore_alpha) ? 32 : 24;
         
         if (bpp == 32)
         {
            dynamic_wstring ext(pFilename);
            get_extension(ext);

            if ((ext == L"jpg") || (ext == L"jpeg") || (ext == L"gif") || (ext == L"jp2"))
               bpp = 24;
         }
         
         if ((bpp == 24) && (src.is_grayscale()))
            return save_to_grayscale_file(pFilename, src, cSaveLuma, fi_flag);
                  
         fipImage dst_image(FIT_BITMAP, (WORD)src.get_width(), (WORD)src.get_height(), (WORD)bpp);

         for (uint y = 0; y < src.get_height(); y++)
         {
            for (uint x = 0; x < src.get_width(); x++)
            {
               color_quad_u8 c(src(x, y));

               RGBQUAD quad;
               quad.rgbRed = c.r;
               quad.rgbGreen = c.g;
               quad.rgbBlue = c.b;
               if (bpp == 32)
                  quad.rgbReserved = c.a;
               else
                  quad.rgbReserved = 255;

               dst_image.setPixelColor(x, src.get_height() - 1 - y, &quad);
            } 
         }

         if (!dst_image.saveU(pFilename, fi_flag))
            return false; 

         return true;
      }
   
   } // namespace freeimage_image_utils
   
} // namespace crnlib