Beispiel #1
0
        /// <summary>
        /// <see cref="PsbResHelper.CollectResources"/> for packed-texture specs, like <see cref="PsbSpec.win"/>
        /// </summary>
        /// <param name="psb"></param>
        /// <returns></returns>
        public static List <ImageMetadata> CollectSplitResources(this PSB psb)
        {
            List <ImageMetadata> resList = new List <ImageMetadata>();
            var source = (PsbDictionary)psb.Objects["source"];

            foreach (var tex in source)
            {
                if (tex.Value is PsbDictionary texDic)
                {
                    var typeStr = (PsbString)texDic["texture"].Children("type");
                    typeStr = PsbPixelFormat.WinRGBA8.ToStringForPsb().ToPsbString();
                    var bmps  = SplitTexture(texDic, psb.Platform);
                    var icons = (PsbDictionary)texDic["icon"];
                    foreach (var iconPair in icons)
                    {
                        var res = new PsbResource
                        {
                            Data =
                                RL.GetPixelBytesFromImage(bmps[iconPair.Key], typeStr.Value.ToPsbPixelFormat(psb.Platform))
                        };
                        var icon = (PsbDictionary)iconPair.Value;
                        var md   = PsbResHelper.GenerateImageMetadata(icon, res);
                        md.Spec       = psb.Platform;
                        md.TypeString = typeStr;
                        resList.Add(md);
                    }
                }
            }

            return(resList);
        }
        /// <summary>
        /// Combine Image texture parts
        /// </summary>
        /// <param name="psb">Image (image) type PSB</param>
        /// <returns></returns>
        public static Dictionary <string, Bitmap> CombineTachie(PSB psb)
        {
            if (psb.Type != PsbType.Tachie)
            {
                throw new NotSupportedException("PSB is not image type");
            }

            Dictionary <string, Bitmap> images = new Dictionary <string, Bitmap>();
            PsbList imageList = psb.Objects["imageList"] as PsbList;

            if (imageList == null)
            {
                return(images);
            }

            foreach (var psbValue in imageList)
            {
                var imageItem = psbValue as PsbDictionary;

                var texture = imageItem?["texture"] as PsbList;
                if (texture == null)
                {
                    continue;
                }

                var height = imageItem["height"].GetInt();
                var width  = imageItem["width"].GetInt();
                var label  = imageItem["label"].ToString();

                Bitmap img = new Bitmap(width, height, PixelFormat.Format32bppArgb);
                using (var f = img.FastLock())
                {
                    foreach (var texObj in texture)
                    {
                        var tex = (PsbDictionary)texObj;
                        var md  = PsbResHelper.GenerateImageMetadata(tex.Children("image") as PsbDictionary);
                        md.Spec = psb.Platform;

                        var left    = tex["left"].GetInt();
                        var top     = tex["top"].GetInt();
                        var tHeight = tex["height"].GetInt();
                        var tWidth  = tex["width"].GetInt();

                        f.CopyRegion(md.ToImage(), new Rectangle(0, 0, md.Width, md.Height), new Rectangle(left, top, tWidth, tHeight));
                    }
                }

                images.Add(label, img);
            }

            return(images);
        }
