예제 #1
0
        /// <summary>
        /// Function to save the specified image file.
        /// </summary>
        /// <param name="name">The name of the file to write into.</param>
        /// <param name="image">The image to save.</param>
        /// <param name="pixelFormat">The pixel format for the image.</param>
        /// <param name="codec">[Optional] The codec to use when saving the image.</param>
        /// <returns>The updated working file.</returns>
        public IGorgonVirtualFile SaveImageFile(string name, IGorgonImage image, BufferFormat pixelFormat, IGorgonImageCodec codec = null)
        {
            if (codec == null)
            {
                codec = DefaultCodec;
            }

            // We absolutely need to have an extension, or else the texconv tool will not work.
            if ((codec.CodecCommonExtensions.Count > 0) &&
                (!string.Equals(Path.GetExtension(name), codec.CodecCommonExtensions[0], StringComparison.OrdinalIgnoreCase)))
            {
                _log.Print("Adding extension to working file or else external tools may not be able to read it.", LoggingLevel.Verbose);
                name = Path.ChangeExtension(name, codec.CodecCommonExtensions[0]);
            }

            IGorgonVirtualFile workFile = ScratchArea.FileSystem.GetFile(name);
            var formatInfo = new GorgonFormatInfo(pixelFormat);

            // The file doesn't exist, so we need to create a dummy file.
            if (workFile == null)
            {
                using (Stream tempStream = ScratchArea.OpenStream(name, FileMode.Create))
                {
                    tempStream.WriteString("TEMP_WORKING_FILE");
                }

                workFile = ScratchArea.FileSystem.GetFile(name);
            }

            _log.Print($"Working image file: '{workFile.FullPath}'.", LoggingLevel.Verbose);


            IGorgonVirtualFile result;

            // For compressed images, we need to rely on an external tool to do the job.
            if (formatInfo.IsCompressed)
            {
                _log.Print($"Pixel format [{pixelFormat}] is a block compression format, compressing using external tool...", LoggingLevel.Intermediate);
                if ((_compressor == null) || (!codec.SupportsBlockCompression))
                {
                    throw new GorgonException(GorgonResult.CannotRead, string.Format(Resources.GORIMG_ERR_COMPRESSED_FILE, formatInfo.Format));
                }

                // Send the image data as uncompressed to our working file, so we can have something to compress.
                using (Stream outStream = ScratchArea.OpenStream(workFile.FullPath, FileMode.Create))
                {
                    codec.SaveToStream(image, outStream);
                }

                _log.Print($"Saving to working file '{workFile.FullPath}'...", LoggingLevel.Simple);
                result = _compressor.Compress(workFile, pixelFormat, image.MipCount);

                // Convert to an uncompressed format if we aren't already in that format.
                switch (pixelFormat)
                {
                case BufferFormat.BC5_SNorm when image.Format != BufferFormat.R8G8_SNorm:
                    image.ConvertToFormat(BufferFormat.R8G8_SNorm);
                    break;

                case BufferFormat.BC5_Typeless when image.Format != BufferFormat.R8G8_UNorm:
                case BufferFormat.BC5_UNorm when image.Format != BufferFormat.R8G8_UNorm:
                    image.ConvertToFormat(BufferFormat.R8G8_UNorm);
                    break;

                case BufferFormat.BC6H_Sf16 when image.Format != BufferFormat.R16G16B16A16_Float:
                case BufferFormat.BC6H_Typeless when image.Format != BufferFormat.R16G16B16A16_Float:
                case BufferFormat.BC6H_Uf16 when image.Format != BufferFormat.R16G16B16A16_Float:
                    image.ConvertToFormat(BufferFormat.R16G16B16A16_Float);
                    break;

                case BufferFormat.BC4_SNorm when image.Format != BufferFormat.R8G8_SNorm:
                    image.ConvertToFormat(BufferFormat.R8_SNorm);
                    break;

                case BufferFormat.BC4_Typeless when image.Format != BufferFormat.R8G8_UNorm:
                case BufferFormat.BC4_UNorm when image.Format != BufferFormat.R8G8_UNorm:
                    image.ConvertToFormat(BufferFormat.R8_UNorm);
                    break;

                case BufferFormat.BC1_Typeless when image.Format != BufferFormat.R8G8B8A8_UNorm:
                case BufferFormat.BC1_UNorm when image.Format != BufferFormat.R8G8B8A8_UNorm:
                case BufferFormat.BC2_Typeless when image.Format != BufferFormat.R8G8B8A8_UNorm:
                case BufferFormat.BC2_UNorm when image.Format != BufferFormat.R8G8B8A8_UNorm:
                case BufferFormat.BC3_Typeless when image.Format != BufferFormat.R8G8B8A8_UNorm:
                case BufferFormat.BC3_UNorm when image.Format != BufferFormat.R8G8B8A8_UNorm:
                case BufferFormat.BC7_Typeless when image.Format != BufferFormat.R8G8B8A8_UNorm:
                case BufferFormat.BC7_UNorm when image.Format != BufferFormat.R8G8B8A8_UNorm:
                    image.ConvertToFormat(BufferFormat.R8G8B8A8_UNorm);
                    break;

                case BufferFormat.BC1_UNorm_SRgb when image.Format != BufferFormat.R8G8B8A8_UNorm_SRgb:
                case BufferFormat.BC2_UNorm_SRgb when image.Format != BufferFormat.R8G8B8A8_UNorm_SRgb:
                case BufferFormat.BC3_UNorm_SRgb when image.Format != BufferFormat.R8G8B8A8_UNorm_SRgb:
                case BufferFormat.BC7_UNorm_SRgb when image.Format != BufferFormat.R8G8B8A8_UNorm_SRgb:
                    image.ConvertToFormat(BufferFormat.R8G8B8A8_UNorm_SRgb);
                    break;
                }

                if (result == null)
                {
                    throw new GorgonException(GorgonResult.CannotRead, string.Format(Resources.GORIMG_ERR_COMPRESSED_FILE, formatInfo.Format));
                }
            }
            else
            {
                // We've changed the pixel format, so convert prior to saving.
                if (pixelFormat != image.Format)
                {
                    _log.Print($"Image pixel format [{image.Format}] is different than requested format of [{pixelFormat}], converting...", LoggingLevel.Intermediate);
                    image.ConvertToFormat(pixelFormat);
                    _log.Print($"Converted image '{workFile.Name}' to pixel format: [{pixelFormat}].", LoggingLevel.Simple);
                }

                _log.Print($"Saving to working file '{workFile.FullPath}'...", LoggingLevel.Simple);
                using (Stream outStream = ScratchArea.OpenStream(workFile.FullPath, FileMode.Create))
                {
                    codec.SaveToStream(image, outStream);
                }

                ScratchArea.FileSystem.Refresh();
                result = ScratchArea.FileSystem.GetFile(workFile.FullPath);
            }

            return(result);
        }
