Exemplo n.º 1
0
        public void TestMake()
        {
            Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
            var     resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res");
            var     path    = Path.Combine(resPath, "test.txt");
            PsdFile psd     = new PsdFile
            {
                Width      = 600,
                Height     = 600,
                Resolution = new ResolutionInfo
                {
                    HeightDisplayUnit = ResolutionInfo.Unit.Centimeters,
                    WidthDisplayUnit  = ResolutionInfo.Unit.Centimeters,
                    HResDisplayUnit   = ResolutionInfo.ResUnit.PxPerInch,
                    VResDisplayUnit   = ResolutionInfo.ResUnit.PxPerInch,
                    HDpi = new UFixed16_16(0, 350),
                    VDpi = new UFixed16_16(0, 350)
                },
                ImageCompression = ImageCompression.Rle
            };

            psd.ImageResources.Add(new XmpResource("")
            {
                XmpMetaString = File.ReadAllText(path)
            });
            psd.Save(Path.Combine(resPath, "xmp.psd"), Encoding.UTF8);
        }
Exemplo n.º 2
0
        /// <summary>
        /// PSDファイルをトップレベルのレイヤグループ単位で分割します
        /// </summary>
        /// <param name="outdir_prefix">出力先フォルダのプリフィクス</param>
        /// <param name="split_anime_layer">アニメーションレイヤグループ(「@」から始まるレイヤグループ)の展開を許可します</param>
        public void Split()
        {
            //出力先ディレクトリを作成する
            string out_dir;

            out_dir = Path.Combine(Path.GetDirectoryName(InputFilePath), OutputDirPrefix + Path.GetFileName(InputFilePath));
            out_dir = Path.GetFullPath(out_dir);

            if (!Directory.Exists(out_dir))
            {
                Directory.CreateDirectory(out_dir);
            }

            //PSDを分解する
            List <KeyValuePair <string, List <Layer> > > splitted_layers = SplitPsd();


            //分解したPSDそれぞれ保存する
            for (int i = 0; i < splitted_layers.Count; i++)
            {
                string       name   = splitted_layers[i].Key;
                List <Layer> layers = splitted_layers[i].Value;

                PsdFile psd_out = MakePsd(InputPsdFile, layers);

                string out_filename = string.Format("{0}-{1}.psd", Path.GetFileNameWithoutExtension(InputFilePath), name);
                Array.ForEach(Path.GetInvalidFileNameChars(), x =>
                {
                    out_filename = out_filename.Replace(x, '_');
                });


                psd_out.Save(Path.Combine(out_dir, out_filename), Encoding.UTF8);
            }
        }