Beispiel #3
0
        public static Dictionary <string, Bitmap> SplitTexture(PsbDictionary tex, PsbSpec spec)
        {
            var icon    = (PsbDictionary)tex["icon"];
            var texture = (PsbDictionary)tex["texture"];

            //var mipmap = (PsbDictionary)texture["mipMap"]; //TODO: Mipmap?
            Dictionary <string, Bitmap> textures = new Dictionary <string, Bitmap>(icon.Count);

            var pixel = texture[Consts.ResourceKey];

            if (pixel == null || !(pixel is PsbResource pixelRes))
            {
                throw new PsbBadFormatException(PsbBadFormatReason.Resources,
                                                "External Texture PSB is not supported. Please Link textures into PSB.");
                return(textures);
            }

            var md = PsbResHelper.GenerateImageMetadata(texture, pixelRes);

            md.Spec = spec; //Important
            Bitmap bmp = md.ToImage();

            foreach (var iconPair in icon)
            {
                var    info   = (PsbDictionary)iconPair.Value;
                var    width  = (int)(PsbNumber)info["width"];
                var    height = (int)(PsbNumber)info["height"];
                var    top    = (int)(PsbNumber)info["top"];
                var    left   = (int)(PsbNumber)info["left"];
                Bitmap b      = new Bitmap(width, height, PixelFormat.Format32bppArgb);
#if USE_FASTBITMAP
                using (FastBitmap f = b.FastLock())
                {
                    f.CopyRegion(bmp, new Rectangle(left, top, width, height), new Rectangle(0, 0, b.Width, b.Height));
                }
#else
                Graphics g = Graphics.FromImage(b);
                //g.InterpolationMode = InterpolationMode.NearestNeighbor;
                //g.PixelOffsetMode = PixelOffsetMode.Half;
                g.DrawImage(bmp, new Rectangle(0, 0, b.Width, b.Height), new Rectangle(left, top, width, height),
                            GraphicsUnit.Pixel);
                g.Dispose();
#endif
                textures.Add(iconPair.Key, b);
            }

            bmp.Dispose();
            return(textures);
        }
Beispiel #4
0
        /// <summary>
        /// Link
        /// </summary>
        /// <param name="psb"></param>
        /// <param name="resx">advanced resource json(resx.jon)</param>
        /// <param name="baseDir"></param>
        internal static void Link(this PSB psb, PsbResourceJson resx, string baseDir)
        {
            if (resx.Resources == null)
            {
                return;
            }

            var context = FreeMount.CreateContext(resx.Context);

            if (psb.TypeHandler != null)
            {
                psb.TypeHandler.Link(psb, context, resx.Resources, baseDir);
            }
            else
            {
                PsbResHelper.LinkImages(psb, context, resx.Resources, baseDir);
            }
        }
Beispiel #5
0
        /// <summary>
        /// Save (most user friendly) images
        /// </summary>
        /// <param name="inputPath"></param>
        /// <param name="format"></param>
        public static void ExtractImageFiles(string inputPath, PsbImageFormat format = PsbImageFormat.png)
        {
            if (!File.Exists(inputPath))
            {
                return;
            }

            var name    = Path.GetFileNameWithoutExtension(inputPath);
            var dirPath = Path.Combine(Path.GetDirectoryName(inputPath), name);

            if (File.Exists(dirPath))
            {
                name    += "-resources";
                dirPath += "-resources";
            }

            if (!Directory.Exists(dirPath)) //ensure there is no file with same name!
            {
                Directory.CreateDirectory(dirPath);
            }

            var texExt    = format == PsbImageFormat.bmp ? ".bmp" : ".png";
            var texFormat = format.ToImageFormat();

            var psb = new PSB(inputPath);

            if (psb.Type == PsbType.Tachie)
            {
                var bitmaps = TextureCombiner.CombineTachie(psb);
                foreach (var kv in bitmaps)
                {
                    kv.Value.Save(Path.Combine(dirPath, $"{kv.Key}{texExt}"), texFormat);
                }
                return;
            }

            var texs = PsbResHelper.UnlinkImages(psb);

            foreach (var tex in texs)
            {
                tex.Save(Path.Combine(dirPath, tex.Tag + texExt), texFormat);
            }
        }
Beispiel #6
0
        /// <summary>
        /// Link Textures
        /// </summary>
        /// <param name="psb"></param>
        /// <param name="resPaths">resource paths</param>
        /// <param name="baseDir"></param>
        /// <param name="order">how to arrange images</param>
        /// <param name="isExternal">Whether this is an external texture PSB</param>
        public static void Link(this PSB psb, IList <string> resPaths, string baseDir = null,
                                PsbLinkOrderBy order = PsbLinkOrderBy.Convention, bool isExternal = false)
        {
            var context = FreeMount.CreateContext();

            if (psb.Type == PsbType.Motion)
            {
                PsbResHelper.LinkImages(psb, context, resPaths, baseDir, order, isExternal);
                return;
            }

            if (psb.TypeHandler != null)
            {
                psb.TypeHandler.Link(psb, context, resPaths, baseDir, order);
            }
            else
            {
                PsbResHelper.LinkImages(psb, context, resPaths, baseDir, order);
            }
        }
