1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

局ロゴの研究②

Last updated at Posted at 2025-08-14

前回、手作業で行った局ロゴデータの汎用PNG化を自動化。

局ロゴPNG化の自動化

.NET Frameworkのcscでも扱えるC#5にて作成。

コード例

logo2png.cs
using System;
using System.IO;
using System.Linq;
using System.Text;

class Program
{
    static void Main(string[] args)
    {
        // PLTEチャンクとtRNSチャンクのバイナリを繋げて入力(536バイト)
        byte[] fixedChunk = HexToBytes("00 00 01 80 50 4C…(中略)…80 80 CE B6 B1 6C");

        foreach (string inputPath in args)
        {
            if (Path.GetExtension(inputPath).ToLower() == ".png")
            {
                Console.WriteLine(".pngは除外: " + inputPath);
                continue;
            }

            string outputPath = inputPath + ".png";
            using (var reader = new BinaryReader(File.OpenRead(inputPath)))
            using (var writer = new BinaryWriter(File.Create(outputPath)))
            {
                // PNGヘッダー(8バイト)をそのままコピー
                writer.Write(reader.ReadBytes(8));

                while (reader.BaseStream.Position < reader.BaseStream.Length)
                {
                    // チャンク長(4バイト)
                    byte[] lengthBytes = reader.ReadBytes(4);
                    uint length = BitConverter.ToUInt32(lengthBytes.Reverse().ToArray(), 0);

                    // チャンクタイプ(4バイト)
                    byte[] typeBytes = reader.ReadBytes(4);
                    string type = Encoding.ASCII.GetString(typeBytes);

                    // チャンクデータ(lengthバイト)+CRC(4バイト)
                    byte[] dataBytes = reader.ReadBytes((int)length + 4);

                    // チャンク全体を出力
                    writer.Write(lengthBytes);
                    writer.Write(typeBytes);
                    writer.Write(dataBytes);

                    // IHDRの後に fixedChunk を挿入
                    if (type == "IHDR")
                    {
                        writer.Write(fixedChunk);
                    }
                }
            }

            Console.WriteLine("処理完了: " + Path.GetFileName(outputPath));
        }
    }

    static byte[] HexToBytes(string hex)
    {
        string[] parts = hex.Split(' ');
        byte[] bytes = new byte[parts.Length];
        for (int i = 0; i < parts.Length; i++)
        {
            bytes[i] = Convert.ToByte(parts[i], 16);
        }
        return bytes;
    }
}

バイナリ部分は、前回通りのPLTEチャンクの値とtRNSチャンクの値をそのまま繋げてスペース区切りで入力する。(改行もスペースに置換)

exeに生ロゴデータのファイルをドラッグ&ドロップすると、色情報付きのPNGファイルに変換できる。

おまけ

ロゴデータが蓄積されている「LogoData」ファイルを覗くと、生ロゴデータ(PNG構造)の羅列となっている。
これを1つずつバイナリエディタで分離すると生ロゴデータが手に入るが、これも自動化。

コード例

logodata2logo.cs
using System;
using System.IO;
using System.Text;

class Program
{
    static void Main(string[] args)
    {
        string inputPath = args[0];
        string outputDir = Path.Combine(Path.GetDirectoryName(inputPath), "Logo_" + Path.GetFileName(inputPath));
        Directory.CreateDirectory(outputDir);

        using (var br = new BinaryReader(File.OpenRead(inputPath)))
        {
            // ファイルヘッダー
            string type = Encoding.ASCII.GetString(br.ReadBytes(8));
            if (type != "LogoData")
            {
                Console.WriteLine("無効なファイル形式: " + inputPath);
                return;
            }

            uint version = br.ReadUInt32();
            uint numImages = br.ReadUInt32();

            for (uint i = 0; i < numImages; i++)
            {
                // ロゴヘッダー
                ushort networkID = br.ReadUInt16();
                ushort logoID = br.ReadUInt16();
                ushort logoVersion = br.ReadUInt16();
                byte logoType = br.ReadByte();
                br.ReadByte(); // Reserved1
                ushort dataSize = br.ReadUInt16();
                br.ReadBytes(6); // Reserved2
                ulong time = br.ReadUInt64();

                // PNGデータ
                byte[] pngData = br.ReadBytes(dataSize);

                // CRC(読み飛ばし)
                br.ReadUInt32();

                // ファイル生成
                string fileName = string.Format("{0:X4}_{1:X3}_{2:X3}_{3:X2}", networkID, logoID, logoVersion, logoType);
                string outputPath = Path.Combine(outputDir, fileName);
                File.WriteAllBytes(outputPath, pngData);

                // 更新日時を設定
                var fileTime = DateTime.FromFileTimeUtc((long)time * 10000000).AddHours(-9);
                File.SetLastWriteTime(outputPath, fileTime);

                Console.WriteLine("抽出: " + fileName);
            }
        }

        Console.WriteLine("抽出完了: " + outputDir);
    }
}

「LogoData」ファイルのドラッグ&ドロップで、生ロゴデータのファイルが「Logo_LogoData」フォルダに抽出される。これをさらにlogo2pngにかけると色情報付きのPNGファイルとなる。

(ファイル名と更新日時も、各ヘッダーの情報を基に設定。)

つづく…

制作協力:Copilot

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?