Exemplo n.º 3
0
        public static void Save(Document input, Stream output, PsdSaveConfigToken psdToken,
                                Surface scratchSurface, ProgressEventHandler progressCallback)
        {
            var psdVersion = ((input.Height > 30000) || (input.Width > 30000))
        ? PsdFileVersion.PsbLargeDocument
        : PsdFileVersion.Psd;
            var psdFile = new PsdFile(psdVersion);

            psdFile.RowCount    = input.Height;
            psdFile.ColumnCount = input.Width;

            // We only save in RGBA format, 8 bits per channel, which corresponds to
            // Paint.NET's internal representation.

            psdFile.ChannelCount     = 4;
            psdFile.ColorMode        = PsdColorMode.RGB;
            psdFile.BitDepth         = 8;
            psdFile.Resolution       = GetResolutionInfo(input);
            psdFile.ImageCompression = psdToken.RleCompress
        ? ImageCompression.Rle
        : ImageCompression.Raw;

            // Treat the composite image as another layer when reporting progress.
            var progress        = new ProgressNotifier(progressCallback);
            var percentPerLayer = percentStoreImages
                                  / (input.Layers.Count + 1);

            // Render the composite image.  This operation is parallelized within
            // Paint.NET using its own private thread pool.
            using (var ra = new RenderArgs(scratchSurface))
            {
                input.Flatten(scratchSurface);
                progress.Notify(percentRenderComposite);
            }

            // Delegate to store the composite
            Action storeCompositeAction = () =>
            {
                // Allocate space for the composite image data
                int imageSize = psdFile.RowCount * psdFile.ColumnCount;
                for (short i = 0; i < psdFile.ChannelCount; i++)
                {
                    var channel = new Channel(i, psdFile.BaseLayer);
                    channel.ImageData        = new byte[imageSize];
                    channel.ImageCompression = psdFile.ImageCompression;
                    psdFile.BaseLayer.Channels.Add(channel);
                }

                var channelsArray = psdFile.BaseLayer.Channels.ToIdArray();
                StoreLayerImage(channelsArray, channelsArray[3],
                                scratchSurface, psdFile.BaseLayer.Rect);

                progress.Notify(percentPerLayer);
            };

            // Delegate to store the layers
            Action storeLayersAction = () =>
            {
                // LayerList is an ArrayList, so we have to cast to get a generic
                // IEnumerable that works with LINQ.
                var pdnLayers = input.Layers.Cast <BitmapLayer>();

                // Create folders/groups before actual image data will be saved.
                var layerInfos = PrepareLayers(pdnLayers, psdToken.SaveLayers);


                var psdLayers = layerInfos.AsParallel().AsOrdered().Select(pdnLayer =>
                {
                    var psdLayer = new PhotoshopFile.Layer(psdFile);
                    StoreLayer(pdnLayer, psdLayer, psdToken);

                    progress.Notify(percentPerLayer);
                    return(psdLayer);
                });
                psdFile.Layers.AddRange(psdLayers);
            };

            // Process composite and layers in parallel
            Parallel.Invoke(storeCompositeAction, storeLayersAction);

            psdFile.Save(output, Encoding.Default);
        }
Exemplo n.º 4
0
        static private void UpdatePsd(FileInfo fileInfo, Dictionary <string, Color> convertMap)
        {
            Console.Out.WriteLine("Start Convert " + fileInfo.FullName);

            var fileStream = new FileStream(fileInfo.FullName, FileMode.Open);

            if (fileStream == null)
            {
                Console.Out.WriteLine("Paramter Error, Skip");
                return;
            }

            var psdFile = new PsdFile(fileStream, new LoadContext());

            fileStream.Close();

            foreach (Layer layr in psdFile.Layers)
            {
                var layName = layr.Name.ToUpper();
                try
                {
                    var findKey = convertMap.Single(x => layName.Contains(x.Key));
                    var color   = findKey.Value;

                    var vscg       = layr.AdditionalInfo.SingleOrDefault(x => x.Key == "vscg");
                    var solidColor = layr.AdditionalInfo.SingleOrDefault(x => x.Key == "SoCo");
                    //var tysh = layr.AdditionalInfo.SingleOrDefault(x => x.Key == "TySh");
                    if (solidColor == null /*&& tysh == null*/ && vscg == null)
                    {
                        ConsoleColor oldColor = Console.ForegroundColor;
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.Out.WriteLine("Convert Error : " + fileInfo.FullName);
                        Console.ForegroundColor = oldColor;
                        return;
                    }

                    if (vscg != null)
                    {
                        solidColor = vscg;
                    }

                    if (solidColor != null)
                    {
                        PhotoshopFile.PsdDescriptor eff = new PhotoshopFile.PsdDescriptor(CreateReadStream(solidColor));

                        double red   = color.R;
                        double green = color.G;
                        double blue  = color.B;
                        byte[] redBuffer, greenBuffer, blueBuffer;
                        unsafe
                        {
                            BinaryReverseReader.SwapBytes((byte *)&red, 8);
                            redBuffer = ConvertDoubleToByteArray(red);
                            BinaryReverseReader.SwapBytes((byte *)&green, 8);
                            greenBuffer = ConvertDoubleToByteArray(green);
                            BinaryReverseReader.SwapBytes((byte *)&blue, 8);
                            blueBuffer = ConvertDoubleToByteArray(blue);
                        }

                        long redOffset = 0, greenOffset = 0, blueOffset = 0;
                        GetPSDColorOffset(eff, ref redOffset, ref greenOffset, ref blueOffset);

                        BinaryReverseWriter writer = CreateWriteStream(solidColor);
                        writer.Seek((int)redOffset, SeekOrigin.Begin);
                        writer.Write(redBuffer);
                        writer.Seek((int)greenOffset, SeekOrigin.Begin);
                        writer.Write(greenBuffer);
                        writer.Seek((int)blueOffset, SeekOrigin.Begin);
                        writer.Write(blueBuffer);
                    }
                    //else if (tysh != null)
                    //{
                    //    PhotoshopFile.LayerResources.TypeToolTyShPH6 txt = new PhotoshopFile.LayerResources.TypeToolTyShPH6(CreateReadStream(tysh));
                    //    Dictionary<string, object> d = txt.StylesheetReader.GetStylesheetDataFromLongestRun();
                    //    BinaryReverseWriter writer = CreateWriteStream(tysh);
                    //    //writer.Seek((int)redOffset, SeekOrigin.Begin);
                    //    //writer.Write(redBuffer);
                    //    //writer.Seek((int)greenOffset, SeekOrigin.Begin);
                    //    //writer.Write(greenBuffer);
                    //    //writer.Seek((int)blueOffset, SeekOrigin.Begin);
                    //    //writer.Write(blueBuffer);
                    //}
                }
                catch
                {
                }
            }

            psdFile.Save(fileInfo.DirectoryName + "\\_" + fileInfo.Name, Encoding.Default);
            Console.Out.WriteLine("Convert Finished, Save to " + fileInfo.DirectoryName + "\\_" + fileInfo.Name, Encoding.Default);
        }