Beispiel #7
0
        public List <ImageMetadata> FindFontResources(PSB psb, bool deDuplication = true)
        {
            List <ImageMetadata> resList = new List <ImageMetadata>(psb.Resources.Count);

            if (psb.Objects == null || !psb.Objects.ContainsKey(Source) || !(psb.Objects[Source] is PsbList list))
            {
                return(resList);
            }

            foreach (var item in list)
            {
                if (!(item is PsbDictionary obj))
                {
                    continue;
                }

                //TODO: deDuplication for resource (besides pal)
                var md = PsbResHelper.GenerateImageMetadata(obj, null);
                resList.Add(md);
            }

            return(resList);
        }
Beispiel #8
0
 public virtual void Link(PSB psb, FreeMountContext context, IList <string> resPaths, string baseDir = null, PsbLinkOrderBy order = PsbLinkOrderBy.Convention)
 {
     PsbResHelper.LinkImages(psb, context, resPaths, baseDir, order);
 }
Beispiel #9
0
 public virtual Dictionary <string, string> OutputResources(PSB psb, FreeMountContext context, string name, string dirPath,
                                                            PsbExtractOption extractOption = PsbExtractOption.Original)
 {
     return(PsbResHelper.OutputImageResources(psb, context, name, dirPath, extractOption));
 }
Beispiel #10
0
 public virtual void UnlinkToFile(PSB psb, FreeMountContext context, string name, string dirPath, bool outputUnlinkedPsb = true,
                                  PsbLinkOrderBy order = PsbLinkOrderBy.Name)
 {
     PsbResHelper.UnlinkImagesToFile(psb, context, name, dirPath, outputUnlinkedPsb, order);
 }
Beispiel #11
0
 public virtual List <Bitmap> Unlink(PSB psb, PsbLinkOrderBy order = PsbLinkOrderBy.Name, bool disposeResInPsb = true)
 {
     return(PsbResHelper.UnlinkImages(psb, order, disposeResInPsb));
 }
Beispiel #12
0
 public virtual void Link(PSB psb, FreeMountContext context, IDictionary <string, string> resPaths, string baseDir = null)
 {
     PsbResHelper.LinkImages(psb, context, resPaths, baseDir);
 }
Beispiel #13
0
        internal static void OutputResources(PSB psb, FreeMountContext context, string filePath, PsbExtractOption extractOption = PsbExtractOption.Original,
                                             PsbImageFormat extractFormat = PsbImageFormat.png, bool useResx = true)
        {
            var             name    = Path.GetFileNameWithoutExtension(filePath);
            var             dirPath = Path.Combine(Path.GetDirectoryName(filePath), name);
            PsbResourceJson resx    = new PsbResourceJson(psb, context.Context);

            if (File.Exists(dirPath))
            {
                name    += "-resources";
                dirPath += "-resources";
            }

            var extraDir = Path.Combine(dirPath, Consts.ExtraResourceFolderName);

            if (!Directory.Exists(dirPath)) //ensure there is no file with same name!
            {
                if (psb.Resources.Count != 0)
                {
                    Directory.CreateDirectory(dirPath);
                }
            }

            if (psb.ExtraResources.Count > 0)
            {
                var extraDic = PsbResHelper.OutputExtraResources(psb, context, name, extraDir, out var flattenArrays, extractOption);
                resx.ExtraResources = extraDic;
                if (flattenArrays != null && flattenArrays.Count > 0)
                {
                    resx.ExtraFlattenArrays = flattenArrays;
                }
            }

            var resDictionary = psb.TypeHandler.OutputResources(psb, context, name, dirPath, extractOption);

            //MARK: We use `.resx.json` to distinguish from psbtools' `.res.json`
            if (useResx)
            {
                resx.Resources = resDictionary;
                resx.Context   = context.Context;
                string json;
                if (Consts.JsonArrayCollapse)
                {
                    json = ArrayCollapseJsonTextWriter.SerializeObject(resx);
                }
                else
                {
                    json = JsonConvert.SerializeObject(resx, Formatting.Indented);
                }
                File.WriteAllText(ChangeExtensionForOutputJson(filePath, ".resx.json"), json);
            }
            else
            {
                if (psb.ExtraResources.Count > 0)
                {
                    throw new NotSupportedException("PSBv4 cannot use legacy res.json format.");
                }
                File.WriteAllText(ChangeExtensionForOutputJson(filePath, ".res.json"),
                                  JsonConvert.SerializeObject(resDictionary.Values.ToList(), Formatting.Indented));
            }
        }
