4 using System.Collections.Generic;
 
    5 using System.Runtime.InteropServices;
 
    8 using SiliconStudio.Core;
 
    9 using SiliconStudio.Core.Diagnostics;
 
   10 using SiliconStudio.TextureConverter.Requests;
 
   12 using FreeImageAPI.Plugins;
 
   14 namespace SiliconStudio.TextureConverter.TexLibraries
 
   19     internal class FreeImageTextureLibraryData : ITextureLibraryData
 
   24         public FIBITMAP[] Bitmaps { 
get; set; }
 
   29         public IntPtr Data { 
get; set; }
 
   35     internal class FITexLib : ITexLibrary
 
   37         private static Logger Log = GlobalLogger.GetLogger(
"FITexLib");
 
   47         public void Dispose() {}
 
   49         public void Dispose(TexImage image)
 
   51             FreeImageTextureLibraryData libraryData = (FreeImageTextureLibraryData) image.LibraryData[
this];
 
   52             if (libraryData.Data != IntPtr.Zero) Marshal.FreeHGlobal(libraryData.Data);
 
   55         public void StartLibrary(TexImage image)
 
   57             if(Tools.IsCompressed(image.Format))
 
   59                 Log.Error(
"FreeImage can't process compressed texture.");
 
   60                 throw new TextureToolsException(
"FreeImage can't process compressed texture.");
 
   63             FreeImageTextureLibraryData libraryData = 
new FreeImageTextureLibraryData();
 
   64             image.LibraryData[
this] = libraryData;
 
   66             libraryData.Bitmaps = 
new FIBITMAP[image.SubImageArray.Length];
 
   67             uint bpp = Tools.GetBPP(image.Format);
 
   69             for (
int i = 0; i < image.SubImageArray.Length; ++i)
 
   71                 libraryData.Bitmaps[i] = FreeImage.ConvertFromRawBits(image.SubImageArray[i].Data, FREE_IMAGE_TYPE.FIT_BITMAP, image.SubImageArray[i].Width, image.SubImageArray[i].Height, image.SubImageArray[i].RowPitch, bpp, 0x00FF0000, 0x0000FF00, 0x000000FF, 
false);
 
   74             if (image.DisposingLibrary != null) image.DisposingLibrary.Dispose(image);
 
   76             image.DisposingLibrary = 
this;
 
   78             libraryData.Data = IntPtr.Zero;
 
   81         public void EndLibrary(TexImage image)
 
   83             if (!image.LibraryData.ContainsKey(
this)) 
return;
 
   84             FreeImageTextureLibraryData libraryData = (FreeImageTextureLibraryData)image.LibraryData[
this];
 
   86             IntPtr buffer = Marshal.AllocHGlobal(image.DataSize);
 
   88             int size, rowPitch, slicePitch;
 
   90             image.SubImageArray = 
new TexImage.SubImage[libraryData.Bitmaps.Length];
 
   94                 for (
int i = 0; i < libraryData.Bitmaps.Length; ++i)
 
   96                     image.SubImageArray[i].Width = (int)FreeImage.GetWidth(libraryData.Bitmaps[i]);
 
   97                     image.SubImageArray[i].Height = (int)FreeImage.GetHeight(libraryData.Bitmaps[i]);
 
   99                     Tools.ComputePitch(image.Format, image.SubImageArray[i].Width, image.SubImageArray[i].Height, out rowPitch, out slicePitch);
 
  102                     image.SubImageArray[i].Data = 
new IntPtr(buffer.ToInt64() + offset);
 
  103                     image.SubImageArray[i].DataSize = 
