public static void ToStream(Stream writer, SubtitleSection section) { byte[] rawText = null; using (var content = new MemoryStream()) { foreach (var text in section.Texts) { SubtitleSectionText.ToStream(content, text, section.LanguageID == 7); } rawText = content.ToArray(); } writer.WriteBE(section.LanguageID); writer.WriteBE(section.StreamID); if (section.LanguageID == 1 || section.LanguageID == 7) { var total = 16 + rawText.Length + 4 + 4 + section.FontData?.Length ?? 0; total = ((total + 16 - 1) / 16) * 16; writer.WriteBE(total); writer.WriteBE(section.BaseTime); writer.Write(0u); writer.Write((uint)rawText.Length); writer.Write(rawText); //if (section.LanguageID == 7) { if (section.FontData == null) { writer.Write(0); } else { writer.Write(section.FontData.Length); writer.Write(section.FontData); } } writer.WriteOffset(16); } else { writer.WriteBE(section.Length); writer.WriteBE(section.BaseTime); writer.Write(section.RawData); } }
public static void ToStream(Stream writer, StreamSection packet) { switch (packet.Type) { case SectionType.Subtitle: SubtitleSection.ToStream(writer, (SubtitleSection)packet); break; case SectionType.EndOfStream: EndOfStreamSection.ToStream(writer, (EndOfStreamSection)packet); break; case SectionType.Raw: RawSection.ToStream(writer, (RawSection)packet); break; } }
public new static SubtitleSection FromStream(Stream reader) { var section = new SubtitleSection(); var basePosition = reader.Position; section.Offset = reader.Position; section.LanguageID = reader.ReadUInt16BE(); section.StreamID = reader.ReadUInt16BE(); section.Length = reader.ReadUInt32BE(); section.BaseTime = reader.ReadUInt32BE(); var endPosition = basePosition + section.Length; if (section.LanguageID == 1 || section.LanguageID == 7) { var dummy = reader.ReadUInt32(); Debug.Assert(dummy == 0); var dataLength = reader.ReadUInt32(); var textStart = reader.Position; while (reader.Position < textStart + dataLength) { var text = SubtitleSectionText.FromStream(reader); section.Texts.Add(text); } Debug.Assert(reader.Position == textStart + dataLength); var fontLength = reader.ReadUInt32(); section.FontData = reader.ReadBytes((int)fontLength); if (endPosition != reader.Position) { var rem = reader.ReadBytes((int)(endPosition - reader.Position)); Debug.Assert(rem.Count(x => x == 0) == rem.Length); } Debug.Assert(endPosition % 0x10 == 0); reader.Seek(endPosition, SeekOrigin.Begin); } else { section.RawData = reader.ReadBytes((int)(endPosition - reader.Position)); } return(section); }
public static StreamSection FromStream(Stream reader) { var id = reader.ReadUInt32BE() & 0xff; reader.Seek(-4, SeekOrigin.Current); switch (id) { case 0x04: return(SubtitleSection.FromStream(reader)); case 0xF0: return(EndOfStreamSection.FromStream(reader)); default: return(RawSection.FromStream(reader)); } }
private static void ApplyNewFont(SubtitleSection section) { var letters = section.Texts.SelectMany(x => x.TranslatedText).Where(x => x >= '가' && x <= '힣').Distinct().ToArray(); var start = section.FontData.Length / 144; start = 0x9000 + start + 1 + start / 255; start = 0x9001; var rs = new List <string>(); var rt = new List <string>(); foreach (var item in letters) { if ((start & 0xFF) == 0) { start++; } rs.Add(new string(item, 1)); rt.Add($"\\x{start++:X4}"); } for (int i = 0; i < section.Texts.Count; i++) { var buffer = new StringBuilder(section.Texts[i].TranslatedText); for (int j = 0; j < letters.Length; j++) { buffer.Replace(rs[j], rt[j]); } section.Texts[i].Text = " " + buffer.Replace(" ", " ").Replace("[NL]", "[NL] ").ToString(); } using (var bitmap = FontUtility.GenerateFontBitmap(letters)) { section.FontData = FontUtility.GetBytes(letters.Length, bitmap); } }
public static void ApplyTranslation(string originalPath, string outputPath) { var index = 0; var subtitleLocation = originalPath.Remove(originalPath.LastIndexOf('.')); var set = LoadSubtitle(index, subtitleLocation); var buffer = new Dictionary <long, byte[]>(); using (var output = File.Create(outputPath)) using (var input = File.OpenRead(originalPath)) { while (input.Position < input.Length) { var section = StreamSection.FromStream(input); switch (section.Type) { case SectionType.Raw: var rawSection = section as RawSection; using (var ms = new MemoryStream()) { RawSection.ToStream(ms, rawSection); AppendToBuffer(buffer, rawSection.First, ms.ToArray()); } break; case SectionType.EndOfStream: if (buffer.Count > 0) { var source = buffer.ToArray().OrderBy(x => x.Key); foreach (var item in source) { output.Write(item.Value); } buffer.Clear(); } EndOfStreamSection.ToStream(output, section as EndOfStreamSection); index++; set = LoadSubtitle(index, subtitleLocation); break; case SectionType.Subtitle: var subtitleSection = section as SubtitleSection; SubtitleSection loaded; using (var ms = new MemoryStream()) { if (set != null && set.TryGetValue(GetKey(subtitleSection), out loaded)) { if (loaded.Texts.Where(x => x.TranslatedText != null).Count() > 0) { var copy = loaded.Texts.ToArray(); for (int i = 0; i < copy.Length; i++) { loaded.Texts.Clear(); loaded.Texts.Add(copy[i]); loaded.BaseTime = copy[i].Start; SubtitleSection.ToStreamTranslated(ms, loaded); AppendToBuffer(buffer, loaded.BaseTime, ms.ToArray()); } } else { SubtitleSection.ToStream(ms, subtitleSection); AppendToBuffer(buffer, subtitleSection.BaseTime, ms.ToArray()); } } else { SubtitleSection.ToStream(ms, subtitleSection); AppendToBuffer(buffer, subtitleSection.BaseTime, ms.ToArray()); } } break; } } } }
private static long GetKey(SubtitleSection x) { return((x.BaseTime << 8) | x.LanguageID); }