private void compressCompositeNormalMap(String originalNormalMapSource, String source, String dest, MaterialDescription matDesc)
 {
     Task.WaitAll(
         saveUncompressed(source, dest, true, FREE_IMAGE_FILTER.FILTER_BILINEAR, new FullImageSizeStrategy(), (resized) =>
     {
         String fileName = String.Format("{0}_{1}{2}", Path.GetFileNameWithoutExtension(originalNormalMapSource), resized.Width, Path.GetExtension(originalNormalMapSource));
         fileName        = Path.Combine(Path.GetDirectoryName(originalNormalMapSource), fileName);
         if (File.Exists(fileName))
         {
             Log.Info("Using manually supplied resized normal map for {0} size {1}", dest, resized.Width);
             using (var image = FreeImageBitmap.FromFile(fileName))
             {
                 if (image.Width != resized.Width || image.Height != resized.Height)
                 {
                     throw new Exception(String.Format("Image {0} does not match expected size {1}x{1}. Please fix source image.", fileName, resized.Width));
                 }
                 combineImages(resized, Channel.Alpha, image, Channel.Red, image, Channel.Green, resized, Channel.Blue, resized);
             }
         }
         else
         {
             Log.Info("Using automatic resized normal map for {0} size {1}", dest, resized.Width);
         }
     })
         );
 }
Exemple #2
0
 public static bool HasDesktopImageFormat(string imagePath)
 {
     using (var img = FreeImageBitmap.FromFile(imagePath))
     {
         return(img.Width > img.Height && img.Width > 1900);
     }
 }
 public void FreeImageFileFile()
 {
     using var output  = TestFiles.OutputJpg();
     using var image   = FreeImageBitmap.FromFile(TestFiles.InputJpg);
     using var resized = new FreeImageBitmap(image, Width, Height);
     resized.Save(output.Path, FREE_IMAGE_FORMAT.FIF_JPEG, FREE_IMAGE_SAVE_FLAGS.JPEG_QUALITYGOOD);
 }
Exemple #4
0
 /// <summary>
 /// Compressing Image
 /// </summary>
 /// <param name="imagePath">Path to image</param>
 /// <param name="size">Size to compress</param>
 /// <returns>Compressing result</returns>
 public static bool CompressImage(string imagePath, int size)
 {
     try
     {
         //string newFile = imagePath.Replace(".jpg", ".new");
         using (var original = FreeImageBitmap.FromFile(imagePath + ".new"))
         {
             int width, height;
             if (original.Width > original.Height)
             {
                 width  = size;
                 height = original.Height * size / original.Width;
             }
             else
             {
                 width  = original.Width * size / original.Height;
                 height = size;
             }
             var resized = new FreeImageBitmap(original, width, height);
             // JPEG_QUALITYGOOD is 75 JPEG.
             // JPEG_BASELINE strips metadata (EXIF, etc.)
             resized.Save(imagePath + ".jpg", FREE_IMAGE_FORMAT.FIF_JPEG,
                          FREE_IMAGE_SAVE_FLAGS.JPEG_QUALITYGOOD |
                          FREE_IMAGE_SAVE_FLAGS.JPEG_BASELINE);
         }
         System.IO.File.Delete(imagePath + ".new");
         return(true);
     }
     catch (Exception ex)
     {
         return(false);
     }
 }
Exemple #5
0
 public static byte[] ImageToByteArray(string path, FREE_IMAGE_FORMAT format)
 {
     using (var image = FreeImageBitmap.FromFile(path))
     {
         using (var m = new MemoryStream())
         {
             image.Save(m, format);
             return(m.ToArray());
         }
     }
 }
Exemple #6
0
 public static byte[] ThumbNailByteArray(string path, FREE_IMAGE_FORMAT format)
 {
     using (var image = FreeImageBitmap.FromFile(path))
     {
         var newImage = image.GetThumbnailImage(1000, true);
         using (var m = new MemoryStream())
         {
             newImage.Save(m, format);
             return(m.ToArray());
         }
     }
 }
 internal static void FreeImageResize(string path, int size, string outputDirectory)
 {
     using (var original = FreeImageBitmap.FromFile(path))
     {
         var scaled  = ScaledSize(original.Width, original.Height, size);
         var resized = new FreeImageBitmap(original, scaled.width, scaled.height);
         // JPEG_QUALITYGOOD is 75 JPEG.
         // JPEG_BASELINE strips metadata (EXIF, etc.)
         resized.Save(OutputPath(path, outputDirectory, FreeImage), FREE_IMAGE_FORMAT.FIF_JPEG,
                      FREE_IMAGE_SAVE_FLAGS.JPEG_QUALITYGOOD |
                      FREE_IMAGE_SAVE_FLAGS.JPEG_BASELINE);
     }
 }