size;
 
  104                     image.SubImageArray[i].RowPitch = rowPitch;
 
  105                     image.SubImageArray[i].SlicePitch = slicePitch;
 
  107                     Utilities.CopyMemory(image.SubImageArray[i].Data, FreeImage.GetBits(libraryData.Bitmaps[i]), size);
 
  111             catch (AccessViolationException e)
 
  113                 Log.Error(
"Failed to convert FreeImage native data to TexImage texture. ", e);
 
  114                 throw new TextureToolsException(
"Failed to convert FreeImage native data to TexImage texture. ", e);
 
  117             image.Data = image.SubImageArray[0].Data;
 
  118             libraryData.Data = image.Data;
 
  121             for (
int i = 0; i < libraryData.Bitmaps.Length; ++i)
 
  123                 FreeImage.Unload(libraryData.Bitmaps[i]);
 
  126             libraryData.Bitmaps = null;
 
  127             image.DisposingLibrary = 
this;
 
  130         public bool CanHandleRequest(TexImage image, IRequest request)
 
  132             switch (request.Type)
 
  134                 case RequestType.Loading:
 
  136                         LoadingRequest loader = (LoadingRequest)request;
 
  138                         return format != FREE_IMAGE_FORMAT.FIF_UNKNOWN && format != FREE_IMAGE_FORMAT.FIF_DDS; 
 
  140                 case RequestType.Export:
 
  142                         ExportRequest export = (ExportRequest)request;
 
  144                         return format != FREE_IMAGE_FORMAT.FIF_UNKNOWN && format != FREE_IMAGE_FORMAT.FIF_DDS;
 
  146                 case RequestType.Rescaling:
 
  147                     RescalingRequest rescale = (RescalingRequest)request;
 
  148                     return rescale.Filter != Filter.Rescaling.Nearest;
 
  150                 case RequestType.SwitchingChannels:
 
  151                 case RequestType.GammaCorrection:
 
  152                 case RequestType.Flipping:
 
  153                 case RequestType.FlippingSub:
 
  154                 case RequestType.Swapping:
 
  161         public void Execute(TexImage image, IRequest request)
 
  163             FreeImageTextureLibraryData libraryData = image.LibraryData.ContainsKey(
this) ? (FreeImageTextureLibraryData)image.LibraryData[this] : null;
 
  167                 case RequestType.Loading:
 
  168                     Load(image, libraryData, (LoadingRequest)request);
 
  171                 case RequestType.Rescaling:
 
  172                     Rescale(image, libraryData, (RescalingRequest)request);
 
  175                 case RequestType.SwitchingChannels:
 
  176                     SwitchChannels(image, libraryData, (SwitchingBRChannelsRequest)request);
 
  179                 case RequestType.Flipping:
 
  180                     Flip(image, libraryData, (FlippingRequest)request);
 
  183                 case RequestType.FlippingSub:
 
  184                     FlipSub(image, libraryData, (FlippingSubRequest)request);
 
  187                 case RequestType.Swapping:
 
  188                     Swap(image, libraryData, (SwappingRequest)request);
 
  191                 case RequestType.Export:
 
  192                     Export(image, libraryData, (ExportRequest)request);
 
  195                 case RequestType.GammaCorrection:
 
  196                     CorrectGamma(image, libraryData, (GammaCorrectionRequest)request);
 
  200                     Log.Error(
"FITexLib (FreeImage) can't handle this request: " + request.Type);
 
  201                     throw new TextureToolsException(
"FITexLib (FreeImage) can't handle this request: " + request.Type);
 
  213         private void Load(TexImage image, FreeImageTextureLibraryData libraryData, LoadingRequest loader)
 
  215             Log.Info(
"Loading " + loader.FilePath + 
" ...");
 
  220                 temp = FreeImage.LoadEx(loader.FilePath);
 
  221                 FreeImage.FlipVertical(temp);
 
  224                     throw new Exception(
"FreeImage's image data is null");
 
  228                 Log.Error(
"Loading file " + loader.FilePath + 
" failed: " + e.Message);
 
  229                 throw new TextureToolsException(
"Loading file " + loader.FilePath + 
" failed: " + e.Message);
 
  233             libraryData = 