Exemplo n.º 5
0
        private static void ExportMapSafe(String mapName)
        {
            try
            {
                String relativePath    = FieldMap.GetMapResourcePath(mapName);
                String outputDirectory = Path.Combine(Configuration.Export.Path, relativePath);
                if (Directory.Exists(outputDirectory))
                {
                    Log.Warning($"Export was not skipped because kostyli");
                    //Log.Warning($"[FieldSceneExporter] Export was skipped bacause a directory already exists: [{outputDirectory}].");
                    //return;
                }

                Log.Message("[FieldSceneExporter] Exporting [{0}]...", mapName);

                BGSCENE_DEF scene = new BGSCENE_DEF(true);
                scene.LoadEBG(null, relativePath, mapName);

                //String directoryPath = Path.GetDirectoryName(outputPath);
                Directory.CreateDirectory(outputDirectory);

                Texture2D atlasTexture  = TextureHelper.CopyAsReadable(scene.atlas);
                Int32     factor        = (Int32)scene.SPRITE_W / 16;
                Int32     textureWidth  = (Int32)(scene.overlayList.SelectMany(s => s.spriteList).Max(s => s.offY * factor) + scene.SPRITE_H);
                Int32     textureHeight = (Int32)(scene.overlayList.SelectMany(s => s.spriteList).Max(s => s.offX * factor) + scene.SPRITE_W);

                using (Stream output = File.Create(outputDirectory + "test.psd"))
                {
                    PsdFile file = new PsdFile();
                    file.BitDepth     = 8;
                    file.ChannelCount = 4;
                    file.ColorMode    = PsdColorMode.Rgb;
                    file.RowCount     = textureWidth;
                    file.ColumnCount  = textureHeight;
                    file.Resolution   = new ResolutionInfo
                    {
                        Name = "ResolutionInfo ",

                        HDpi              = new UFixed1616(72, 0),
                        HResDisplayUnit   = ResolutionInfo.ResUnit.PxPerInch,
                        HeightDisplayUnit = ResolutionInfo.Unit.Centimeters,

                        VDpi             = new UFixed1616(72, 0),
                        VResDisplayUnit  = ResolutionInfo.ResUnit.PxPerInch,
                        WidthDisplayUnit = ResolutionInfo.Unit.Centimeters
                    };

                    file.BaseLayer.Name = "Base";
                    for (Int16 i = 0; i < 4; i++)
                    {
                        Channel channel = new Channel(i, file.BaseLayer);
                        channel.ImageCompression = file.ImageCompression;
                        channel.Length           = file.RowCount * Util.BytesPerRow(file.BaseLayer.Rect.Size, file.BitDepth);
                        channel.ImageData        = new Byte[channel.Length];
                        file.BaseLayer.Channels.Add(channel);
                    }

                    file.BaseLayer.Channels.Last().ID = -1;

                    for (Int32 index = scene.overlayList.Count - 1; index >= 0; index--) //scene.overlayList.Count
                    {
                        BGOVERLAY_DEF overlay    = scene.overlayList[index];
                        String        outputPath = outputDirectory + $"Overlay{index}.png";
                        ExportOverlayTest(overlay, atlasTexture, outputPath, scene, file);
                        //return;
                    }

                    file.Save(output, Encoding.UTF8);
                }

                //TextureHelper.WriteTextureToFile(TextureHelper.CopyAsReadable(scene.atlas), outputPath);

                Log.Message("[FieldSceneExporter] Exporting completed successfully.");
            }
            catch (Exception ex)
            {
                Log.Error(ex, "[FieldSceneExporter] Failed to export map [{0}].", mapName);
            }
        }
