From d5f25c3fccbd9da31175e6cc4928a1d2d6d15473 Mon Sep 17 00:00:00 2001
From: Claude
Date: Tue, 4 Nov 2025 20:31:17 +0000
Subject: [PATCH] Massive expansion of converter portfolio: Added 35 new file
converters
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This commit significantly expands ClipConvert's conversion capabilities from 23 to 58 converters, more than doubling the portfolio.
New Converters Added:
📄 RTF Document Support (3):
- RTF → PDF, DOCX, TXT
🖼️ Advanced Image Formats (12):
- GIF ↔ PNG, JPG
- TIFF ↔ PNG, JPG
- ICO ↔ PNG
- BMP → GIF, TIFF
- WEBP → PNG
🎵 Extended Audio Support (5):
- FLAC → MP3, WAV
- OGG → MP3
- AAC → MP3
- MP3 → FLAC
🎬 Video Format Conversions (5):
- AVI, MOV, MKV, WEBM → MP4
- MP4 → AVI
📝 Markdown Conversions (3):
- PDF, DOCX, HTML → Markdown
📊 Enhanced Data Exports (3):
- XLSX → JSON, XML
- CSV → JSON
📑 Document Conversions (4):
- HTML → DOCX
- TXT ↔ DOCX
Technical Changes:
- Updated FileTypeDetector to recognize all new formats
- Registered all 58 converters in App.xaml.cs
- Maintained consistent architecture using Strategy Pattern
- All converters follow async stream-based design
Supported Formats Now: 26 file types with 58 conversion paths
---
FileConvertor/App.xaml.cs | 58 +++++++++-
.../Core/Converters/AacToMp3Converter.cs | 24 ++++
.../Core/Converters/AviToMp4Converter.cs | 52 +++++++++
.../Core/Converters/BmpToGifConverter.cs | 25 +++++
.../Core/Converters/BmpToTiffConverter.cs | 25 +++++
.../Core/Converters/CsvToJsonConverter.cs | 88 +++++++++++++++
.../Converters/DocxToMarkdownConverter.cs | 67 +++++++++++
.../Core/Converters/DocxToTextConverter.cs | 29 +++++
.../Core/Converters/ExcelToJsonConverter.cs | 64 +++++++++++
.../Core/Converters/ExcelToXmlConverter.cs | 85 ++++++++++++++
.../Core/Converters/FlacToMp3Converter.cs | 24 ++++
.../Core/Converters/FlacToWavConverter.cs | 22 ++++
.../Core/Converters/GifToJpgConverter.cs | 25 +++++
.../Core/Converters/GifToPngConverter.cs | 26 +++++
.../Core/Converters/HtmlToDocxConverter.cs | 74 ++++++++++++
.../Converters/HtmlToMarkdownConverter.cs | 85 ++++++++++++++
.../Core/Converters/IcoToPngConverter.cs | 23 ++++
.../Core/Converters/JpgToGifConverter.cs | 25 +++++
.../Core/Converters/JpgToTiffConverter.cs | 25 +++++
.../Core/Converters/MkvToMp4Converter.cs | 49 ++++++++
.../Core/Converters/MovToMp4Converter.cs | 49 ++++++++
.../Core/Converters/Mp3ToFlacConverter.cs | 51 +++++++++
.../Core/Converters/Mp4ToAviConverter.cs | 49 ++++++++
.../Core/Converters/OggToMp3Converter.cs | 24 ++++
.../Core/Converters/PdfToMarkdownConverter.cs | 50 +++++++++
.../Core/Converters/PngToGifConverter.cs | 25 +++++
.../Core/Converters/PngToIcoConverter.cs | 35 ++++++
.../Core/Converters/PngToTiffConverter.cs | 25 +++++
.../Core/Converters/RtfToDocxConverter.cs | 98 ++++++++++++++++
.../Core/Converters/RtfToPdfConverter.cs | 105 ++++++++++++++++++
.../Core/Converters/RtfToTextConverter.cs | 93 ++++++++++++++++
.../Core/Converters/TextToDocxConverter.cs | 45 ++++++++
.../Core/Converters/TiffToJpgConverter.cs | 25 +++++
.../Core/Converters/TiffToPngConverter.cs | 25 +++++
.../Core/Converters/WebmToMp4Converter.cs | 49 ++++++++
.../Core/Converters/WebpToPngConverter.cs | 23 ++++
.../Core/Helpers/FileTypeDetector.cs | 20 +++-
37 files changed, 1676 insertions(+), 10 deletions(-)
create mode 100644 FileConvertor/Core/Converters/AacToMp3Converter.cs
create mode 100644 FileConvertor/Core/Converters/AviToMp4Converter.cs
create mode 100644 FileConvertor/Core/Converters/BmpToGifConverter.cs
create mode 100644 FileConvertor/Core/Converters/BmpToTiffConverter.cs
create mode 100644 FileConvertor/Core/Converters/CsvToJsonConverter.cs
create mode 100644 FileConvertor/Core/Converters/DocxToMarkdownConverter.cs
create mode 100644 FileConvertor/Core/Converters/DocxToTextConverter.cs
create mode 100644 FileConvertor/Core/Converters/ExcelToJsonConverter.cs
create mode 100644 FileConvertor/Core/Converters/ExcelToXmlConverter.cs
create mode 100644 FileConvertor/Core/Converters/FlacToMp3Converter.cs
create mode 100644 FileConvertor/Core/Converters/FlacToWavConverter.cs
create mode 100644 FileConvertor/Core/Converters/GifToJpgConverter.cs
create mode 100644 FileConvertor/Core/Converters/GifToPngConverter.cs
create mode 100644 FileConvertor/Core/Converters/HtmlToDocxConverter.cs
create mode 100644 FileConvertor/Core/Converters/HtmlToMarkdownConverter.cs
create mode 100644 FileConvertor/Core/Converters/IcoToPngConverter.cs
create mode 100644 FileConvertor/Core/Converters/JpgToGifConverter.cs
create mode 100644 FileConvertor/Core/Converters/JpgToTiffConverter.cs
create mode 100644 FileConvertor/Core/Converters/MkvToMp4Converter.cs
create mode 100644 FileConvertor/Core/Converters/MovToMp4Converter.cs
create mode 100644 FileConvertor/Core/Converters/Mp3ToFlacConverter.cs
create mode 100644 FileConvertor/Core/Converters/Mp4ToAviConverter.cs
create mode 100644 FileConvertor/Core/Converters/OggToMp3Converter.cs
create mode 100644 FileConvertor/Core/Converters/PdfToMarkdownConverter.cs
create mode 100644 FileConvertor/Core/Converters/PngToGifConverter.cs
create mode 100644 FileConvertor/Core/Converters/PngToIcoConverter.cs
create mode 100644 FileConvertor/Core/Converters/PngToTiffConverter.cs
create mode 100644 FileConvertor/Core/Converters/RtfToDocxConverter.cs
create mode 100644 FileConvertor/Core/Converters/RtfToPdfConverter.cs
create mode 100644 FileConvertor/Core/Converters/RtfToTextConverter.cs
create mode 100644 FileConvertor/Core/Converters/TextToDocxConverter.cs
create mode 100644 FileConvertor/Core/Converters/TiffToJpgConverter.cs
create mode 100644 FileConvertor/Core/Converters/TiffToPngConverter.cs
create mode 100644 FileConvertor/Core/Converters/WebmToMp4Converter.cs
create mode 100644 FileConvertor/Core/Converters/WebpToPngConverter.cs
diff --git a/FileConvertor/App.xaml.cs b/FileConvertor/App.xaml.cs
index c124263..316fbb1 100644
--- a/FileConvertor/App.xaml.cs
+++ b/FileConvertor/App.xaml.cs
@@ -61,8 +61,8 @@ private void ConfigureServices(IServiceCollection services)
services.AddSingleton(provider =>
{
var factory = new ConverterFactory(provider);
-
- // Register converter types instead of instances
+
+ // Register original converter types
factory.RegisterConverterType(typeof(TextToPdfConverter));
factory.RegisterConverterType(typeof(PngToJpgConverter));
factory.RegisterConverterType(typeof(ExcelToCsvConverter));
@@ -82,8 +82,58 @@ private void ConfigureServices(IServiceCollection services)
factory.RegisterConverterType(typeof(Mp4ToMp3Converter));
factory.RegisterConverterType(typeof(M4aToMp3Converter));
factory.RegisterConverterType(typeof(HeicToJpgConverter));
-
- Logger.Log(LogLevel.Info, "App", "Registered converter types for lazy loading");
+ factory.RegisterConverterType(typeof(WavToMp3Converter));
+
+ // Register RTF converters
+ factory.RegisterConverterType(typeof(RtfToPdfConverter));
+ factory.RegisterConverterType(typeof(RtfToDocxConverter));
+ factory.RegisterConverterType(typeof(RtfToTextConverter));
+
+ // Register advanced image converters
+ factory.RegisterConverterType(typeof(GifToPngConverter));
+ factory.RegisterConverterType(typeof(GifToJpgConverter));
+ factory.RegisterConverterType(typeof(PngToGifConverter));
+ factory.RegisterConverterType(typeof(JpgToGifConverter));
+ factory.RegisterConverterType(typeof(BmpToGifConverter));
+ factory.RegisterConverterType(typeof(TiffToPngConverter));
+ factory.RegisterConverterType(typeof(TiffToJpgConverter));
+ factory.RegisterConverterType(typeof(PngToTiffConverter));
+ factory.RegisterConverterType(typeof(JpgToTiffConverter));
+ factory.RegisterConverterType(typeof(BmpToTiffConverter));
+ factory.RegisterConverterType(typeof(PngToIcoConverter));
+ factory.RegisterConverterType(typeof(IcoToPngConverter));
+ factory.RegisterConverterType(typeof(WebpToPngConverter));
+
+ // Register additional audio converters
+ factory.RegisterConverterType(typeof(FlacToMp3Converter));
+ factory.RegisterConverterType(typeof(FlacToWavConverter));
+ factory.RegisterConverterType(typeof(OggToMp3Converter));
+ factory.RegisterConverterType(typeof(AacToMp3Converter));
+ factory.RegisterConverterType(typeof(Mp3ToFlacConverter));
+
+ // Register video converters
+ factory.RegisterConverterType(typeof(AviToMp4Converter));
+ factory.RegisterConverterType(typeof(MovToMp4Converter));
+ factory.RegisterConverterType(typeof(MkvToMp4Converter));
+ factory.RegisterConverterType(typeof(WebmToMp4Converter));
+ factory.RegisterConverterType(typeof(Mp4ToAviConverter));
+
+ // Register Markdown converters
+ factory.RegisterConverterType(typeof(PdfToMarkdownConverter));
+ factory.RegisterConverterType(typeof(DocxToMarkdownConverter));
+ factory.RegisterConverterType(typeof(HtmlToMarkdownConverter));
+
+ // Register Excel advanced converters
+ factory.RegisterConverterType(typeof(ExcelToJsonConverter));
+ factory.RegisterConverterType(typeof(ExcelToXmlConverter));
+ factory.RegisterConverterType(typeof(CsvToJsonConverter));
+
+ // Register document converters
+ factory.RegisterConverterType(typeof(HtmlToDocxConverter));
+ factory.RegisterConverterType(typeof(TextToDocxConverter));
+ factory.RegisterConverterType(typeof(DocxToTextConverter));
+
+ Logger.Log(LogLevel.Info, "App", "Registered 58 converter types for lazy loading");
return factory;
});
diff --git a/FileConvertor/Core/Converters/AacToMp3Converter.cs b/FileConvertor/Core/Converters/AacToMp3Converter.cs
new file mode 100644
index 0000000..06df14d
--- /dev/null
+++ b/FileConvertor/Core/Converters/AacToMp3Converter.cs
@@ -0,0 +1,24 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using NAudio.Wave;
+using NAudio.Lame;
+
+namespace FileConvertor.Core.Converters
+{
+ public class AacToMp3Converter : BaseConverter
+ {
+ public override string SourceFormat => "aac";
+ public override string TargetFormat => "mp3";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ await Task.Run(() =>
+ {
+ using var reader = new StreamMediaFoundationReader(sourceStream);
+ using var writer = new LameMP3FileWriter(targetStream, reader.WaveFormat, 128);
+ reader.CopyTo(writer);
+ });
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/AviToMp4Converter.cs b/FileConvertor/Core/Converters/AviToMp4Converter.cs
new file mode 100644
index 0000000..da055a8
--- /dev/null
+++ b/FileConvertor/Core/Converters/AviToMp4Converter.cs
@@ -0,0 +1,52 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using Xabe.FFmpeg;
+
+namespace FileConvertor.Core.Converters
+{
+ public class AviToMp4Converter : BaseConverter
+ {
+ public override string SourceFormat => "avi";
+ public override string TargetFormat => "mp4";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ var tempInput = Path.GetTempFileName();
+ var tempOutput = Path.GetTempFileName();
+
+ try
+ {
+ // Write source stream to temp file
+ using (var fileStream = File.Create(tempInput))
+ {
+ await sourceStream.CopyToAsync(fileStream);
+ }
+
+ // Convert using FFmpeg
+ var mediaInfo = await FFmpeg.GetMediaInfo(tempInput);
+ var conversion = FFmpeg.Conversions.New();
+
+ if (mediaInfo.VideoStreams.Any())
+ conversion.AddStream(mediaInfo.VideoStreams.First());
+
+ if (mediaInfo.AudioStreams.Any())
+ conversion.AddStream(mediaInfo.AudioStreams.First());
+
+ await conversion
+ .SetOutput(tempOutput)
+ .Start();
+
+ // Copy result to target stream
+ using var outputFile = File.OpenRead(tempOutput);
+ await outputFile.CopyToAsync(targetStream);
+ }
+ finally
+ {
+ if (File.Exists(tempInput)) File.Delete(tempInput);
+ if (File.Exists(tempOutput)) File.Delete(tempOutput);
+ }
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/BmpToGifConverter.cs b/FileConvertor/Core/Converters/BmpToGifConverter.cs
new file mode 100644
index 0000000..b8c9ff3
--- /dev/null
+++ b/FileConvertor/Core/Converters/BmpToGifConverter.cs
@@ -0,0 +1,25 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using System.Windows.Media.Imaging;
+
+namespace FileConvertor.Core.Converters
+{
+ public class BmpToGifConverter : BaseConverter
+ {
+ public override string SourceFormat => "bmp";
+ public override string TargetFormat => "gif";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ await Task.Run(() =>
+ {
+ var decoder = new BmpBitmapDecoder(sourceStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
+ var encoder = new GifBitmapEncoder();
+
+ encoder.Frames.Add(BitmapFrame.Create(decoder.Frames[0]));
+ encoder.Save(targetStream);
+ });
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/BmpToTiffConverter.cs b/FileConvertor/Core/Converters/BmpToTiffConverter.cs
new file mode 100644
index 0000000..0885ede
--- /dev/null
+++ b/FileConvertor/Core/Converters/BmpToTiffConverter.cs
@@ -0,0 +1,25 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using System.Windows.Media.Imaging;
+
+namespace FileConvertor.Core.Converters
+{
+ public class BmpToTiffConverter : BaseConverter
+ {
+ public override string SourceFormat => "bmp";
+ public override string TargetFormat => "tiff";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ await Task.Run(() =>
+ {
+ var decoder = new BmpBitmapDecoder(sourceStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
+ var encoder = new TiffBitmapEncoder { Compression = TiffCompressOption.Zip };
+
+ encoder.Frames.Add(BitmapFrame.Create(decoder.Frames[0]));
+ encoder.Save(targetStream);
+ });
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/CsvToJsonConverter.cs b/FileConvertor/Core/Converters/CsvToJsonConverter.cs
new file mode 100644
index 0000000..9139746
--- /dev/null
+++ b/FileConvertor/Core/Converters/CsvToJsonConverter.cs
@@ -0,0 +1,88 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Text.Json;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+
+namespace FileConvertor.Core.Converters
+{
+ public class CsvToJsonConverter : BaseConverter
+ {
+ public override string SourceFormat => "csv";
+ public override string TargetFormat => "json";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ await Task.Run(() =>
+ {
+ using var reader = new StreamReader(sourceStream, Encoding.UTF8);
+ var data = new List>();
+
+ // Read header
+ var headerLine = reader.ReadLine();
+ if (string.IsNullOrEmpty(headerLine))
+ return;
+
+ var headers = ParseCsvLine(headerLine);
+
+ // Read data
+ while (!reader.EndOfStream)
+ {
+ var line = reader.ReadLine();
+ if (string.IsNullOrEmpty(line))
+ continue;
+
+ var values = ParseCsvLine(line);
+ var rowData = new Dictionary();
+
+ for (int i = 0; i < Math.Min(headers.Count, values.Count); i++)
+ {
+ rowData[headers[i]] = values[i];
+ }
+
+ data.Add(rowData);
+ }
+
+ // Write JSON
+ var json = JsonSerializer.Serialize(data, new JsonSerializerOptions
+ {
+ WriteIndented = true
+ });
+
+ using var writer = new StreamWriter(targetStream, Encoding.UTF8);
+ writer.Write(json);
+ writer.Flush();
+ });
+ }
+
+ private List ParseCsvLine(string line)
+ {
+ var values = new List();
+ var currentValue = new StringBuilder();
+ bool inQuotes = false;
+
+ for (int i = 0; i < line.Length; i++)
+ {
+ char c = line[i];
+
+ if (c == '"')
+ {
+ inQuotes = !inQuotes;
+ }
+ else if (c == ',' && !inQuotes)
+ {
+ values.Add(currentValue.ToString());
+ currentValue.Clear();
+ }
+ else
+ {
+ currentValue.Append(c);
+ }
+ }
+
+ values.Add(currentValue.ToString());
+ return values;
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/DocxToMarkdownConverter.cs b/FileConvertor/Core/Converters/DocxToMarkdownConverter.cs
new file mode 100644
index 0000000..58de2a0
--- /dev/null
+++ b/FileConvertor/Core/Converters/DocxToMarkdownConverter.cs
@@ -0,0 +1,67 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Threading.Tasks;
+using DocumentFormat.OpenXml.Packaging;
+using DocumentFormat.OpenXml.Wordprocessing;
+
+namespace FileConvertor.Core.Converters
+{
+ public class DocxToMarkdownConverter : BaseConverter
+ {
+ public override string SourceFormat => "docx";
+ public override string TargetFormat => "md";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ await Task.Run(() =>
+ {
+ var markdown = new StringBuilder();
+
+ using (var wordDocument = WordprocessingDocument.Open(sourceStream, false))
+ {
+ var body = wordDocument.MainDocumentPart?.Document.Body;
+
+ if (body != null)
+ {
+ foreach (var element in body.Elements())
+ {
+ if (element is Paragraph paragraph)
+ {
+ var text = paragraph.InnerText;
+
+ if (!string.IsNullOrWhiteSpace(text))
+ {
+ // Check if it's a heading
+ var styleId = paragraph.ParagraphProperties?.ParagraphStyleId?.Val?.Value;
+
+ if (styleId != null && styleId.StartsWith("Heading"))
+ {
+ var level = 1;
+ if (styleId.Length > 7 && char.IsDigit(styleId[7]))
+ {
+ level = int.Parse(styleId[7].ToString());
+ }
+
+ markdown.AppendLine($"{new string('#', level)} {text}");
+ }
+ else
+ {
+ markdown.AppendLine(text);
+ }
+
+ markdown.AppendLine();
+ }
+ }
+ }
+ }
+ }
+
+ // Write markdown to stream
+ using var writer = new StreamWriter(targetStream, Encoding.UTF8);
+ writer.Write(markdown.ToString().TrimEnd());
+ writer.Flush();
+ });
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/DocxToTextConverter.cs b/FileConvertor/Core/Converters/DocxToTextConverter.cs
new file mode 100644
index 0000000..f14d384
--- /dev/null
+++ b/FileConvertor/Core/Converters/DocxToTextConverter.cs
@@ -0,0 +1,29 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Threading.Tasks;
+using DocumentFormat.OpenXml.Packaging;
+
+namespace FileConvertor.Core.Converters
+{
+ public class DocxToTextConverter : BaseConverter
+ {
+ public override string SourceFormat => "docx";
+ public override string TargetFormat => "txt";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ await Task.Run(() =>
+ {
+ using var wordDocument = WordprocessingDocument.Open(sourceStream, false);
+ var body = wordDocument.MainDocumentPart?.Document.Body;
+
+ var text = body?.InnerText ?? string.Empty;
+
+ using var writer = new StreamWriter(targetStream, Encoding.UTF8);
+ writer.Write(text);
+ writer.Flush();
+ });
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/ExcelToJsonConverter.cs b/FileConvertor/Core/Converters/ExcelToJsonConverter.cs
new file mode 100644
index 0000000..607a141
--- /dev/null
+++ b/FileConvertor/Core/Converters/ExcelToJsonConverter.cs
@@ -0,0 +1,64 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Text.Json;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using ClosedXML.Excel;
+
+namespace FileConvertor.Core.Converters
+{
+ public class ExcelToJsonConverter : BaseConverter
+ {
+ public override string SourceFormat => "xlsx";
+ public override string TargetFormat => "json";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ await Task.Run(() =>
+ {
+ using var workbook = new XLWorkbook(sourceStream);
+ var worksheet = workbook.Worksheet(1);
+
+ var data = new List>();
+ var headerRow = worksheet.Row(1);
+ var headers = new List();
+
+ // Get headers
+ foreach (var cell in headerRow.CellsUsed())
+ {
+ headers.Add(cell.GetValue());
+ }
+
+ // Get data rows
+ foreach (var row in worksheet.RowsUsed().Skip(1))
+ {
+ var rowData = new Dictionary();
+ var colIndex = 0;
+
+ foreach (var cell in row.CellsUsed())
+ {
+ if (colIndex < headers.Count)
+ {
+ var value = cell.Value;
+ rowData[headers[colIndex]] = value.IsBlank ? null : value.ToString();
+ }
+ colIndex++;
+ }
+
+ data.Add(rowData);
+ }
+
+ // Write JSON
+ var json = JsonSerializer.Serialize(data, new JsonSerializerOptions
+ {
+ WriteIndented = true
+ });
+
+ using var writer = new StreamWriter(targetStream, Encoding.UTF8);
+ writer.Write(json);
+ writer.Flush();
+ });
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/ExcelToXmlConverter.cs b/FileConvertor/Core/Converters/ExcelToXmlConverter.cs
new file mode 100644
index 0000000..a52c77c
--- /dev/null
+++ b/FileConvertor/Core/Converters/ExcelToXmlConverter.cs
@@ -0,0 +1,85 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Threading.Tasks;
+using System.Xml;
+using ClosedXML.Excel;
+
+namespace FileConvertor.Core.Converters
+{
+ public class ExcelToXmlConverter : BaseConverter
+ {
+ public override string SourceFormat => "xlsx";
+ public override string TargetFormat => "xml";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ await Task.Run(() =>
+ {
+ using var workbook = new XLWorkbook(sourceStream);
+ var worksheet = workbook.Worksheet(1);
+
+ var settings = new XmlWriterSettings
+ {
+ Indent = true,
+ Encoding = Encoding.UTF8
+ };
+
+ using var writer = XmlWriter.Create(targetStream, settings);
+
+ writer.WriteStartDocument();
+ writer.WriteStartElement("Workbook");
+ writer.WriteStartElement("Worksheet");
+
+ var headerRow = worksheet.Row(1);
+ var headers = new System.Collections.Generic.List();
+
+ // Get headers
+ foreach (var cell in headerRow.CellsUsed())
+ {
+ headers.Add(cell.GetValue());
+ }
+
+ // Write rows
+ foreach (var row in worksheet.RowsUsed().Skip(1))
+ {
+ writer.WriteStartElement("Row");
+
+ var colIndex = 0;
+ foreach (var cell in row.CellsUsed())
+ {
+ if (colIndex < headers.Count)
+ {
+ writer.WriteStartElement(SanitizeXmlName(headers[colIndex]));
+ writer.WriteString(cell.GetValue());
+ writer.WriteEndElement();
+ }
+ colIndex++;
+ }
+
+ writer.WriteEndElement(); // Row
+ }
+
+ writer.WriteEndElement(); // Worksheet
+ writer.WriteEndElement(); // Workbook
+ writer.WriteEndDocument();
+ });
+ }
+
+ private string SanitizeXmlName(string name)
+ {
+ // Replace invalid XML characters
+ var sanitized = name.Replace(" ", "_")
+ .Replace("-", "_")
+ .Replace(".", "_");
+
+ // Ensure it starts with a letter or underscore
+ if (!char.IsLetter(sanitized[0]) && sanitized[0] != '_')
+ {
+ sanitized = "_" + sanitized;
+ }
+
+ return sanitized;
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/FlacToMp3Converter.cs b/FileConvertor/Core/Converters/FlacToMp3Converter.cs
new file mode 100644
index 0000000..6744a06
--- /dev/null
+++ b/FileConvertor/Core/Converters/FlacToMp3Converter.cs
@@ -0,0 +1,24 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using NAudio.Wave;
+using NAudio.Lame;
+
+namespace FileConvertor.Core.Converters
+{
+ public class FlacToMp3Converter : BaseConverter
+ {
+ public override string SourceFormat => "flac";
+ public override string TargetFormat => "mp3";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ await Task.Run(() =>
+ {
+ using var reader = new StreamMediaFoundationReader(sourceStream);
+ using var writer = new LameMP3FileWriter(targetStream, reader.WaveFormat, 128);
+ reader.CopyTo(writer);
+ });
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/FlacToWavConverter.cs b/FileConvertor/Core/Converters/FlacToWavConverter.cs
new file mode 100644
index 0000000..2102f00
--- /dev/null
+++ b/FileConvertor/Core/Converters/FlacToWavConverter.cs
@@ -0,0 +1,22 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using NAudio.Wave;
+
+namespace FileConvertor.Core.Converters
+{
+ public class FlacToWavConverter : BaseConverter
+ {
+ public override string SourceFormat => "flac";
+ public override string TargetFormat => "wav";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ await Task.Run(() =>
+ {
+ using var reader = new StreamMediaFoundationReader(sourceStream);
+ WaveFileWriter.WriteWavFileToStream(targetStream, reader);
+ });
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/GifToJpgConverter.cs b/FileConvertor/Core/Converters/GifToJpgConverter.cs
new file mode 100644
index 0000000..0367c8d
--- /dev/null
+++ b/FileConvertor/Core/Converters/GifToJpgConverter.cs
@@ -0,0 +1,25 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using System.Windows.Media.Imaging;
+
+namespace FileConvertor.Core.Converters
+{
+ public class GifToJpgConverter : BaseConverter
+ {
+ public override string SourceFormat => "gif";
+ public override string TargetFormat => "jpg";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ await Task.Run(() =>
+ {
+ var decoder = new GifBitmapDecoder(sourceStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
+ var encoder = new JpegBitmapEncoder { QualityLevel = 90 };
+
+ encoder.Frames.Add(BitmapFrame.Create(decoder.Frames[0]));
+ encoder.Save(targetStream);
+ });
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/GifToPngConverter.cs b/FileConvertor/Core/Converters/GifToPngConverter.cs
new file mode 100644
index 0000000..6079dfe
--- /dev/null
+++ b/FileConvertor/Core/Converters/GifToPngConverter.cs
@@ -0,0 +1,26 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using System.Windows.Media.Imaging;
+
+namespace FileConvertor.Core.Converters
+{
+ public class GifToPngConverter : BaseConverter
+ {
+ public override string SourceFormat => "gif";
+ public override string TargetFormat => "png";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ await Task.Run(() =>
+ {
+ var decoder = new GifBitmapDecoder(sourceStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
+ var encoder = new PngBitmapEncoder();
+
+ // Convert first frame (for animated GIFs, convert first frame)
+ encoder.Frames.Add(BitmapFrame.Create(decoder.Frames[0]));
+ encoder.Save(targetStream);
+ });
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/HtmlToDocxConverter.cs b/FileConvertor/Core/Converters/HtmlToDocxConverter.cs
new file mode 100644
index 0000000..6f4c220
--- /dev/null
+++ b/FileConvertor/Core/Converters/HtmlToDocxConverter.cs
@@ -0,0 +1,74 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using DocumentFormat.OpenXml;
+using DocumentFormat.OpenXml.Packaging;
+using DocumentFormat.OpenXml.Wordprocessing;
+
+namespace FileConvertor.Core.Converters
+{
+ public class HtmlToDocxConverter : BaseConverter
+ {
+ public override string SourceFormat => "html";
+ public override string TargetFormat => "docx";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ await Task.Run(() =>
+ {
+ using var reader = new StreamReader(sourceStream, Encoding.UTF8);
+ var html = reader.ReadToEnd();
+
+ // Strip HTML tags for basic conversion
+ var plainText = StripHtmlTags(html);
+
+ // Create DOCX
+ using var wordDocument = WordprocessingDocument.Create(targetStream, WordprocessingDocumentType.Document);
+ wordDocument.AddMainDocumentPart();
+ var mainPart = wordDocument.MainDocumentPart!;
+
+ mainPart.Document = new Document();
+ var body = new Body();
+
+ // Split into paragraphs
+ var lines = plainText.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
+ foreach (var line in lines)
+ {
+ if (!string.IsNullOrWhiteSpace(line))
+ {
+ var paragraph = new Paragraph();
+ var run = new Run();
+ run.Append(new Text(line.Trim()));
+ paragraph.Append(run);
+ body.Append(paragraph);
+ }
+ }
+
+ mainPart.Document.Append(body);
+ mainPart.Document.Save();
+ });
+ }
+
+ private string StripHtmlTags(string html)
+ {
+ // Remove script and style tags with content
+ html = Regex.Replace(html, @"", "", RegexOptions.Singleline | RegexOptions.IgnoreCase);
+ html = Regex.Replace(html, @"", "", RegexOptions.Singleline | RegexOptions.IgnoreCase);
+
+ // Convert line breaks
+ html = Regex.Replace(html, @"
", "\n", RegexOptions.IgnoreCase);
+ html = Regex.Replace(html, @"
", "\n", RegexOptions.IgnoreCase);
+ html = Regex.Replace(html, @"", "\n", RegexOptions.IgnoreCase);
+
+ // Remove all HTML tags
+ html = Regex.Replace(html, @"<[^>]+>", "");
+
+ // Decode HTML entities
+ html = System.Net.WebUtility.HtmlDecode(html);
+
+ return html;
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/HtmlToMarkdownConverter.cs b/FileConvertor/Core/Converters/HtmlToMarkdownConverter.cs
new file mode 100644
index 0000000..1c41123
--- /dev/null
+++ b/FileConvertor/Core/Converters/HtmlToMarkdownConverter.cs
@@ -0,0 +1,85 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+
+namespace FileConvertor.Core.Converters
+{
+ public class HtmlToMarkdownConverter : BaseConverter
+ {
+ public override string SourceFormat => "html";
+ public override string TargetFormat => "md";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ await Task.Run(() =>
+ {
+ using var reader = new StreamReader(sourceStream, Encoding.UTF8);
+ var html = reader.ReadToEnd();
+
+ var markdown = ConvertHtmlToMarkdown(html);
+
+ using var writer = new StreamWriter(targetStream, Encoding.UTF8);
+ writer.Write(markdown);
+ writer.Flush();
+ });
+ }
+
+ private string ConvertHtmlToMarkdown(string html)
+ {
+ var markdown = html;
+
+ // Convert headings
+ markdown = Regex.Replace(markdown, @"]*>(.*?)
", "# $1\n", RegexOptions.Singleline | RegexOptions.IgnoreCase);
+ markdown = Regex.Replace(markdown, @"]*>(.*?)
", "## $1\n", RegexOptions.Singleline | RegexOptions.IgnoreCase);
+ markdown = Regex.Replace(markdown, @"]*>(.*?)
", "### $1\n", RegexOptions.Singleline | RegexOptions.IgnoreCase);
+ markdown = Regex.Replace(markdown, @"]*>(.*?)
", "#### $1\n", RegexOptions.Singleline | RegexOptions.IgnoreCase);
+ markdown = Regex.Replace(markdown, @"]*>(.*?)
", "##### $1\n", RegexOptions.Singleline | RegexOptions.IgnoreCase);
+ markdown = Regex.Replace(markdown, @"]*>(.*?)
", "###### $1\n", RegexOptions.Singleline | RegexOptions.IgnoreCase);
+
+ // Convert bold
+ markdown = Regex.Replace(markdown, @"]*>(.*?)", "**$1**", RegexOptions.Singleline | RegexOptions.IgnoreCase);
+ markdown = Regex.Replace(markdown, @"]*>(.*?)", "**$1**", RegexOptions.Singleline | RegexOptions.IgnoreCase);
+
+ // Convert italic
+ markdown = Regex.Replace(markdown, @"]*>(.*?)", "*$1*", RegexOptions.Singleline | RegexOptions.IgnoreCase);
+ markdown = Regex.Replace(markdown, @"]*>(.*?)", "*$1*", RegexOptions.Singleline | RegexOptions.IgnoreCase);
+
+ // Convert links
+ markdown = Regex.Replace(markdown, @"]*href=[""']([^""']*)[""'][^>]*>(.*?)", "[$2]($1)", RegexOptions.Singleline | RegexOptions.IgnoreCase);
+
+ // Convert images
+ markdown = Regex.Replace(markdown, @"
]*src=[""']([^""']*)[""'][^>]*alt=[""']([^""']*)[""'][^>]*>", "", RegexOptions.IgnoreCase);
+ markdown = Regex.Replace(markdown, @"
]*src=[""']([^""']*)[""'][^>]*>", "", RegexOptions.IgnoreCase);
+
+ // Convert lists
+ markdown = Regex.Replace(markdown, @"]*>", "", RegexOptions.IgnoreCase);
+ markdown = Regex.Replace(markdown, @"
", "\n", RegexOptions.IgnoreCase);
+ markdown = Regex.Replace(markdown, @"]*>", "", RegexOptions.IgnoreCase);
+ markdown = Regex.Replace(markdown, @"
", "\n", RegexOptions.IgnoreCase);
+ markdown = Regex.Replace(markdown, @"]*>(.*?)", "- $1\n", RegexOptions.Singleline | RegexOptions.IgnoreCase);
+
+ // Convert paragraphs
+ markdown = Regex.Replace(markdown, @"]*>(.*?)
", "$1\n\n", RegexOptions.Singleline | RegexOptions.IgnoreCase);
+
+ // Convert line breaks
+ markdown = Regex.Replace(markdown, @"
", "\n", RegexOptions.IgnoreCase);
+
+ // Convert code
+ markdown = Regex.Replace(markdown, @"]*>(.*?)", "`$1`", RegexOptions.Singleline | RegexOptions.IgnoreCase);
+ markdown = Regex.Replace(markdown, @"]*>(.*?)
", "```\n$1\n```\n", RegexOptions.Singleline | RegexOptions.IgnoreCase);
+
+ // Remove remaining HTML tags
+ markdown = Regex.Replace(markdown, @"<[^>]+>", "", RegexOptions.Singleline);
+
+ // Decode HTML entities
+ markdown = System.Net.WebUtility.HtmlDecode(markdown);
+
+ // Clean up extra whitespace
+ markdown = Regex.Replace(markdown, @"\n{3,}", "\n\n");
+
+ return markdown.Trim();
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/IcoToPngConverter.cs b/FileConvertor/Core/Converters/IcoToPngConverter.cs
new file mode 100644
index 0000000..5f8b3c9
--- /dev/null
+++ b/FileConvertor/Core/Converters/IcoToPngConverter.cs
@@ -0,0 +1,23 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using SixLabors.ImageSharp;
+using SixLabors.ImageSharp.Formats.Png;
+
+namespace FileConvertor.Core.Converters
+{
+ public class IcoToPngConverter : BaseConverter
+ {
+ public override string SourceFormat => "ico";
+ public override string TargetFormat => "png";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ await Task.Run(() =>
+ {
+ using var image = Image.Load(sourceStream);
+ image.Save(targetStream, new PngEncoder());
+ });
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/JpgToGifConverter.cs b/FileConvertor/Core/Converters/JpgToGifConverter.cs
new file mode 100644
index 0000000..92481cb
--- /dev/null
+++ b/FileConvertor/Core/Converters/JpgToGifConverter.cs
@@ -0,0 +1,25 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using System.Windows.Media.Imaging;
+
+namespace FileConvertor.Core.Converters
+{
+ public class JpgToGifConverter : BaseConverter
+ {
+ public override string SourceFormat => "jpg";
+ public override string TargetFormat => "gif";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ await Task.Run(() =>
+ {
+ var decoder = new JpegBitmapDecoder(sourceStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
+ var encoder = new GifBitmapEncoder();
+
+ encoder.Frames.Add(BitmapFrame.Create(decoder.Frames[0]));
+ encoder.Save(targetStream);
+ });
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/JpgToTiffConverter.cs b/FileConvertor/Core/Converters/JpgToTiffConverter.cs
new file mode 100644
index 0000000..166e8d6
--- /dev/null
+++ b/FileConvertor/Core/Converters/JpgToTiffConverter.cs
@@ -0,0 +1,25 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using System.Windows.Media.Imaging;
+
+namespace FileConvertor.Core.Converters
+{
+ public class JpgToTiffConverter : BaseConverter
+ {
+ public override string SourceFormat => "jpg";
+ public override string TargetFormat => "tiff";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ await Task.Run(() =>
+ {
+ var decoder = new JpegBitmapDecoder(sourceStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
+ var encoder = new TiffBitmapEncoder { Compression = TiffCompressOption.Zip };
+
+ encoder.Frames.Add(BitmapFrame.Create(decoder.Frames[0]));
+ encoder.Save(targetStream);
+ });
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/MkvToMp4Converter.cs b/FileConvertor/Core/Converters/MkvToMp4Converter.cs
new file mode 100644
index 0000000..335c9e8
--- /dev/null
+++ b/FileConvertor/Core/Converters/MkvToMp4Converter.cs
@@ -0,0 +1,49 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using Xabe.FFmpeg;
+
+namespace FileConvertor.Core.Converters
+{
+ public class MkvToMp4Converter : BaseConverter
+ {
+ public override string SourceFormat => "mkv";
+ public override string TargetFormat => "mp4";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ var tempInput = Path.GetTempFileName();
+ var tempOutput = Path.GetTempFileName();
+
+ try
+ {
+ using (var fileStream = File.Create(tempInput))
+ {
+ await sourceStream.CopyToAsync(fileStream);
+ }
+
+ var mediaInfo = await FFmpeg.GetMediaInfo(tempInput);
+ var conversion = FFmpeg.Conversions.New();
+
+ if (mediaInfo.VideoStreams.Any())
+ conversion.AddStream(mediaInfo.VideoStreams.First());
+
+ if (mediaInfo.AudioStreams.Any())
+ conversion.AddStream(mediaInfo.AudioStreams.First());
+
+ await conversion
+ .SetOutput(tempOutput)
+ .Start();
+
+ using var outputFile = File.OpenRead(tempOutput);
+ await outputFile.CopyToAsync(targetStream);
+ }
+ finally
+ {
+ if (File.Exists(tempInput)) File.Delete(tempInput);
+ if (File.Exists(tempOutput)) File.Delete(tempOutput);
+ }
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/MovToMp4Converter.cs b/FileConvertor/Core/Converters/MovToMp4Converter.cs
new file mode 100644
index 0000000..83ae331
--- /dev/null
+++ b/FileConvertor/Core/Converters/MovToMp4Converter.cs
@@ -0,0 +1,49 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using Xabe.FFmpeg;
+
+namespace FileConvertor.Core.Converters
+{
+ public class MovToMp4Converter : BaseConverter
+ {
+ public override string SourceFormat => "mov";
+ public override string TargetFormat => "mp4";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ var tempInput = Path.GetTempFileName();
+ var tempOutput = Path.GetTempFileName();
+
+ try
+ {
+ using (var fileStream = File.Create(tempInput))
+ {
+ await sourceStream.CopyToAsync(fileStream);
+ }
+
+ var mediaInfo = await FFmpeg.GetMediaInfo(tempInput);
+ var conversion = FFmpeg.Conversions.New();
+
+ if (mediaInfo.VideoStreams.Any())
+ conversion.AddStream(mediaInfo.VideoStreams.First());
+
+ if (mediaInfo.AudioStreams.Any())
+ conversion.AddStream(mediaInfo.AudioStreams.First());
+
+ await conversion
+ .SetOutput(tempOutput)
+ .Start();
+
+ using var outputFile = File.OpenRead(tempOutput);
+ await outputFile.CopyToAsync(targetStream);
+ }
+ finally
+ {
+ if (File.Exists(tempInput)) File.Delete(tempInput);
+ if (File.Exists(tempOutput)) File.Delete(tempOutput);
+ }
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/Mp3ToFlacConverter.cs b/FileConvertor/Core/Converters/Mp3ToFlacConverter.cs
new file mode 100644
index 0000000..fe20d1e
--- /dev/null
+++ b/FileConvertor/Core/Converters/Mp3ToFlacConverter.cs
@@ -0,0 +1,51 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using Xabe.FFmpeg;
+
+namespace FileConvertor.Core.Converters
+{
+ public class Mp3ToFlacConverter : BaseConverter
+ {
+ public override string SourceFormat => "mp3";
+ public override string TargetFormat => "flac";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ // Create temporary files for FFmpeg
+ var tempInput = Path.GetTempFileName();
+ var tempOutput = Path.GetTempFileName();
+
+ try
+ {
+ // Write source stream to temp file
+ using (var fileStream = File.Create(tempInput))
+ {
+ await sourceStream.CopyToAsync(fileStream);
+ }
+
+ // Convert using FFmpeg
+ var mediaInfo = await FFmpeg.GetMediaInfo(tempInput);
+ var audioStream = mediaInfo.AudioStreams.FirstOrDefault();
+
+ if (audioStream != null)
+ {
+ await FFmpeg.Conversions.New()
+ .AddStream(audioStream)
+ .SetOutput(tempOutput)
+ .Start();
+
+ // Copy result to target stream
+ using var outputFile = File.OpenRead(tempOutput);
+ await outputFile.CopyToAsync(targetStream);
+ }
+ }
+ finally
+ {
+ // Clean up temp files
+ if (File.Exists(tempInput)) File.Delete(tempInput);
+ if (File.Exists(tempOutput)) File.Delete(tempOutput);
+ }
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/Mp4ToAviConverter.cs b/FileConvertor/Core/Converters/Mp4ToAviConverter.cs
new file mode 100644
index 0000000..9052a05
--- /dev/null
+++ b/FileConvertor/Core/Converters/Mp4ToAviConverter.cs
@@ -0,0 +1,49 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using Xabe.FFmpeg;
+
+namespace FileConvertor.Core.Converters
+{
+ public class Mp4ToAviConverter : BaseConverter
+ {
+ public override string SourceFormat => "mp4";
+ public override string TargetFormat => "avi";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ var tempInput = Path.GetTempFileName();
+ var tempOutput = Path.GetTempFileName();
+
+ try
+ {
+ using (var fileStream = File.Create(tempInput))
+ {
+ await sourceStream.CopyToAsync(fileStream);
+ }
+
+ var mediaInfo = await FFmpeg.GetMediaInfo(tempInput);
+ var conversion = FFmpeg.Conversions.New();
+
+ if (mediaInfo.VideoStreams.Any())
+ conversion.AddStream(mediaInfo.VideoStreams.First());
+
+ if (mediaInfo.AudioStreams.Any())
+ conversion.AddStream(mediaInfo.AudioStreams.First());
+
+ await conversion
+ .SetOutput(tempOutput)
+ .Start();
+
+ using var outputFile = File.OpenRead(tempOutput);
+ await outputFile.CopyToAsync(targetStream);
+ }
+ finally
+ {
+ if (File.Exists(tempInput)) File.Delete(tempInput);
+ if (File.Exists(tempOutput)) File.Delete(tempOutput);
+ }
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/OggToMp3Converter.cs b/FileConvertor/Core/Converters/OggToMp3Converter.cs
new file mode 100644
index 0000000..6eba620
--- /dev/null
+++ b/FileConvertor/Core/Converters/OggToMp3Converter.cs
@@ -0,0 +1,24 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using NAudio.Wave;
+using NAudio.Lame;
+
+namespace FileConvertor.Core.Converters
+{
+ public class OggToMp3Converter : BaseConverter
+ {
+ public override string SourceFormat => "ogg";
+ public override string TargetFormat => "mp3";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ await Task.Run(() =>
+ {
+ using var reader = new StreamMediaFoundationReader(sourceStream);
+ using var writer = new LameMP3FileWriter(targetStream, reader.WaveFormat, 128);
+ reader.CopyTo(writer);
+ });
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/PdfToMarkdownConverter.cs b/FileConvertor/Core/Converters/PdfToMarkdownConverter.cs
new file mode 100644
index 0000000..1ff4f74
--- /dev/null
+++ b/FileConvertor/Core/Converters/PdfToMarkdownConverter.cs
@@ -0,0 +1,50 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Threading.Tasks;
+using UglyToad.PdfPig;
+
+namespace FileConvertor.Core.Converters
+{
+ public class PdfToMarkdownConverter : BaseConverter
+ {
+ public override string SourceFormat => "pdf";
+ public override string TargetFormat => "md";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ await Task.Run(() =>
+ {
+ var memoryStream = new MemoryStream();
+ sourceStream.CopyTo(memoryStream);
+ memoryStream.Position = 0;
+
+ var markdown = new StringBuilder();
+
+ using (var document = PdfDocument.Open(memoryStream))
+ {
+ for (var i = 1; i <= document.NumberOfPages; i++)
+ {
+ var page = document.GetPage(i);
+ var text = page.Text;
+
+ // Add page separator
+ if (i > 1)
+ {
+ markdown.AppendLine("\n---\n");
+ }
+
+ // Add page content
+ markdown.AppendLine($"## Page {i}\n");
+ markdown.AppendLine(text);
+ }
+ }
+
+ // Write markdown to stream
+ using var writer = new StreamWriter(targetStream, Encoding.UTF8);
+ writer.Write(markdown.ToString());
+ writer.Flush();
+ });
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/PngToGifConverter.cs b/FileConvertor/Core/Converters/PngToGifConverter.cs
new file mode 100644
index 0000000..04fa67c
--- /dev/null
+++ b/FileConvertor/Core/Converters/PngToGifConverter.cs
@@ -0,0 +1,25 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using System.Windows.Media.Imaging;
+
+namespace FileConvertor.Core.Converters
+{
+ public class PngToGifConverter : BaseConverter
+ {
+ public override string SourceFormat => "png";
+ public override string TargetFormat => "gif";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ await Task.Run(() =>
+ {
+ var decoder = new PngBitmapDecoder(sourceStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
+ var encoder = new GifBitmapEncoder();
+
+ encoder.Frames.Add(BitmapFrame.Create(decoder.Frames[0]));
+ encoder.Save(targetStream);
+ });
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/PngToIcoConverter.cs b/FileConvertor/Core/Converters/PngToIcoConverter.cs
new file mode 100644
index 0000000..4001d4f
--- /dev/null
+++ b/FileConvertor/Core/Converters/PngToIcoConverter.cs
@@ -0,0 +1,35 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using SixLabors.ImageSharp;
+using SixLabors.ImageSharp.Formats.Ico;
+using SixLabors.ImageSharp.Processing;
+
+namespace FileConvertor.Core.Converters
+{
+ public class PngToIcoConverter : BaseConverter
+ {
+ public override string SourceFormat => "png";
+ public override string TargetFormat => "ico";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ await Task.Run(() =>
+ {
+ using var image = Image.Load(sourceStream);
+
+ // Resize to standard icon sizes if needed
+ if (image.Width > 256 || image.Height > 256)
+ {
+ image.Mutate(x => x.Resize(new ResizeOptions
+ {
+ Size = new Size(256, 256),
+ Mode = ResizeMode.Max
+ }));
+ }
+
+ image.Save(targetStream, new IcoEncoder());
+ });
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/PngToTiffConverter.cs b/FileConvertor/Core/Converters/PngToTiffConverter.cs
new file mode 100644
index 0000000..d3bda45
--- /dev/null
+++ b/FileConvertor/Core/Converters/PngToTiffConverter.cs
@@ -0,0 +1,25 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using System.Windows.Media.Imaging;
+
+namespace FileConvertor.Core.Converters
+{
+ public class PngToTiffConverter : BaseConverter
+ {
+ public override string SourceFormat => "png";
+ public override string TargetFormat => "tiff";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ await Task.Run(() =>
+ {
+ var decoder = new PngBitmapDecoder(sourceStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
+ var encoder = new TiffBitmapEncoder { Compression = TiffCompressOption.Zip };
+
+ encoder.Frames.Add(BitmapFrame.Create(decoder.Frames[0]));
+ encoder.Save(targetStream);
+ });
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/RtfToDocxConverter.cs b/FileConvertor/Core/Converters/RtfToDocxConverter.cs
new file mode 100644
index 0000000..6bdfa65
--- /dev/null
+++ b/FileConvertor/Core/Converters/RtfToDocxConverter.cs
@@ -0,0 +1,98 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Threading.Tasks;
+using DocumentFormat.OpenXml;
+using DocumentFormat.OpenXml.Packaging;
+using DocumentFormat.OpenXml.Wordprocessing;
+
+namespace FileConvertor.Core.Converters
+{
+ public class RtfToDocxConverter : BaseConverter
+ {
+ public override string SourceFormat => "rtf";
+ public override string TargetFormat => "docx";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ await Task.Run(() =>
+ {
+ // Read RTF content
+ using var reader = new StreamReader(sourceStream, Encoding.Default);
+ string rtfContent = reader.ReadToEnd();
+
+ // Strip RTF formatting to get plain text
+ string plainText = StripRtfFormatting(rtfContent);
+
+ // Create DOCX
+ using var wordDocument = WordprocessingDocument.Create(targetStream, WordprocessingDocumentType.Document);
+ wordDocument.AddMainDocumentPart();
+ var mainPart = wordDocument.MainDocumentPart!;
+
+ mainPart.Document = new Document();
+ var body = new Body();
+
+ // Add paragraphs
+ var lines = plainText.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
+ foreach (var line in lines)
+ {
+ var paragraph = new Paragraph();
+ var run = new Run();
+ run.Append(new Text(line));
+ paragraph.Append(run);
+ body.Append(paragraph);
+ }
+
+ mainPart.Document.Append(body);
+ mainPart.Document.Save();
+ });
+ }
+
+ private string StripRtfFormatting(string rtf)
+ {
+ if (string.IsNullOrEmpty(rtf))
+ return string.Empty;
+
+ var sb = new StringBuilder();
+ bool inControl = false;
+
+ for (int i = 0; i < rtf.Length; i++)
+ {
+ char c = rtf[i];
+
+ if (c == '\\')
+ {
+ inControl = true;
+ if (i + 1 < rtf.Length)
+ {
+ char next = rtf[i + 1];
+ if (next == '\\' || next == '{' || next == '}')
+ {
+ sb.Append(next);
+ i++;
+ inControl = false;
+ }
+ }
+ }
+ else if (c == '{' || c == '}')
+ {
+ inControl = false;
+ }
+ else if (c == ' ' || c == '\n' || c == '\r')
+ {
+ if (!inControl)
+ {
+ sb.Append(c);
+ }
+ inControl = false;
+ }
+ else if (!inControl)
+ {
+ sb.Append(c);
+ }
+ }
+
+ return sb.ToString().Trim();
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/RtfToPdfConverter.cs b/FileConvertor/Core/Converters/RtfToPdfConverter.cs
new file mode 100644
index 0000000..898be21
--- /dev/null
+++ b/FileConvertor/Core/Converters/RtfToPdfConverter.cs
@@ -0,0 +1,105 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Threading.Tasks;
+using iText.Kernel.Pdf;
+using iText.Layout;
+using iText.Layout.Element;
+using iText.Kernel.Font;
+using iText.IO.Font.Constants;
+
+namespace FileConvertor.Core.Converters
+{
+ public class RtfToPdfConverter : BaseConverter
+ {
+ public override string SourceFormat => "rtf";
+ public override string TargetFormat => "pdf";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ await Task.Run(() =>
+ {
+ // Read RTF content
+ using var reader = new StreamReader(sourceStream, Encoding.Default);
+ string rtfContent = reader.ReadToEnd();
+
+ // Strip RTF formatting to get plain text (basic implementation)
+ string plainText = StripRtfFormatting(rtfContent);
+
+ // Create PDF
+ using var writer = new PdfWriter(targetStream);
+ writer.SetCloseStream(false);
+ using var pdf = new PdfDocument(writer);
+ using var document = new Document(pdf);
+
+ var font = PdfFontFactory.CreateFont(StandardFonts.HELVETICA);
+ var paragraph = new Paragraph(plainText)
+ .SetFont(font)
+ .SetFontSize(12);
+
+ document.Add(paragraph);
+ });
+ }
+
+ private string StripRtfFormatting(string rtf)
+ {
+ if (string.IsNullOrEmpty(rtf))
+ return string.Empty;
+
+ var sb = new StringBuilder();
+ bool inControl = false;
+ bool inGroup = false;
+
+ for (int i = 0; i < rtf.Length; i++)
+ {
+ char c = rtf[i];
+
+ if (c == '\\')
+ {
+ inControl = true;
+ // Check for special characters
+ if (i + 1 < rtf.Length)
+ {
+ char next = rtf[i + 1];
+ if (next == '\\' || next == '{' || next == '}')
+ {
+ sb.Append(next);
+ i++;
+ inControl = false;
+ }
+ }
+ }
+ else if (c == '{')
+ {
+ inGroup = true;
+ inControl = false;
+ }
+ else if (c == '}')
+ {
+ inGroup = false;
+ inControl = false;
+ }
+ else if (c == ' ' || c == '\n' || c == '\r')
+ {
+ if (inControl)
+ {
+ inControl = false;
+ }
+ else if (!inGroup || rtf[i - 1] == '}')
+ {
+ if (c == '\n' || c == '\r')
+ sb.Append(' ');
+ else
+ sb.Append(c);
+ }
+ }
+ else if (!inControl)
+ {
+ sb.Append(c);
+ }
+ }
+
+ return sb.ToString().Trim();
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/RtfToTextConverter.cs b/FileConvertor/Core/Converters/RtfToTextConverter.cs
new file mode 100644
index 0000000..2057644
--- /dev/null
+++ b/FileConvertor/Core/Converters/RtfToTextConverter.cs
@@ -0,0 +1,93 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FileConvertor.Core.Converters
+{
+ public class RtfToTextConverter : BaseConverter
+ {
+ public override string SourceFormat => "rtf";
+ public override string TargetFormat => "txt";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ await Task.Run(() =>
+ {
+ // Read RTF content
+ using var reader = new StreamReader(sourceStream, Encoding.Default);
+ string rtfContent = reader.ReadToEnd();
+
+ // Strip RTF formatting to get plain text
+ string plainText = StripRtfFormatting(rtfContent);
+
+ // Write plain text
+ using var writer = new StreamWriter(targetStream, Encoding.UTF8);
+ writer.Write(plainText);
+ writer.Flush();
+ });
+ }
+
+ private string StripRtfFormatting(string rtf)
+ {
+ if (string.IsNullOrEmpty(rtf))
+ return string.Empty;
+
+ var sb = new StringBuilder();
+ bool inControl = false;
+ bool inGroup = false;
+
+ for (int i = 0; i < rtf.Length; i++)
+ {
+ char c = rtf[i];
+
+ if (c == '\\')
+ {
+ inControl = true;
+ // Handle escaped characters
+ if (i + 1 < rtf.Length)
+ {
+ char next = rtf[i + 1];
+ if (next == '\\' || next == '{' || next == '}')
+ {
+ sb.Append(next);
+ i++;
+ inControl = false;
+ }
+ else if (next == 'p' && i + 3 < rtf.Length && rtf.Substring(i, 4) == "\\par")
+ {
+ sb.AppendLine();
+ i += 3;
+ inControl = false;
+ }
+ }
+ }
+ else if (c == '{')
+ {
+ inGroup = true;
+ inControl = false;
+ }
+ else if (c == '}')
+ {
+ inGroup = false;
+ inControl = false;
+ }
+ else if (c == ' ' || c == '\n' || c == '\r')
+ {
+ if (!inControl)
+ {
+ if (c != '\r' && c != '\n')
+ sb.Append(c);
+ }
+ inControl = false;
+ }
+ else if (!inControl)
+ {
+ sb.Append(c);
+ }
+ }
+
+ return sb.ToString().Trim();
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/TextToDocxConverter.cs b/FileConvertor/Core/Converters/TextToDocxConverter.cs
new file mode 100644
index 0000000..cc3374e
--- /dev/null
+++ b/FileConvertor/Core/Converters/TextToDocxConverter.cs
@@ -0,0 +1,45 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Threading.Tasks;
+using DocumentFormat.OpenXml;
+using DocumentFormat.OpenXml.Packaging;
+using DocumentFormat.OpenXml.Wordprocessing;
+
+namespace FileConvertor.Core.Converters
+{
+ public class TextToDocxConverter : BaseConverter
+ {
+ public override string SourceFormat => "txt";
+ public override string TargetFormat => "docx";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ await Task.Run(() =>
+ {
+ using var reader = new StreamReader(sourceStream, Encoding.UTF8);
+ var text = reader.ReadToEnd();
+
+ using var wordDocument = WordprocessingDocument.Create(targetStream, WordprocessingDocumentType.Document);
+ wordDocument.AddMainDocumentPart();
+ var mainPart = wordDocument.MainDocumentPart!;
+
+ mainPart.Document = new Document();
+ var body = new Body();
+
+ var lines = text.Split(new[] { '\r', '\n' }, StringSplitOptions.None);
+ foreach (var line in lines)
+ {
+ var paragraph = new Paragraph();
+ var run = new Run();
+ run.Append(new Text(line));
+ paragraph.Append(run);
+ body.Append(paragraph);
+ }
+
+ mainPart.Document.Append(body);
+ mainPart.Document.Save();
+ });
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/TiffToJpgConverter.cs b/FileConvertor/Core/Converters/TiffToJpgConverter.cs
new file mode 100644
index 0000000..4e4a1ad
--- /dev/null
+++ b/FileConvertor/Core/Converters/TiffToJpgConverter.cs
@@ -0,0 +1,25 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using System.Windows.Media.Imaging;
+
+namespace FileConvertor.Core.Converters
+{
+ public class TiffToJpgConverter : BaseConverter
+ {
+ public override string SourceFormat => "tiff";
+ public override string TargetFormat => "jpg";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ await Task.Run(() =>
+ {
+ var decoder = new TiffBitmapDecoder(sourceStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
+ var encoder = new JpegBitmapEncoder { QualityLevel = 90 };
+
+ encoder.Frames.Add(BitmapFrame.Create(decoder.Frames[0]));
+ encoder.Save(targetStream);
+ });
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/TiffToPngConverter.cs b/FileConvertor/Core/Converters/TiffToPngConverter.cs
new file mode 100644
index 0000000..af74e82
--- /dev/null
+++ b/FileConvertor/Core/Converters/TiffToPngConverter.cs
@@ -0,0 +1,25 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using System.Windows.Media.Imaging;
+
+namespace FileConvertor.Core.Converters
+{
+ public class TiffToPngConverter : BaseConverter
+ {
+ public override string SourceFormat => "tiff";
+ public override string TargetFormat => "png";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ await Task.Run(() =>
+ {
+ var decoder = new TiffBitmapDecoder(sourceStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
+ var encoder = new PngBitmapEncoder();
+
+ encoder.Frames.Add(BitmapFrame.Create(decoder.Frames[0]));
+ encoder.Save(targetStream);
+ });
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/WebmToMp4Converter.cs b/FileConvertor/Core/Converters/WebmToMp4Converter.cs
new file mode 100644
index 0000000..e119183
--- /dev/null
+++ b/FileConvertor/Core/Converters/WebmToMp4Converter.cs
@@ -0,0 +1,49 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using Xabe.FFmpeg;
+
+namespace FileConvertor.Core.Converters
+{
+ public class WebmToMp4Converter : BaseConverter
+ {
+ public override string SourceFormat => "webm";
+ public override string TargetFormat => "mp4";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ var tempInput = Path.GetTempFileName();
+ var tempOutput = Path.GetTempFileName();
+
+ try
+ {
+ using (var fileStream = File.Create(tempInput))
+ {
+ await sourceStream.CopyToAsync(fileStream);
+ }
+
+ var mediaInfo = await FFmpeg.GetMediaInfo(tempInput);
+ var conversion = FFmpeg.Conversions.New();
+
+ if (mediaInfo.VideoStreams.Any())
+ conversion.AddStream(mediaInfo.VideoStreams.First());
+
+ if (mediaInfo.AudioStreams.Any())
+ conversion.AddStream(mediaInfo.AudioStreams.First());
+
+ await conversion
+ .SetOutput(tempOutput)
+ .Start();
+
+ using var outputFile = File.OpenRead(tempOutput);
+ await outputFile.CopyToAsync(targetStream);
+ }
+ finally
+ {
+ if (File.Exists(tempInput)) File.Delete(tempInput);
+ if (File.Exists(tempOutput)) File.Delete(tempOutput);
+ }
+ }
+ }
+}
diff --git a/FileConvertor/Core/Converters/WebpToPngConverter.cs b/FileConvertor/Core/Converters/WebpToPngConverter.cs
new file mode 100644
index 0000000..2623e45
--- /dev/null
+++ b/FileConvertor/Core/Converters/WebpToPngConverter.cs
@@ -0,0 +1,23 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using SixLabors.ImageSharp;
+using SixLabors.ImageSharp.Formats.Png;
+
+namespace FileConvertor.Core.Converters
+{
+ public class WebpToPngConverter : BaseConverter
+ {
+ public override string SourceFormat => "webp";
+ public override string TargetFormat => "png";
+
+ public override async Task ConvertAsync(Stream sourceStream, Stream targetStream)
+ {
+ await Task.Run(() =>
+ {
+ using var image = Image.Load(sourceStream);
+ image.Save(targetStream, new PngEncoder());
+ });
+ }
+ }
+}
diff --git a/FileConvertor/Core/Helpers/FileTypeDetector.cs b/FileConvertor/Core/Helpers/FileTypeDetector.cs
index a30ed0f..f2b7c9b 100644
--- a/FileConvertor/Core/Helpers/FileTypeDetector.cs
+++ b/FileConvertor/Core/Helpers/FileTypeDetector.cs
@@ -61,15 +61,23 @@ private Dictionary InitializeExtensionMap()
{ ".tif", "tiff" },
{ ".webp", "webp" },
{ ".svg", "svg" },
-
- // Audio/Video formats
+ { ".ico", "ico" },
+ { ".heic", "heic" },
+
+ // Audio formats
{ ".mp3", "mp3" },
{ ".wav", "wav" },
- { ".mp4", "mp4" },
{ ".m4a", "m4a" },
-
- // Additional image formats
- { ".heic", "heic" },
+ { ".flac", "flac" },
+ { ".ogg", "ogg" },
+ { ".aac", "aac" },
+
+ // Video formats
+ { ".mp4", "mp4" },
+ { ".avi", "avi" },
+ { ".mov", "mov" },
+ { ".mkv", "mkv" },
+ { ".webm", "webm" },
};
}