new FreeImageTextureLibraryData { Bitmaps = 
new FIBITMAP[1] { FreeImage.ConvertTo32Bits(temp) } };
 
  234             image.LibraryData[
this] = libraryData;
 
  236             FreeImage.Unload(temp);
 
  238             image.Data = FreeImage.GetBits(libraryData.Bitmaps[0]);
 
  239             image.Width = (int)FreeImage.GetWidth(libraryData.Bitmaps[0]);
 
  240             image.Height = (int)FreeImage.GetHeight(libraryData.Bitmaps[0]);
 
  242             image.Dimension = image.Height == 1 ? TexImage.TextureDimension.Texture1D : TexImage.TextureDimension.Texture2D;
 
  243             image.Format = SiliconStudio.Paradox.Graphics.PixelFormat.B8G8R8A8_UNorm;
 
  245             int rowPitch, slicePitch;
 
  246             Tools.ComputePitch(image.Format, image.Width, image.Height, out rowPitch, out slicePitch);
 
  247             image.RowPitch = rowPitch;
 
  248             image.SlicePitch = slicePitch;
 
  251             image.SubImageArray[0].Data = image.Data;
 
  252             image.SubImageArray[0].DataSize = image.DataSize;
 
  253             image.SubImageArray[0].Width = image.Width;
 
  254             image.SubImageArray[0].Height = image.Height;
 
  255             image.SubImageArray[0].RowPitch = rowPitch;
 
  256             image.SubImageArray[0].SlicePitch = slicePitch;
 
  257             image.DataSize = (int) (FreeImage.GetDIBSize(libraryData.Bitmaps[0]) - GetHeaderSize()); 
 
  258             libraryData.Data = IntPtr.Zero;
 
  259             image.DisposingLibrary = 
this;
 
  266         private unsafe uint GetHeaderSize()
 
  281         private void Rescale(TexImage image, FreeImageTextureLibraryData libraryData, RescalingRequest rescale)
 
  283             int width = rescale.ComputeWidth(image);
 
  284             int height = rescale.ComputeHeight(image);
 
  286             Log.Info(
"Rescaling image to " + width + 
"x" + height + 
" with " + rescale.Filter + 
" ...");
 
  290             if (image.Dimension == TexImage.TextureDimension.Texture3D) 
 
  292                 newTab = 
new FIBITMAP[image.ArraySize * image.FaceCount * image.Depth];
 
  295                 int nbSubImageWithMipMapPerArrayMemeber = 0; 
 
  296                 curDepth = image.Depth;
 
  297                 for (
int i = 0; i < image.MipmapCount; ++i)
 
  299                     nbSubImageWithMipMapPerArrayMemeber += curDepth;
 
  300                     curDepth = curDepth > 1 ? curDepth >>= 1 : curDepth;
 
  304                 for (
int j = 0; j < image.ArraySize; ++j)
 
  306                     for (
int i = 0; i < image.Depth; ++i)
 
  308                         newTab[ct] = FreeImage.Rescale(libraryData.Bitmaps[i + j * nbSubImageWithMipMapPerArrayMemeber], width, height, (
FREE_IMAGE_FILTER)rescale.Filter);
 
  315                 newTab = 