Exemplo n.º 6
0
        protected override void OnSave(Document input, System.IO.Stream output,
                                       SaveConfigToken token, Surface scratchSurface, ProgressEventHandler callback)
        {
            PsdSaveConfigToken psdToken = (PsdSaveConfigToken)token;
            PsdFile            psdFile  = new PsdFile();

            //-----------------------------------------------------------------------

            psdFile.Rows    = input.Height;
            psdFile.Columns = input.Width;

            // we have an Alpha channel which will be saved,
            // we have to add this to our image resources
            psdFile.Channels = 4;

            // for now we oly save the images as RGB
            psdFile.ColorMode = PsdFile.ColorModes.RGB;

            psdFile.Depth = 8;

            //-----------------------------------------------------------------------
            // no color mode Data

            //-----------------------------------------------------------------------

            ResolutionInfo resInfo = new ResolutionInfo();

            resInfo.HeightUnit = ResolutionInfo.Unit.In;
            resInfo.WidthUnit  = ResolutionInfo.Unit.In;

            if (input.DpuUnit == MeasurementUnit.Inch)
            {
                resInfo.HResUnit = ResolutionInfo.ResUnit.PxPerInch;
                resInfo.VResUnit = ResolutionInfo.ResUnit.PxPerInch;

                resInfo.HRes = (short)input.DpuX;
                resInfo.VRes = (short)input.DpuY;
            }
            else
            {
                resInfo.HResUnit = ResolutionInfo.ResUnit.PxPerCent;
                resInfo.VResUnit = ResolutionInfo.ResUnit.PxPerCent;


                resInfo.HRes = (short)(input.DpuX / 2.54);
                resInfo.VRes = (short)(input.DpuY / 2.54);
            }

            psdFile.Resolution = resInfo;
            //-----------------------------------------------------------------------

            psdFile.ImageCompression = psdToken.RleCompress ? ImageCompression.Rle : ImageCompression.Raw;

            int size = psdFile.Rows * psdFile.Columns;

            psdFile.ImageData = new byte[psdFile.Channels][];
            for (int i = 0; i < psdFile.Channels; i++)
            {
                psdFile.ImageData[i] = new byte[size];
            }

            using (RenderArgs ra = new RenderArgs(scratchSurface))
            {
                input.Flatten(scratchSurface);
            }

            unsafe
            {
                for (int y = 0; y < psdFile.Rows; y++)
                {
                    int        rowIndex = y * psdFile.Columns;
                    ColorBgra *srcRow   = scratchSurface.GetRowAddress(y);
                    ColorBgra *srcPixel = srcRow;

                    for (int x = 0; x < psdFile.Columns; x++)
                    {
                        int pos = rowIndex + x;

                        psdFile.ImageData[0][pos] = srcPixel->R;
                        psdFile.ImageData[1][pos] = srcPixel->G;
                        psdFile.ImageData[2][pos] = srcPixel->B;
                        psdFile.ImageData[3][pos] = srcPixel->A;
                        srcPixel++;
                    }
                }
            }

            PaintDotNet.Threading.PrivateThreadPool threadPool = new PaintDotNet.Threading.PrivateThreadPool();
            foreach (BitmapLayer layer in input.Layers)
            {
                PhotoshopFile.Layer psdLayer = new PhotoshopFile.Layer(psdFile);
                BlendOpToBlendModeKey(layer.BlendOp, psdLayer);

                SaveLayerPixelsContext slc          = new SaveLayerPixelsContext(layer, psdFile, input, psdLayer, psdToken);
                WaitCallback           waitCallback = new WaitCallback(slc.SaveLayer);
                threadPool.QueueUserWorkItem(waitCallback);
            }
            threadPool.Drain();

            psdFile.Save(output);
        }