예제 #2
0
        /// <summary>Function to save the atlas data.</summary>
        /// <param name="atlas">The atlas data to save.</param>
        public void SaveAtlas(IReadOnlyDictionary <IContentFile, GorgonSprite> spriteFiles, GorgonTextureAtlas atlas)
        {
            IGorgonImage image     = null;
            string       directory = Path.GetDirectoryName(atlas.Textures[0].Texture.Name).FormatDirectory('/');
            Stream       outStream = null;

            try
            {
                _fileSystem.BeginBatch();

                if (!_fileSystem.DirectoryExists(directory))
                {
                    _fileSystem.CreateDirectory(directory);
                }

                void WriteImageFile(Stream stream) => _defaultImageCodec.SaveToStream(image, stream);

                // Check the files to ensure they're not open for editing.
                foreach (GorgonTexture2DView texture in atlas.Textures)
                {
                    IContentFile textureFile = _fileSystem.GetFile(texture.Texture.Name);

                    if ((textureFile != null) && (textureFile.IsOpen))
                    {
                        throw new IOException(string.Format(Resources.GORTAG_ERR_IMAGE_OPEN, textureFile.Path));
                    }
                }

                foreach ((GorgonSprite original, GorgonSprite sprite) in atlas.Sprites)
                {
                    IContentFile oldFile = spriteFiles.FirstOrDefault(item => item.Value == original).Key;

                    if ((oldFile != null) && (oldFile.IsOpen))
                    {
                        throw new IOException(string.Format(Resources.GORTAG_ERR_IMAGE_OPEN, oldFile.Path));
                    }
                }

                // Write textures.
                foreach (GorgonTexture2DView texture in atlas.Textures)
                {
                    image = texture.Texture.ToImage();
                    _fileSystem.WriteFile(texture.Texture.Name, WriteImageFile);
                    image.Dispose();
                }

                // Write out the updated sprites.
                foreach ((GorgonSprite original, GorgonSprite sprite) in atlas.Sprites)
                {
                    IContentFile oldTextureFile = null;
                    IContentFile textureFile    = _fileSystem.GetFile(sprite.Texture.Texture.Name);
                    IContentFile oldFile        = spriteFiles.FirstOrDefault(item => item.Value == original).Key;

                    if (oldFile.Metadata.DependsOn.TryGetValue(CommonEditorContentTypes.ImageType, out string oldTexturePath))
                    {
                        oldTextureFile = _fileSystem.GetFile(oldTexturePath);
                    }

                    outStream = oldFile.OpenWrite();
                    _defaultSpriteCodec.Save(sprite, outStream);

                    textureFile.LinkContent(oldFile);
                    oldTextureFile?.UnlinkContent(oldFile);

                    oldFile.RefreshMetadata();
                    oldFile.Refresh();
                    outStream.Dispose();
                }
            }
            finally
            {
                outStream?.Dispose();
                image?.Dispose();
                _fileSystem.EndBatch();
            }
        }