new FIBITMAP[image.ArraySize];
 
  317                 for (
int i = 0; i < libraryData.Bitmaps.Length; i += image.MipmapCount)
 
  319                     newTab[ct] = FreeImage.Rescale(libraryData.Bitmaps[i], width, height, (
FREE_IMAGE_FILTER)rescale.Filter);
 
  324             for (
int i = 0; i < libraryData.Bitmaps.Length; ++i)
 
  326                 FreeImage.Unload(libraryData.Bitmaps[i]);
 
  329             libraryData.Bitmaps = newTab;
 
  330             image.Data = FreeImage.GetBits(newTab[0]);
 
  333             image.Rescale(width, height);
 
  335             int rowPitch, slicePitch;
 
  336             Tools.ComputePitch(image.Format, width, height, out rowPitch, out slicePitch);
 
  338             image.RowPitch = rowPitch;
 
  339             image.SlicePitch = slicePitch;
 
  340             image.MipmapCount = 1;
 
  341             image.DataSize = image.SlicePitch * image.ArraySize * image.FaceCount * image.Depth;
 
  354         private void SwitchChannels(TexImage image, FreeImageTextureLibraryData libraryData, SwitchingBRChannelsRequest switchC)
 
  357             Log.Info(
"Switching channels R and G ...");
 
  359             for (
int i = 0; i < libraryData.Bitmaps.Length; ++i)
 
  361                 FIBITMAP blueChannel = FreeImage.GetChannel(libraryData.Bitmaps[i], FREE_IMAGE_COLOR_CHANNEL.FICC_BLUE);
 
  362                 FIBITMAP redChannel = FreeImage.GetChannel(libraryData.Bitmaps[i], FREE_IMAGE_COLOR_CHANNEL.FICC_RED);
 
  363                 FreeImage.SetChannel(libraryData.Bitmaps[i], redChannel, FREE_IMAGE_COLOR_CHANNEL.FICC_BLUE);
 
  364                 FreeImage.SetChannel(libraryData.Bitmaps[i], blueChannel, FREE_IMAGE_COLOR_CHANNEL.FICC_RED);
 
  365                 FreeImage.Unload(blueChannel);
 
  366                 FreeImage.Unload(redChannel);
 
  369             if (Tools.IsInBGRAOrder(image.Format))
 
  370                 image.Format = SiliconStudio.Paradox.Graphics.PixelFormat.R8G8B8A8_UNorm;
 
  372                 image.Format = SiliconStudio.Paradox.Graphics.PixelFormat.B8G8R8A8_UNorm;
 
  375         public bool SupportBGRAOrder()
 
  387         private void Flip(TexImage image, FreeImageTextureLibraryData libraryData, FlippingRequest flip)
 
  389             Log.Info(
"Flipping image : " + flip.Flip + 
" ...");
 
  391             for (
int i = 0; i < libraryData.Bitmaps.Length; ++i)
 
  395                     case Orientation.Vertical:
 
  396                         FreeImage.FlipVertical(libraryData.Bitmaps[i]);
 
  399                     case Orientation.Horizontal:
 
  400                         FreeImage.FlipHorizontal(libraryData.Bitmaps[i]);
 
  405             image.Flip(flip.Flip);
 
  415         private void FlipSub(TexImage image, FreeImageTextureLibraryData libraryData, FlippingSubRequest flipSub)
 
  417             Log.Info(
"Flipping image : sub-image " + flipSub.SubImageIndex + 
" " + flipSub.Flip + 
" ...");
 
  419             if (flipSub.SubImageIndex >= 0 && flipSub.SubImageIndex < libraryData.Bitmaps.Length)
 
  421                 switch (flipSub.Flip)
 
  423                     case Orientation.Vertical:
 
  424                         FreeImage.FlipVertical(libraryData.Bitmaps[flipSub.SubImageIndex]);
 
  427                     case Orientation.Horizontal:
 
  428                         FreeImage.FlipHorizontal(libraryData.Bitmaps[flipSub.SubImageIndex]);
 
  434                 Log.Warning(
"Cannot flip the sub-image " + flipSub.SubImageIndex + 
" because there is only " + libraryData.Bitmaps.Length + 
" sub-images.");
 
  447         private void Swap(TexImage image, FreeImageTextureLibraryData libraryData, SwappingRequest swap)
 
  449             Log.Info(
"Swapping image : sub-image " + swap.FirstSubImageIndex + 
" and " + swap.SecondSubImageIndex + 
" ...");
 
  451             if (swap.FirstSubImageIndex >= 0 && swap.FirstSubImageIndex < libraryData.Bitmaps.Length
 
  452                 && swap.SecondSubImageIndex >= 0 && swap.SecondSubImageIndex < libraryData.Bitmaps.Length)
 
  455                 var firstImage = FreeImage.Copy(libraryData.Bitmaps[swap.FirstSubImageIndex], 0, 0, image.Width, image.Height);
 
  456                 FreeImage.Paste(libraryData.Bitmaps[swap.FirstSubImageIndex], libraryData.Bitmaps[swap.SecondSubImageIndex], 0, 0, 256);
 
  457                 FreeImage.Paste(libraryData.Bitmaps[swap.SecondSubImageIndex], firstImage, 0, 0, 256);
 
  463                 Log.Warning(
"Cannot swap the sub-images " + swap.FirstSubImageIndex + 
" and " + swap.SecondSubImageIndex + 
" because there is only " + libraryData.Bitmaps.Length + 
" sub-images.");
 
  482         private void Export(TexImage image, FreeImageTextureLibraryData libraryData, ExportRequest request)
 
  484             String directory = Path.GetDirectoryName(request.FilePath);
 
  485             String fileName = Path.GetFileNameWithoutExtension(request.FilePath);
 
  486             String extension = Path.GetExtension(request.FilePath);
 
  489             if (image.Dimension == TexImage.TextureDimension.Texture3D)
 
  491                 Log.Error(
"Not implemented.");
 
  492                 throw new TextureToolsException(
"Not implemented.");
 
  495             if(!Tools.IsInBGRAOrder(image.Format))
 
  497                 SwitchChannels(image, libraryData, 
new SwitchingBRChannelsRequest());
 
  500             if (image.SubImageArray.Length > 1 && request.MinimumMipMapSize < FreeImage.GetWidth(libraryData.Bitmaps[0]) && request.MinimumMipMapSize < FreeImage.GetHeight(libraryData.Bitmaps[0]))
 
  503                 for (
int i = 0; i < image.ArraySize; ++i)
 
  505                     for (
int j = 0; j < image.MipmapCount; ++j)
 
  507                         if (FreeImage.GetWidth(libraryData.Bitmaps[imageCount]) < request.MinimumMipMapSize || FreeImage.GetHeight(libraryData.Bitmaps[imageCount]) < request.MinimumMipMapSize)
 
  510                         finalName = directory + 