Exemplo n.º 7
0
        public void ToBMP(string path)
        {
            int width  = MaxX / (DIAMETER * 2) - MinX / (DIAMETER * 2);
            int height = MaxY / (DIAMETER * 2) - MinY / (DIAMETER * 2);
            int depth  = MaxZ - MinZ;

            PsdFile psdFile = new PsdFile()
            {
                //-----------------------------------------------------------------------

                Rows    = height,
                Columns = width,

                // We only save in 8 bits per channel RGBA format, which corresponds to
                // Paint.NET's internal representation.
                Channels  = 4,
                ColorMode = PsdColorMode.RGB,
                Depth     = 8
            };

            //-----------------------------------------------------------------------
            // No color mode data is necessary for RGB
            //-----------------------------------------------------------------------

            ResolutionInfo resInfo = new ResolutionInfo()
            {
                HeightDisplayUnit = ResolutionInfo.Unit.In,
                WidthDisplayUnit  = ResolutionInfo.Unit.In,

                HResDisplayUnit = ResolutionInfo.ResUnit.PxPerInch,
                VResDisplayUnit = ResolutionInfo.ResUnit.PxPerInch,

                HDpi = new UFixed16_16(72),
                VDpi = new UFixed16_16(72)
            };

            psdFile.Resolution       = resInfo;
            psdFile.ImageCompression = ImageCompression.Rle;

            //-----------------------------------------------------------------------
            // Set document image data from the fully-rendered image
            //-----------------------------------------------------------------------

            int imageSize = psdFile.Rows * psdFile.Columns;

            psdFile.Layers.Clear();
            for (short i = 0; i < psdFile.Channels; i++)
            {
                var channel = new Layer.Channel(i, psdFile.BaseLayer)
                {
                    ImageData        = new byte[imageSize],
                    ImageCompression = psdFile.ImageCompression
                };
            }
            AddNewLayer(psdFile, 0);
            var alpha = psdFile.Layers[0].AlphaChannel.ImageData;

            for (int i = 0; i < psdFile.Rows * psdFile.Columns; i++)
            {
                alpha[i] = 255;
            }
            AddNewLayer(psdFile, 1);
            for (int y = MinY; y <= MaxY - (DIAMETER * 2); y += (DIAMETER * 2))
            {
                for (int x = MinX; x <= MaxX - (DIAMETER * 2); x += (DIAMETER * 2))
                {
                    int hash = CalcHash((short)x, (short)y);
                    try
                    {
                        if (values.ContainsKey(hash))
                        {
                            var points = (from p in values[hash].Keys
                                          orderby p descending
                                          select p).ToArray();
                            for (int index = 0; index < points.Length; index++)
                            {
                                int c  = (int)((((float)points[index] - MinZ) / depth) * 250 + 5);
                                int x2 = (x - MinX) / (DIAMETER * 2);
                                int y2 = (y - MinY) / (DIAMETER * 2);

                                if (index >= psdFile.Layers.Count - 1)
                                {
                                    AddNewLayer(psdFile, index + 1);
                                }

                                int pos     = x2 + width * y2;
                                var rgb     = psdFile.Layers[index + 1].ChannelsArray;
                                var alphaCh = psdFile.Layers[index + 1].AlphaChannel;
                                rgb[0].ImageData[pos]  = (byte)c;
                                rgb[1].ImageData[pos]  = (byte)c;
                                rgb[2].ImageData[pos]  = (byte)c;
                                alphaCh.ImageData[pos] = 255;
                            }
                        }
                    }
                    catch
                    {
                    }
                }
            }
            Layer l = psdFile.Layers[0];

            psdFile.Layers.RemoveAt(0);
            psdFile.Layers.Reverse();
            psdFile.Layers.Insert(0, l);
            psdFile.Save(path);
            psdFile = null;
        }