Beispiel #14
0
        /// <summary>
        /// Split textures into parts and save to files
        /// </summary>
        /// <param name="psb">PSB</param>
        /// <param name="path">Save directory</param>
        /// <param name="option">Save option</param>
        /// <param name="imageFormat">Save format</param>
        /// <param name="pixelFormat">When save to PSB special formats, specific pixel format to use</param>
        public static void SplitTextureToFiles(this PSB psb, string path, PsbExtractOption option = PsbExtractOption.Extract,
                                               PsbImageFormat imageFormat = PsbImageFormat.png, PsbPixelFormat pixelFormat = PsbPixelFormat.None)
        {
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }

            var source = (PsbDictionary)psb.Objects["source"];

            foreach (var texPair in source)
            {
                if (!(texPair.Value is PsbDictionary tex))
                {
                    continue;
                }

                var name = texPair.Key;
                if (!Directory.Exists(Path.Combine(path, name)))
                {
                    Directory.CreateDirectory(Path.Combine(path, name));
                }

                var icon    = (PsbDictionary)tex["icon"];
                var texture = (PsbDictionary)tex["texture"];

                //var mipmap = (PsbDictionary)texture["mipMap"]; //TODO: Mipmap?

                var pixel = texture[Consts.ResourceKey];
                if (pixel == null || !(pixel is PsbResource pixelRes))
                {
                    throw new PsbBadFormatException(PsbBadFormatReason.Resources,
                                                    "External Texture PSB is not supported. Please Link textures into PSB.");
                    return;
                }

                var md = PsbResHelper.GenerateImageMetadata(texture, pixelRes);
                md.Spec = psb.Platform; //Important
                Bitmap bmp = md.ToImage();

                foreach (var iconPair in icon)
                {
                    var    savePath = Path.Combine(path, name, iconPair.Key);
                    var    info     = (PsbDictionary)iconPair.Value;
                    var    width    = (int)(PsbNumber)info["width"];
                    var    height   = (int)(PsbNumber)info["height"];
                    var    top      = (int)(PsbNumber)info["top"];
                    var    left     = (int)(PsbNumber)info["left"];
                    var    attr     = (int)(PsbNumber)info["attr"];
                    Bitmap b        = new Bitmap(width, height, PixelFormat.Format32bppArgb);
#if USE_FASTBITMAP
                    using (FastBitmap f = b.FastLock())
                    {
                        f.CopyRegion(bmp, new Rectangle(left, top, width, height), new Rectangle(0, 0, b.Width, b.Height));
                    }
#else
                    Graphics g = Graphics.FromImage(b);
                    //g.InterpolationMode = InterpolationMode.NearestNeighbor;
                    //g.PixelOffsetMode = PixelOffsetMode.Half;
                    g.DrawImage(bmp, new Rectangle(0, 0, b.Width, b.Height), new Rectangle(left, top, width, height),
                                GraphicsUnit.Pixel);
                    g.Dispose();
#endif

                    switch (option)
                    {
                    case PsbExtractOption.Decompress:
                        File.WriteAllBytes(savePath + ".raw", RL.GetPixelBytesFromImage(b, pixelFormat));
                        break;

                    case PsbExtractOption.Compress:
                        File.WriteAllBytes(savePath + ".rl", RL.CompressImage(b, pixelFormat));
                        break;

                    case PsbExtractOption.Original:
                    case PsbExtractOption.Extract:
                    default:
                        switch (imageFormat)
                        {
                        case PsbImageFormat.bmp:
                            b.Save(savePath + ".bmp", ImageFormat.Bmp);
                            break;

                        case PsbImageFormat.png:
                        default:
                            b.Save(savePath + ".png", ImageFormat.Png);
                            //b.Save(savePath + $"_{attr}.png", ImageFormat.png);
                            break;
                        }

                        break;
                    }
                }

                bmp.Dispose();
            }
        }
