//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);
                        }
                    }
                }
            });
        }
Beispiel #2
0
        /// <summary>
        /// Create a paged image from a FreeImageBitmap instance, note that this function is destructive
        /// to the passed in FreeImageBitmap since it will resize it while creating all the mip levels
        /// for the paged image. However, you will still need to dispose the image you pass in, this class
        /// makes a copy while destroying the image, but does not take ownership of the original.
        /// </summary>
        /// <param name="image">The image to extract pages from.</param>
        /// <param name="pageSize">The size of the pages to extract.</param>
        public static void fromBitmap(FreeImageBitmap image, int pageSize, int padding, Stream stream, ImageType imageType, int maxSize, bool lossless, FREE_IMAGE_FILTER filter, ImagePageSizeStrategy pageSizeStrategy, Action <FreeImageBitmap> afterResize = null)
        {
            stream.Seek(HeaderSize, SeekOrigin.Begin); //Leave some space for the header

            if (image.Width > maxSize)
            {
                Logging.Log.Info("Image size {0} was too large, resizing to {1}", image.Width, maxSize);
                pageSizeStrategy.rescaleImage(image, new Size(maxSize, maxSize), filter);
            }

            PagedImage            pagedImage = new PagedImage();
            int                   padding2x  = padding * 2;
            FREE_IMAGE_FORMAT     outputFormat;
            FREE_IMAGE_SAVE_FLAGS saveFlags = FREE_IMAGE_SAVE_FLAGS.DEFAULT;

            switch (imageType)
            {
            default:
            case ImageType.PNG:
                outputFormat = FREE_IMAGE_FORMAT.FIF_PNG;
                break;

            case ImageType.WEBP:
                outputFormat = FREE_IMAGE_FORMAT.FIF_WEBP;
                if (lossless)
                {
                    saveFlags = FREE_IMAGE_SAVE_FLAGS.WEBP_LOSSLESS;
                }
                else
                {
                    saveFlags = (FREE_IMAGE_SAVE_FLAGS)90;
                }
                break;
            }

            //Kind of weird, ogre and freeimage are backwards from one another in terms of scanline 0 being the top or bottom
            //This easily fixes the math below by just flipping the image first. Note that pages must be flipped back over because
            //of this when they are saved.
            image.RotateFlip(RotateFlipType.RotateNoneFlipY);

            pagedImage.numImages  = 0;
            pagedImage.imageType  = (int)imageType;
            pagedImage.imageXSize = image.Width;
            pagedImage.imageYSize = image.Height;
            pagedImage.pageSize   = pageSize;
            if (pagedImage.imageXSize != pagedImage.imageYSize)
            {
                throw new InvalidDataException("Image must be a square");
            }

            int mipLevelCount = 0;
            int numPages      = 0;

            for (int i = pagedImage.imageXSize; i >= pageSize; i >>= 1)
            {
                ++mipLevelCount;
                int pagesForMip = i / pageSize;
                numPages += pagesForMip * pagesForMip;
            }
            pagedImage.pages      = new List <ImageInfo>(numPages);
            pagedImage.mipIndices = new List <MipIndexInfo>(mipLevelCount);

            IntSize2 fullPageSize = new IntSize2(pageSize + padding2x, pageSize + padding2x);

            for (int mip = 0; mip < mipLevelCount; ++mip)
            {
                //Setup mip level
                if (mip != 0)
                {
                    pageSizeStrategy.rescaleImage(image, new Size(image.Width >> 1, image.Height >> 1), filter);
                    if (afterResize != null)
                    {
                        //Flip so external functions aren't confused
                        image.RotateFlip(RotateFlipType.RotateNoneFlipY);
                        afterResize(image);
                        //Flip back for correct math
                        image.RotateFlip(RotateFlipType.RotateNoneFlipY);
                    }
                }
                int size = image.Width / pageSize;
                pagedImage.mipIndices.Add(new MipIndexInfo(pagedImage.numImages, size));
                pageSizeStrategy.extractPage(image, padding, stream, pagedImage, pageSize, fullPageSize, size, outputFormat, saveFlags);
            }

            //Write half size mip
            int      halfPageSize   = pageSize >> 1;
            IntSize2 halfSizePadded = new IntSize2(halfPageSize + padding2x, halfPageSize + padding2x);

            pageSizeStrategy.rescaleImage(image, new Size(image.Width >> 1, image.Height >> 1), filter);
            pageSizeStrategy.extractPage(image, padding, stream, pagedImage, halfPageSize, halfSizePadded, 1, outputFormat, saveFlags);

            pagedImage.indexStart = (int)stream.Position;

            using (BinaryWriter sw = new BinaryWriter(stream, EncodingShim.Default, true))
            {
                foreach (var imageInfo in pagedImage.pages)
                {
                    imageInfo.write(sw);
                }

                //Go back to header reserved space
                sw.BaseStream.Seek(0, SeekOrigin.Begin);
                sw.Write(MagicNumber);
                sw.Write(pagedImage.numImages);
                sw.Write(pagedImage.imageType);
                sw.Write(pagedImage.imageXSize);
                sw.Write(pagedImage.imageYSize);
                sw.Write(pagedImage.pageSize);
                sw.Write(pagedImage.indexStart);
            }
        }