Exemplo n.º 8
0
        private void OnSaveClick(object sender, EventArgs e)
        {
            if (m_fileStructure.Nodes.Count == 0)
            {
                return;
            }

            PsdFile psdFileSrc = (PsdFile)m_fileStructure.Nodes[0].Tag;


            PsdFile psdFile = new PsdFile();

            //-----------------------------------------------------------------------

            psdFile.Rows    = psdFileSrc.Rows;
            psdFile.Columns = psdFileSrc.Columns;

            // we have an Alpha channel which will be saved,
            // we have to add this to our image resources
            psdFile.Channels = 3;// 4;

            // for now we oly save the images as RGB
            psdFile.ColorMode = PsdFile.ColorModes.RGB;

            psdFile.Depth = 8;

            //-----------------------------------------------------------------------
            // no color mode Data

            //-----------------------------------------------------------------------

            psdFile.ImageResources.Clear();
            psdFile.ImageResources.AddRange(psdFileSrc.ImageResources.ToArray());

            //-----------------------------------------------------------------------

            int size = psdFile.Rows * psdFile.Columns;

            psdFile.ImageData = new byte[psdFile.Channels][];
            for (int i = 0; i < psdFile.Channels; i++)
            {
                psdFile.ImageData[i] = new byte[size];
            }

            Bitmap bmp = ImageDecoder.DecodeImage(psdFileSrc);

            for (int y = 0; y < psdFile.Rows; y++)
            {
                int rowIndex = y * psdFile.Columns;

                for (int x = 0; x < psdFile.Columns; x++)
                {
                    int pos = rowIndex + x;

                    Color pixelColor = bmp.GetPixel(x, y);

                    psdFile.ImageData[0][pos] = pixelColor.R;
                    psdFile.ImageData[1][pos] = pixelColor.G;
                    psdFile.ImageData[2][pos] = pixelColor.B;
                    //psdFile.ImageData[3][pos] = pixelColor.A;
                }
            }

            //-----------------------------------------------------------------------

            psdFile.ImageCompression = ImageCompression.Rle;

            psdFile.Save(Path.Combine(Path.GetDirectoryName(m_fileName.Text), Path.GetFileNameWithoutExtension(m_fileName.Text) + "-saved.psd"));
        }