Exemple #8
0
 public void FreeImageResize(string input)
 {
     using (var original = FreeImageBitmap.FromFile(input))
     {
         var scaled  = ScaledSize(original.Width, original.Height, ThumbnailSize);
         var resized = new FreeImageBitmap(original, scaled.width, scaled.height);
         // JPEG_QUALITYGOOD is 75 JPEG.
         // JPEG_BASELINE strips metadata (EXIF, etc.)
         resized.Save(OutputPath(input, FreeImage), FREE_IMAGE_FORMAT.FIF_JPEG,
                      FREE_IMAGE_SAVE_FLAGS.JPEG_QUALITYGOOD |
                      FREE_IMAGE_SAVE_FLAGS.JPEG_BASELINE);
     }
 }
 private void combineSingleChannelMaps(String redSource, Channel redSourceChannel, String greenSource, Channel greenSourceChannel, String tempFile, String destinationFile, MaterialDescription matDesc, Action <String, String, MaterialDescription> compressFunction)
 {
     Log.Info("Building composite image with red source {0} and green source {1}", redSource, greenSource);
     using (FreeImageBitmap redMap = FreeImageBitmap.FromFile(redSource))
     {
         using (FreeImageBitmap greenMap = FreeImageBitmap.FromFile(greenSource))
         {
             using (FreeImageBitmap combined = createImageFromChannels(redMap, redSourceChannel, greenMap, greenSourceChannel))
             {
                 saveImage(combined, tempFile, TempFileImageFormat);
                 compressFunction(tempFile, destinationFile, matDesc);
                 deleteFile(tempFile);
             }
         }
     }
 }
 private void addMapToBlueAndCompress(String rgSource, String bSource, Channel bSourceChannel, String tempFile, String destinationFile, MaterialDescription matDesc, Action <String, String, MaterialDescription> compressFunction)
 {
     Log.Info("Building composite image with RG {0} and B {1}", rgSource, bSource);
     using (FreeImageBitmap rgMap = FreeImageBitmap.FromFile(rgSource))
     {
         using (FreeImageBitmap bMap = FreeImageBitmap.FromFile(bSource))
         {
             using (FreeImageBitmap combined = createImageFromChannels(rgMap, Channel.Red, rgMap, Channel.Green, bMap, bSourceChannel))
             {
                 saveImage(combined, tempFile, TempFileImageFormat);
                 compressFunction(tempFile, destinationFile, matDesc);
                 deleteFile(tempFile);
             }
         }
     }
 }
 private void addMapToAlphaAndCompress(String rgbSource, String alphaSource, Channel alphaSourceChannel, String tempFile, String destinationFile, MaterialDescription matDesc, Action <String, String, MaterialDescription> compressFunction)
 {
     Log.Info("Building composite image with RGB {0} and alpha {1}", rgbSource, alphaSource);
     using (FreeImageBitmap rgbMap = FreeImageBitmap.FromFile(rgbSource))
     {
         using (FreeImageBitmap alphaMap = FreeImageBitmap.FromFile(alphaSource))
         {
             using (FreeImageBitmap combined = createImageFromChannels(alphaMap, alphaSourceChannel, rgbMap))
             {
                 saveImage(combined, tempFile, TempFileImageFormat);
                 compressFunction(tempFile, destinationFile, matDesc);
                 deleteFile(tempFile);
             }
         }
     }
 }
        //private unsafe byte getColor(int x, int y, FreeImageBitmap src, Channel channel)
        //{
        //    int bpp = 4;
        //    if (src.PixelFormat == FreeImageAPI.PixelFormat.Format24bppRgb)
        //    {
        //        bpp = 3;
        //    }

        //    byte* pixel = (byte*)src.Bits.ToPointer();
        //    pixel += (src.Pitch * (src.Height - y - 1) + x) * bpp;
        //    switch (channel)
        //    {
        //        case Channel.Alpha:
        //            return pixel[3];
        //        case Channel.Red:
        //            return pixel[2];
        //        case Channel.Green:
        //            return pixel[1];
        //        case Channel.Blue:
        //            return pixel[0];
        //    }
        //    throw new NotSupportedException(); //Won't get here
        //}

        private async Task saveUncompressed(String sourceFile, String destFile, bool lossless, FREE_IMAGE_FILTER filter, ImagePageSizeStrategy pageSizeStrategy, Action <FreeImageBitmap> afterResize = null)
        {
            await Task.Run(() =>
            {
                if ((outputFormats & OutputFormats.Uncompressed) != 0)
                {
                    Log.Info("Creating paged data for {0}", sourceFile);
                    using (FreeImageBitmap source = FreeImageBitmap.FromFile(sourceFile))
                    {
                        using (var stream = File.Open(String.Format(PagedTextureNameFormat, destFile), FileMode.Create, FileAccess.ReadWrite))
                        {
                            PagedImage.fromBitmap(source, 128, 1, stream, PagedImage.ImageType.WEBP, maxSize, lossless, filter, pageSizeStrategy, afterResize);
                        }
                    }
                }
            });
        }
 internal static void FreeImageResize(string path, int size, string outputDirectory)
 {
     using (var original = FreeImageBitmap.FromFile(path))
     {
         int width, height;
         if (original.Width > original.Height)
         {
             width  = size;
             height = original.Height * size / original.Width;
         }
         else
         {
             width  = original.Width * size / original.Height;
             height = size;
         }
         var resized = new FreeImageBitmap(original, width, height);
         // JPEG_QUALITYGOOD is 75 JPEG.
         // JPEG_BASELINE strips metadata (EXIF, etc.)
         resized.Save(OutputPath(path, outputDirectory, FreeImage), FREE_IMAGE_FORMAT.FIF_JPEG,
                      FREE_IMAGE_SAVE_FLAGS.JPEG_QUALITYGOOD |
                      FREE_IMAGE_SAVE_FLAGS.JPEG_BASELINE);
     }
 }
        private void writeSimpleDiffuseSprite(MaterialDescription description, MaterialRepository repo)
        {
            String diffuseSrc = getSourceFullPath(description.DiffuseMapName);

            if (!imageNeedsCompression(diffuseSrc))
            {
                return;
            }

            String diffuseDest = getDestBasePath(description.DiffuseMapName);

            String normalDest = getDestBasePath(description.NormalMapName);
            String normalTmp  = getTempPath(description.NormalMapName);

            using (FreeImageBitmap diffuseMap = FreeImageBitmap.FromFile(diffuseSrc))
            {
                using (FreeImageBitmap normalMap = new FreeImageBitmap(diffuseMap.Width, diffuseMap.Height, FreeImageAPI.PixelFormat.Format32bppArgb))
                {
                    normalMap.FillBackground(new RGBQUAD(new FreeImageAPI.Color()
                    {
                        R = 0x80,
                        G = 0x80,
                        B = 0,
                        A = 255
                    }));
                    using (FreeImageBitmap combined = createImageFromChannels(normalMap, Channel.Red, normalMap, Channel.Green, diffuseMap, Channel.Alpha))
                    {
                        saveImage(combined, normalTmp, TempFileImageFormat);
                        compressCompositeNormalMap(diffuseSrc, normalTmp, normalDest, description);
                        deleteFile(normalTmp);
                    }
                }
            }

            Log.Info("Compressing diffuse map {0} directly", description.DiffuseMapName);
            compressDiffuseMap(diffuseSrc, diffuseDest, description);
        }