Beispiel #15
0
        /// <summary>
        /// Compile Json to PSB
        /// </summary>
        /// <param name="inputJson">Json text</param>
        /// <param name="inputResJson">Resource Json text</param>
        /// <param name="baseDir">If resource Json uses relative paths (usually it does), specify the base dir</param>
        /// <param name="version">PSB version</param>
        /// <param name="cryptKey">CryptKey, use null for pure PSB</param>
        /// <param name="spec">PSB Platform</param>
        /// <param name="keepShell">If true, try to compress PSB to shell type (MDF/LZ4 etc.) specified in resx.json; otherwise just output PSB</param>
        /// <returns></returns>
        public static byte[] Compile(string inputJson, string inputResJson, string baseDir = null,
                                     ushort?version = null, uint?cryptKey  = null,
                                     PsbSpec?spec   = null, bool keepShell = true)
        {
            var context = FreeMount.CreateContext();
            //Parse
            PSB psb = Parse(inputJson, version ?? 3);

            //Link
            if (!string.IsNullOrWhiteSpace(inputResJson))
            {
                if (inputResJson.Trim().StartsWith("{")) //resx.json
                {
                    PsbResourceJson resx = JsonConvert.DeserializeObject <PsbResourceJson>(inputResJson);
                    if (resx.PsbType != null)
                    {
                        psb.Type = resx.PsbType.Value;
                    }

                    if (resx.PsbVersion != null && version == null)
                    {
                        psb.Header.Version = resx.PsbVersion.Value;
                    }

                    if (resx.Platform != null && spec == null)
                    {
                        spec = resx.Platform;
                    }

                    if (resx.CryptKey != null & cryptKey == null)
                    {
                        cryptKey = resx.CryptKey;
                    }

                    context = FreeMount.CreateContext(resx.Context);

                    if (resx.HasExtraResources)
                    {
                        PsbResHelper.LinkExtraResources(psb, context, resx.ExtraResources, resx.ExtraFlattenArrays, baseDir);
                    }

                    if (resx.ExternalTextures)
                    {
#if DEBUG
                        Console.WriteLine("[INFO] External Texture mode ON, no resource will be compiled.");
#endif
                    }
                    else
                    {
                        psb.Link(resx, baseDir);
                    }
                }
                else
                {
                    List <string> resources = JsonConvert.DeserializeObject <List <string> >(inputResJson);
                    psb.Link(resources, baseDir);
                }
            }

            //Build
            psb.Merge();
            if (spec != null && spec != psb.Platform)
            {
                psb.SwitchSpec(spec.Value, spec.Value.DefaultPixelFormat());
                psb.Merge();
            }

            var bytes = psb.Build();

            //Convert
            if (cryptKey != null)
            {
                bytes = PsbFile.EncodeToBytes(cryptKey.Value, bytes, EncodeMode.Encrypt, EncodePosition.Auto);
            }

            if (context.HasShell && keepShell)
            {
                using var outStream = context.PackToShell(new MemoryStream(bytes));
                bytes = outStream.ToArray();
            }

            return(bytes);
        }