Exemplo n.º 9
0
        private static void ExportMapSafe(String mapName)
        {
            try
            {
                String relativePath    = FieldMap.GetMapResourcePath(mapName);
                String outputDirectory = Path.Combine(Configuration.Export.Path, relativePath);
                // TODO: uncomment this when all is well
                //if (Directory.Exists(outputDirectory))
                //{

                //    Log.Warning($"[FieldSceneExporter] Export was skipped bacause a directory already exists: [{outputDirectory}].");
                //    //return;
                //}

                Log.Message("[FieldSceneExporter] Exporting [{0}]...", mapName);

                BGSCENE_DEF scene = new BGSCENE_DEF(true);
                scene.LoadResources(null, relativePath, mapName);

                //String directoryPath = Path.GetDirectoryName(outputPath);

                Directory.CreateDirectory(outputDirectory);

                Texture2D atlasTexture  = TextureHelper.CopyAsReadable(scene.atlas);
                Int32     factor        = (Int32)scene.SPRITE_W / 16;
                Int32     textureWidth  = (Int32)(scene.overlayList.SelectMany(s => s.spriteList).Max(s => s.offY * factor) + scene.SPRITE_H);
                Int32     textureHeight = (Int32)(scene.overlayList.SelectMany(s => s.spriteList).Max(s => s.offX * factor) + scene.SPRITE_W);

                using (Stream output = File.Create(outputDirectory + "test.psd"))
                {
                    PsdFile file = new PsdFile();
                    file.BitDepth     = 8;
                    file.ChannelCount = 4;
                    file.ColorMode    = PsdColorMode.Rgb;
                    file.RowCount     = textureWidth;
                    file.ColumnCount  = textureHeight;
                    file.Resolution   = new ResolutionInfo
                    {
                        Name = "ResolutionInfo ",

                        HDpi              = new UFixed1616(72, 0),
                        HResDisplayUnit   = ResolutionInfo.ResUnit.PxPerInch,
                        HeightDisplayUnit = ResolutionInfo.Unit.Centimeters,

                        VDpi             = new UFixed1616(72, 0),
                        VResDisplayUnit  = ResolutionInfo.ResUnit.PxPerInch,
                        WidthDisplayUnit = ResolutionInfo.Unit.Centimeters
                    };

                    file.BaseLayer.Name = "Base";
                    for (Int16 i = 0; i < 4; i++)
                    {
                        Channel channel = new Channel(i, file.BaseLayer);
                        channel.ImageCompression = file.ImageCompression;
                        channel.Length           = file.RowCount * Util.BytesPerRow(file.BaseLayer.Rect.Size, file.BitDepth);
                        channel.ImageData        = new Byte[channel.Length];
                        file.BaseLayer.Channels.Add(channel);
                    }

                    file.BaseLayer.Channels.Last().ID = -1;

                    for (Int32 index = scene.overlayList.Count - 1; index >= 0; index--) //scene.overlayList.Count
                    {
                        BGOVERLAY_DEF overlay    = scene.overlayList[index];
                        String        outputPath = outputDirectory + $"Overlay{index}.png";
                        ExportOverlay(overlay, atlasTexture, outputPath, scene, file);
                    }

                    // get all languages
                    FieldMapLocalizeAreaTitleInfo info = FieldMapInfo.localizeAreaTitle.GetInfo(mapName);
                    if (info != null)
                    {
                        Int32    startOvrIdx  = info.startOvrIdx;
                        Int32    endOvrIdx    = info.endOvrIdx;
                        String[] allLanguages = Configuration.Export.Languages;
                        foreach (var language in allLanguages)
                        {
                            BGSCENE_DEF localeScene = new BGSCENE_DEF(scene.GetUseUpscaleFM());
                            localeScene.LoadLocale(scene, relativePath, mapName, info, language);
                            for (Int32 index = startOvrIdx; index <= endOvrIdx; index++)
                            {
                                BGOVERLAY_DEF overlay    = scene.overlayList[index];
                                String        outputPath = outputDirectory + $"Overlay{index}_{language}.png";
                                ExportOverlay(overlay, atlasTexture, outputPath, scene, file);
                            }
                        }
                    }

                    file.Save(output, Encoding.UTF8);
                }

                string strings            = $"[PsdSection]\nLayerOrder=name\nReversed = 0";
                System.IO.StreamWriter sw = new System.IO.StreamWriter(Path.Combine(outputDirectory, "psd.meta"));
                sw.WriteLine(strings);
                sw.Close();


                TextureHelper.WriteTextureToFile(atlasTexture, Path.Combine(outputDirectory, "atlas.png"));

                Log.Message("[FieldSceneExporter] Exporting completed successfully.");
            }
            catch (Exception ex)
            {
                Log.Error(ex, "[FieldSceneExporter] Failed to export map [{0}].", mapName);
            }
        }