Exemple #15
0
        public static void Thumbnail(string path, string outpath)
        {
            const int size = 150;

            using (var original = FreeImageBitmap.FromFile(path))
            {
                int width, height;
                if (original.Width > original.Height)
                {
                    width  = size;
                    height = original.Height * size / original.Width;
                }
                else
                {
                    width  = original.Width * size / original.Height;
                    height = size;
                }
                var resized = new FreeImageBitmap(original, width, height);
                // JPEG_QUALITYGOOD is 75 JPEG.
                // JPEG_BASELINE strips metadata (EXIF, etc.)
                //resized.Save()
                resized.Save(outpath);
            }
        }
Exemple #16
0
        public new IFileInfo GetFileInfo(string subpath)
        {
            var fileInfo = base.GetFileInfo(subpath);

            if (fileInfo.Exists)
            {
                return(fileInfo);
            }


            var matchResult = _options.IsMatch(subpath, _options.PathMatch);

            if (!matchResult.Result)
            {
                return(fileInfo);
            }

            var imageHandleDto = matchResult.Data;

            //生成文件
            fileInfo = base.GetFileInfo($"{imageHandleDto.ImagePath}{imageHandleDto.ImageName}.{imageHandleDto.ImageExtensions}");
            if (!fileInfo.Exists)
            {
                return(fileInfo);
            }

            var newImagePath = Path.Join(Root.Replace("\\", "/"), subpath).Replace("//", "/");

            //_stopwatch.Start();

            //var settings = new ProcessImageSettings()
            //{
            //    Width = imageHandleDto.ImageWidth,
            //    Height = imageHandleDto.ImageHeight,
            //    ResizeMode = CropScaleMode.Max,
            //    SaveFormat = FileFormat.Jpeg,
            //    JpegQuality = 75,
            //    JpegSubsampleMode = ChromaSubsampleMode.Subsample420
            //};


            //using (var output = new FileStream(newImagePath, FileMode.Create))
            //{
            //    MagicImageProcessor.ProcessImage(fileInfo.PhysicalPath, output, settings);
            //}

            //_stopwatch.Stop();
            //_logger.LogDebug($"Magick.NET耗时{_stopwatch.ElapsedMilliseconds}ms");

            //File.Delete(newImagePath);


            //_stopwatch.Restart();
            //using (var original = FreeImageBitmap.FromFile(fileInfo.PhysicalPath))
            //{
            //    using (var resized = new FreeImageBitmap(original, imageHandleDto.ImageWidth, imageHandleDto.ImageHeight))
            //    {

            //        resized.Save(newImagePath, FREE_IMAGE_FORMAT.FIF_JPEG,
            //        FREE_IMAGE_SAVE_FLAGS.JPEG_QUALITYGOOD |
            //        FREE_IMAGE_SAVE_FLAGS.JPEG_BASELINE);
            //    }
            //}

            //_stopwatch.Stop();
            //_logger.LogDebug($"FreeImage FromFilePath耗时{_stopwatch.ElapsedMilliseconds}ms");

            //File.Delete(newImagePath);

            //_stopwatch.Restart();
            //using (var original = FreeImageBitmap.FromStream(fileInfo.CreateReadStream()))
            //{
            //    using (var resized = new FreeImageBitmap(original, imageHandleDto.ImageWidth, imageHandleDto.ImageHeight))
            //    {

            //        resized.Save(newImagePath, FREE_IMAGE_FORMAT.FIF_JPEG,
            //        FREE_IMAGE_SAVE_FLAGS.JPEG_QUALITYGOOD |
            //        FREE_IMAGE_SAVE_FLAGS.JPEG_BASELINE);
            //    }
            //}

            //_stopwatch.Stop();
            //_logger.LogDebug($"FreeImage FromFileStream耗时{_stopwatch.ElapsedMilliseconds}ms");


            _stopwatch.Start();


            FREE_IMAGE_FORMAT imageFormat = 0;

            switch (imageHandleDto.ImageExtensions.ToLower())
            {
            case "jpg":
            case "jpeg": imageFormat = FREE_IMAGE_FORMAT.FIF_JPEG; break;

            case "png": imageFormat = FREE_IMAGE_FORMAT.FIF_PNG; break;

            case "gif": imageFormat = FREE_IMAGE_FORMAT.FIF_GIF; break;

            case "ico": imageFormat = FREE_IMAGE_FORMAT.FIF_ICO; break;

            default: imageFormat = FREE_IMAGE_FORMAT.FIF_UNKNOWN; break;
            }



            using (var original = FreeImageBitmap.FromFile(fileInfo.PhysicalPath))
            {
                var size = original.Width / (double)imageHandleDto.ImageWidth;
                if ((imageHandleDto.ImageHeight * size) > original.Height)
                {
                    size = original.Height / (double)imageHandleDto.ImageHeight;
                }

                var width  = original.Width / size;
                var height = original.Height / size;
                width  = width > original.Width ? original.Width : width;
                height = height > original.Height ? original.Height : height;

                using (var resized = original.GetScaledInstance((int)width, (int)height, FREE_IMAGE_FILTER.FILTER_BICUBIC))
                {
                    double left, top, right, bottom;


                    var halfWidth  = Math.Floor(Convert.ToDouble(imageHandleDto.ImageWidth / 2));
                    var halfHeight = Math.Floor(Convert.ToDouble(imageHandleDto.ImageHeight / 2));
                    var centerX    = Math.Round(width / 2);
                    var centerY    = Math.Round(height / 2);

                    if (resized.Width > imageHandleDto.ImageWidth)
                    {
                        left  = centerX - halfWidth;
                        right = centerX + halfWidth;
                    }
                    else
                    {
                        left  = 0;
                        right = resized.Width;
                    }

                    if (resized.Height > imageHandleDto.ImageHeight)
                    {
                        bottom = centerY - halfHeight;
                        top    = centerY + halfHeight;
                    }
                    else
                    {
                        bottom = 0;
                        top    = resized.Height;
                    }

                    using (var crop = resized.Copy((int)left, (int)top, (int)right, (int)bottom))
                    {
                        //, FREE_IMAGE_FORMAT.FIF_JPEG, FREE_IMAGE_SAVE_FLAGS.JPEG_QUALITYGOOD | FREE_IMAGE_SAVE_FLAGS.JPEG_BASELINE
                        crop.Save(newImagePath, imageFormat, FREE_IMAGE_SAVE_FLAGS.DEFAULT);
                    }
                }
            }

            _stopwatch.Stop();
            _logger.LogDebug($"FreeImage FromFilePath耗时{_stopwatch.ElapsedMilliseconds}ms");



            fileInfo = base.GetFileInfo(subpath);
            return(fileInfo);
        }
        public new IFileInfo GetFileInfo(string subpath)
        {
            var fileInfo = base.GetFileInfo(subpath);

            if (fileInfo.Exists)
            {
                return(fileInfo);
            }


            var matchResult = _options.IsMatch(subpath, _options.PathMatch);

            if (!matchResult.Result)
            {
                return(fileInfo);
            }

            var imageHandleDto = matchResult.Data;

            //生成文件
            fileInfo = base.GetFileInfo($"{imageHandleDto.ImagePath}{imageHandleDto.ImageName}.{imageHandleDto.ImageExtensions}");
            if (!fileInfo.Exists)
            {
                return(fileInfo);
            }

            var newImagePath = Path.Join(Root.Replace("\\", "/"), subpath).Replace("//", "/");

            //_stopwatch.Start();

            //var settings = new ProcessImageSettings()
            //{
            //    Width = imageHandleDto.ImageWidth,
            //    Height = imageHandleDto.ImageHeight,
            //    ResizeMode = CropScaleMode.Max,
            //    SaveFormat = FileFormat.Jpeg,
            //    JpegQuality = 75,
            //    JpegSubsampleMode = ChromaSubsampleMode.Subsample420
            //};


            //using (var output = new FileStream(newImagePath, FileMode.Create))
            //{
            //    MagicImageProcessor.ProcessImage(fileInfo.PhysicalPath, output, settings);
            //}

            //_stopwatch.Stop();
            //_logger.LogDebug($"Magick.NET耗时{_stopwatch.ElapsedMilliseconds}ms");

            //File.Delete(newImagePath);


            //_stopwatch.Restart();
            //using (var original = FreeImageBitmap.FromFile(fileInfo.PhysicalPath))
            //{
            //    using (var resized = new FreeImageBitmap(original, imageHandleDto.ImageWidth, imageHandleDto.ImageHeight))
            //    {

            //        resized.Save(newImagePath, FREE_IMAGE_FORMAT.FIF_JPEG,
            //        FREE_IMAGE_SAVE_FLAGS.JPEG_QUALITYGOOD |
            //        FREE_IMAGE_SAVE_FLAGS.JPEG_BASELINE);
            //    }
            //}

            //_stopwatch.Stop();
            //_logger.LogDebug($"FreeImage FromFilePath耗时{_stopwatch.ElapsedMilliseconds}ms");

            //File.Delete(newImagePath);

            //_stopwatch.Restart();
            //using (var original = FreeImageBitmap.FromStream(fileInfo.CreateReadStream()))
            //{
            //    using (var resized = new FreeImageBitmap(original, imageHandleDto.ImageWidth, imageHandleDto.ImageHeight))
            //    {

            //        resized.Save(newImagePath, FREE_IMAGE_FORMAT.FIF_JPEG,
            //        FREE_IMAGE_SAVE_FLAGS.JPEG_QUALITYGOOD |
            //        FREE_IMAGE_SAVE_FLAGS.JPEG_BASELINE);
            //    }
            //}

            //_stopwatch.Stop();
            //_logger.LogDebug($"FreeImage FromFileStream耗时{_stopwatch.ElapsedMilliseconds}ms");


            _stopwatch.Start();


            FREE_IMAGE_FORMAT imageFormat = 0;

            switch (imageHandleDto.ImageExtensions.ToLower())
            {
            case "jpg":
            case "jpeg": imageFormat = FREE_IMAGE_FORMAT.FIF_JPEG; break;

            case "png": imageFormat = FREE_IMAGE_FORMAT.FIF_PNG; break;

            case "gif": imageFormat = FREE_IMAGE_FORMAT.FIF_GIF; break;

            case "ico": imageFormat = FREE_IMAGE_FORMAT.FIF_ICO; break;

            default: imageFormat = FREE_IMAGE_FORMAT.FIF_UNKNOWN; break;
            }



            using (var original = FreeImageBitmap.FromFile(fileInfo.PhysicalPath))
            {
                int x      = 0;
                int y      = 0;
                int width  = original.Width;
                int height = original.Height;

                if ((double)original.Width / (double)original.Height > (double)imageHandleDto.ImageWidth / (double)imageHandleDto.ImageHeight)
                {
                    height = original.Height;
                    width  = original.Height * imageHandleDto.ImageWidth / imageHandleDto.ImageHeight;
                    y      = 0;
                    x      = (original.Width - width) / 2;
                }
                else
                {
                    width  = original.Width;
                    height = original.Width * imageHandleDto.ImageHeight / imageHandleDto.ImageWidth;
                    x      = 0;
                    y      = (original.Height - height) / 2;
                }

                int left = x, top = y + height, right = x + width, bottom = y;

                using (var crop = original.Copy(left, top, right, bottom))
                {
                    using (var resized = crop.GetScaledInstance(imageHandleDto.ImageWidth, imageHandleDto.ImageHeight, FREE_IMAGE_FILTER.FILTER_BICUBIC))
                    {
                        //, FREE_IMAGE_FORMAT.FIF_JPEG, FREE_IMAGE_SAVE_FLAGS.JPEG_QUALITYGOOD | FREE_IMAGE_SAVE_FLAGS.JPEG_BASELINE
                        resized.Save(newImagePath, imageFormat, FREE_IMAGE_SAVE_FLAGS.DEFAULT);
                    }
                }
            }

            _stopwatch.Stop();
            _logger.LogDebug($"FreeImage FromFilePath耗时{_stopwatch.ElapsedMilliseconds}ms");



            fileInfo = base.GetFileInfo(subpath);
            return(fileInfo);
        }
        /// <summary>
        /// Compile input images into WAD texture file.
        /// </summary>
        /// <param name="outputFilename">Output wad file path.</param>
        /// <param name="images">Input image files.</param>
        /// <param name="names">Names of textures.</param>
        /// <param name="reserverLastPalColor">Reserve last color in palette if name starts with {.</param>
        public static void CreateWad(string outputFilename, string[] images, string[] names, bool reserverLastPalColor = false)
        {
            using (FileStream fs = new FileStream(outputFilename, FileMode.Create))
                using (BinaryWriter bw = new BinaryWriter(fs))
                {
                    //Convert bitmaps to 8bpp format
                    List <FreeImageBitmap> imgs = new List <FreeImageBitmap>();
                    for (int i = 0; i < images.Length; i++)
                    {
                        string image = images[i];

                        //Quantize images
                        FreeImageBitmap originalImage = FreeImageBitmap.FromFile(image);

                        //If texture will be transparent, reserve last color if enabled
                        bool reserveLastClr = (names[i].StartsWith("{") && reserverLastPalColor);
                        int  r = reserveLastClr ? 1 : 0;
                        originalImage.Quantize(FREE_IMAGE_QUANTIZE.FIQ_NNQUANT, MaxPaletteColors - r);
                        originalImage.ConvertColorDepth(FREE_IMAGE_COLOR_DEPTH.FICD_08_BPP);

                        if (reserveLastClr)
                        {
                            originalImage.Palette[MaxPaletteColors - 1] = new RGBQUAD(Color.Blue);
                        }

                        //TODO: Transparent png, originalImage.SwapColors(, Color.Blue, true);
                        imgs.Add(originalImage);
                    }
                    uint[] offsets = new uint[images.Length];
                    uint[] sizes   = new uint[images.Length];

                    //WAD header
                    bw.Write(WadHeaderId);
                    bw.Write(images.Length);
                    bw.Write(0); //This will be changed later

                    //Write textures
                    for (int i = 0; i < images.Length; i++)
                    {
                        uint posTextureStart = (uint)bw.BaseStream.Position;
                        offsets[i] = posTextureStart;
                        //Texture name
                        byte[] name = CreateTextureName(names[i]);
                        bw.Write(name, 0, name.Length);

                        //Texture dimensions
                        bw.Write(imgs[i].Width);
                        bw.Write(imgs[i].Height);

                        //Offsets
                        uint posImage = (uint)(bw.BaseStream.Position - posTextureStart);
                        bw.Write(posImage + 16); //image
                        int pixelSize = ((imgs[i].Width) * (imgs[i].Height));
                        int m1        = ((imgs[i].Width / 2) * (imgs[i].Height / 2));
                        int m2        = ((imgs[i].Width / 4) * (imgs[i].Height / 4));
                        int m3        = ((imgs[i].Width / 8) * (imgs[i].Height / 8));
                        bw.Write((uint)(posImage + pixelSize + 16));           //mipmap1
                        bw.Write((uint)(posImage + pixelSize + m1 + 16));      //mipmap2
                        bw.Write((uint)(posImage + pixelSize + m1 + m2 + 16)); //mipmap3

                        //Write pixel data
                        imgs[i].RotateFlip(RotateFlipType.RotateNoneFlipX);
                        byte[] arr = new byte[imgs[i].Width * imgs[i].Height];
                        System.Runtime.InteropServices.Marshal.Copy(imgs[i].GetScanlinePointer(0), arr, 0, arr.Length);
                        Array.Reverse(arr);
                        bw.Write(arr);
                        //

                        //Mip map data
                        int factor = 2;
                        for (int a = 0; a < 3; a++)
                        {
                            int widthMM  = (imgs[i].Width / factor);
                            int heightMM = (imgs[i].Height / factor);


                            using (FreeImageBitmap clBmp = imgs[i].GetScaledInstance(widthMM, heightMM, FREE_IMAGE_FILTER.FILTER_LANCZOS3))
                            {
                                //TODO: opravit png, priesvitnost
                                clBmp.Quantize(FREE_IMAGE_QUANTIZE.FIQ_NNQUANT, MaxPaletteColors, imgs[i].Palette);
                                byte[] arrMM = new byte[widthMM * heightMM];
                                System.Runtime.InteropServices.Marshal.Copy(clBmp.GetScanlinePointer(0), arrMM, 0, arrMM.Length);
                                Array.Reverse(arrMM);
                                bw.Write(arrMM);
                            }
                            factor *= 2;
                        }

                        //Unknown 2 bytes
                        bw.Write(new byte[] { 0x00, 0x01 });

                        //Write color palette
                        for (int p = 0; p < imgs[i].Palette.Length; p++)
                        {
                            bw.Write(imgs[i].Palette[p].rgbRed);
                            bw.Write(imgs[i].Palette[p].rgbGreen);
                            bw.Write(imgs[i].Palette[p].rgbBlue);
                        }

                        //Padding
                        bw.Write(new byte[] { 0x00, 0x00 });
                        sizes[i] = (uint)bw.BaseStream.Position - posTextureStart;
                    }

                    long posLumps = bw.BaseStream.Position;
                    bw.Seek(8, SeekOrigin.Begin);
                    bw.Write((uint)posLumps);
                    bw.Seek((int)posLumps, SeekOrigin.Begin);
                    //Write Lumps infos
                    for (int i = 0; i < images.Length; i++)
                    {
                        bw.Write(offsets[i]);
                        bw.Write(sizes[i]);
                        bw.Write(sizes[i]);
                        bw.Write((byte)0x43);
                        bw.Write((byte)0);
                        bw.Write(new byte[] { 0x00, 0x00 });
                        byte[] name = CreateTextureName(names[i]);
                        bw.Write(name, 0, name.Length);
                    }

                    //Free resources
                    for (int i = 0; i < imgs.Count; i++)
                    {
                        imgs[i].Dispose();
                    }
                }
        }