"/" + fileName + 
"-ind_" + i + 
"-mip_" + j + extension;
 
  511                         FreeImage.FlipVertical(libraryData.Bitmaps[imageCount]);
 
  512                         if (!FreeImage.SaveEx(libraryData.Bitmaps[imageCount], finalName))
 
  514                             Log.Error(
"Export failure.");
 
  515                             throw new TextureToolsException(
"Export failure.");
 
  517                         FreeImage.FlipVertical(libraryData.Bitmaps[imageCount]);
 
  518                         Log.Info(
"Exporting image to " + finalName + 
" ...");
 
  525                 FreeImage.FlipVertical(libraryData.Bitmaps[0]);
 
  526                 if (!FreeImage.SaveEx(libraryData.Bitmaps[0], request.FilePath))
 
  528                     Log.Error(
"Export failure.");
 
  529                     throw new TextureToolsException(
"Export failure.");
 
  531                 FreeImage.FlipVertical(libraryData.Bitmaps[0]);
 
  532                 Log.Info(
"Exporting image to " + request.FilePath + 
" ...");
 
  535             image.Save(request.FilePath);
 
  545         public void CorrectGamma(TexImage image, FreeImageTextureLibraryData libraryData, GammaCorrectionRequest request)
 
  547             Log.Info(
"Applying a gamma correction of " + request.Gamma + 
" ...");
 
  549             foreach (
FIBITMAP bitmap 
in libraryData.Bitmaps)
 
  551                 FreeImage.AdjustGamma(bitmap, request.Gamma);
 
The FIBITMAP structure is a handle to a FreeImage bimtap. 
 
Base implementation for ILogger. 
 
FREE_IMAGE_FILTER
Upsampling / downsampling filters. Constants used in FreeImage_Rescale. 
 
This structure contains information about the dimensions and color format of a device-independent bit...
 
_In_ size_t _In_ size_t _In_ DXGI_FORMAT format
 
FREE_IMAGE_FORMAT
I/O image format identifiers. 
 
_In_ size_t _In_ size_t size
 
Output message to log right away.