diff --git a/PackageSources/converter/Program.cs b/PackageSources/converter/Program.cs index 79e0761..c682cf0 100644 --- a/PackageSources/converter/Program.cs +++ b/PackageSources/converter/Program.cs @@ -1,37 +1,87 @@ -using Docnet.Core.Models; +using Docnet.Core; +using Docnet.Core.Exceptions; +using Docnet.Core.Models; using Docnet.Core.Readers; -using Docnet.Core; +using khofmann; using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; -using Docnet.Core.Exceptions; +using System.Text.Json; +using System.Text.Json.Serialization; + +#region Defines + +const double MM2IN = 25.4; + +#endregion #region Main Code - +/* if (args.Length == 0) { Console.WriteLine("No PDF specified"); return 1; } -Console.WriteLine($"Conversion for {args[0]}"); -Console.WriteLine("Using configuration"); -Console.WriteLine("\tA4 at 96dpi"); -Console.WriteLine(); -return ReadPDF(args[0]); +Console.WriteLine($"Conversion for {args[0]}\n"); +*/ +Tuple size = ReadConfig(); +return ReadPDF("MD11_FCOM_vol1.pdf", size.Item1, size.Item2); #endregion #region Functions -int ReadPDF(string path) +Tuple ReadConfig() +{ + try + { + using FileStream stream = new("config.json", FileMode.Open, FileAccess.Read); + Settings? settings = JsonSerializer.Deserialize(stream); + if (settings != null) + { + Paper paper = settings.PaperSizes.First(p => p.Name.Equals(settings.SelectedPaper)); + if (paper != null) + { + if (paper.Unit == Unit.Millimetre) + { + int width = Convert.ToInt32(Math.Round(paper.Width / MM2IN * settings.DPI)); + int height = Convert.ToInt32(Math.Round(paper.Height / MM2IN * settings.DPI)); + + Console.WriteLine($"Using {paper.Name}, {width}mm x {height}mm at {settings.DPI} DPI"); + + if (width < height) return new(width, height); + else return new(height, width); + } + else + { + int width = Convert.ToInt32(Math.Round(paper.Width * settings.DPI)); + int height = Convert.ToInt32(Math.Round(paper.Height * settings.DPI)); + + Console.WriteLine($"Using {paper.Name}, ${width}in x {height}in at ${settings.DPI}"); + + if (width < height) return new(width, height); + else return new(height, width); + } + } + } + } + catch { } + + Console.WriteLine("Using default A4 at 96 dpi\n"); + + return new(794, 1122); +} + +int ReadPDF(string path, int width, int height) { string outPath = ""; try { outPath = Path.GetFileNameWithoutExtension(path); Directory.CreateDirectory(outPath); - } catch (Exception e) + } + catch (Exception e) { Console.Error.WriteLine("Error creating file directory"); Console.Error.WriteLine(e.Message); @@ -41,54 +91,52 @@ int ReadPDF(string path) try { - using (IDocReader docReader = DocLib.Instance.GetDocReader(path, new PageDimensions(794, 1122))) + using IDocReader docReader = DocLib.Instance.GetDocReader(path, new PageDimensions(width, height)); + int pages = docReader.GetPageCount(); + Console.WriteLine($"Converting {pages} pages"); + + for (int i = 0; i < pages; i++) { - int pages = docReader.GetPageCount(); - Console.WriteLine($"Converting {pages} pages"); - - for (int i = 0; i < pages; i++) + using (IPageReader pageReader = docReader.GetPageReader(i)) { - using (IPageReader pageReader = docReader.GetPageReader(i)) + byte[] rawBytes = pageReader.GetImage(); + int _width = pageReader.GetPageWidth(); + int _height = pageReader.GetPageHeight(); + + using (Bitmap doc = new(_width, _height, PixelFormat.Format32bppArgb)) + using (Bitmap bmp = new(_width, _height, PixelFormat.Format32bppArgb)) { - byte[] rawBytes = pageReader.GetImage(); - int width = pageReader.GetPageWidth(); - int height = pageReader.GetPageHeight(); + AddBytes(bmp, rawBytes); - using (Bitmap doc = new Bitmap(width, height, PixelFormat.Format32bppArgb)) - using (Bitmap bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb)) + Graphics g = Graphics.FromImage(doc); + g.FillRegion(Brushes.White, new(new Rectangle(0, 0, _width, _height))); + g.DrawImage(bmp, new Point(0, 0)); + g.Save(); + + if (i == 0) { - AddBytes(bmp, rawBytes); - - Graphics g = Graphics.FromImage(doc); - g.FillRegion(Brushes.White, new Region(new Rectangle(0, 0, width, height))); - g.DrawImage(bmp, new Point(0, 0)); - g.Save(); - - if (i == 0) - { - Bitmap thumb = new Bitmap(doc, new Size(doc.Width / 10, doc.Height / 10)); - using (MemoryStream stream = new MemoryStream()) - { - //saving and exporting - thumb.Save(stream, ImageFormat.Jpeg); - Console.WriteLine($"Ouputing tumbnail"); - File.WriteAllText($"{outPath}\\thumb.bjpg", Convert.ToBase64String(stream.ToArray())); - }; - } - - using (MemoryStream stream = new MemoryStream()) + Bitmap thumb = new(doc, new(doc.Width / 10, doc.Height / 10)); + using (MemoryStream stream = new()) { //saving and exporting - doc.Save(stream, ImageFormat.Jpeg); - Console.WriteLine($"Ouputing page {i + 1}"); - File.WriteAllText($"{outPath}\\{i + 1}.bjpg", Convert.ToBase64String(stream.ToArray())); + thumb.Save(stream, ImageFormat.Jpeg); + Console.WriteLine($"Ouputing tumbnail"); + File.WriteAllText($"{outPath}\\thumb.bjpg", Convert.ToBase64String(stream.ToArray())); }; + } + + using (MemoryStream stream = new()) + { + //saving and exporting + doc.Save(stream, ImageFormat.Jpeg); + Console.WriteLine($"Ouputing page {i + 1}"); + File.WriteAllText($"{outPath}\\{i + 1}.bjpg", Convert.ToBase64String(stream.ToArray())); }; }; }; - } + }; } - catch(DocnetLoadDocumentException) + catch (DocnetLoadDocumentException) { Console.Error.WriteLine("File is not a PDF"); Console.ReadKey(); @@ -101,7 +149,7 @@ int ReadPDF(string path) void AddBytes(Bitmap bmp, byte[] rawBytes) { - Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); + Rectangle rect = new(0, 0, bmp.Width, bmp.Height); BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.WriteOnly, bmp.PixelFormat); nint pNative = bmpData.Scan0; @@ -110,4 +158,33 @@ void AddBytes(Bitmap bmp, byte[] rawBytes) bmp.UnlockBits(bmpData); } +#endregion + +#region classes + +namespace khofmann +{ + public class Settings + { + public Paper[] PaperSizes { get; set; } = []; + public string? SelectedPaper { get; set; } + public int DPI { get; set; } + } + + public class Paper + { + public string Name { get; set; } = ""; + public double Width { get; set; } + public double Height { get; set; } + [JsonConverter(typeof(JsonStringEnumConverter))] + public Unit Unit { get; set; } + } + + public enum Unit + { + Inch, + Millimetre + } +} + #endregion \ No newline at end of file diff --git a/PackageSources/converter/config.json b/PackageSources/converter/config.json new file mode 100644 index 0000000..63dc746 --- /dev/null +++ b/PackageSources/converter/config.json @@ -0,0 +1,24 @@ +{ + "PaperSizes": [ + { + "Name": "A4", + "Width": 210, + "Height": 297, + "Unit": "Millimetre" + }, + { + "Name": "A5", + "Width": 148.5, + "Height": 210, + "Unit": "Millimetre" + }, + { + "Name": "Letter", + "Width": 8.5, + "Height": 11, + "Unit": "Inch" + } + ], + "SelectedPaper": "A4", + "DPI": 96 +} diff --git a/PackageSources/converter/converter.csproj b/PackageSources/converter/converter.csproj index 22b7dfb..e648210 100644 --- a/PackageSources/converter/converter.csproj +++ b/PackageSources/converter/converter.csproj @@ -8,13 +8,18 @@ False full True + x64 + x64 + obj\ + bin\ + False - + 9999 - + 9999 @@ -23,4 +28,10 @@ + + + Always + + + diff --git a/PackageSources/converter/converter.sln b/PackageSources/converter/converter.sln index 0ab8be3..e57dd15 100644 --- a/PackageSources/converter/converter.sln +++ b/PackageSources/converter/converter.sln @@ -3,18 +3,18 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.8.34309.116 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "converter", "converter.csproj", "{F7DD439C-CE05-4E1B-AD8F-1D66BAB2C132}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "converter", "converter.csproj", "{F7DD439C-CE05-4E1B-AD8F-1D66BAB2C132}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {F7DD439C-CE05-4E1B-AD8F-1D66BAB2C132}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F7DD439C-CE05-4E1B-AD8F-1D66BAB2C132}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F7DD439C-CE05-4E1B-AD8F-1D66BAB2C132}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F7DD439C-CE05-4E1B-AD8F-1D66BAB2C132}.Release|Any CPU.Build.0 = Release|Any CPU + {F7DD439C-CE05-4E1B-AD8F-1D66BAB2C132}.Debug|x64.ActiveCfg = Debug|x64 + {F7DD439C-CE05-4E1B-AD8F-1D66BAB2C132}.Debug|x64.Build.0 = Debug|x64 + {F7DD439C-CE05-4E1B-AD8F-1D66BAB2C132}.Release|x64.ActiveCfg = Release|x64 + {F7DD439C-CE05-4E1B-AD8F-1D66BAB2C132}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/PackageSources/js-bundle/src/contexts/DataContext.tsx b/PackageSources/js-bundle/src/contexts/DataContext.tsx index a797066..8a498b6 100644 --- a/PackageSources/js-bundle/src/contexts/DataContext.tsx +++ b/PackageSources/js-bundle/src/contexts/DataContext.tsx @@ -3,10 +3,9 @@ import { COMMANDS, DATA, LIST, LOAD } from '../constants'; interface IDataContext { list?: IList[]; - dirCount?: number; file?: string; isLoading?: boolean; - refresh?: (path?: string, offset?: number) => void; + refresh?: (path?: string) => void; load?: (path: string) => void; } @@ -21,10 +20,10 @@ export interface IList { export const DataContext = createContext({}); export const useData = () => { - const { list, dirCount, file, isLoading, refresh, load } = useContext(DataContext); + const { list, file, isLoading, refresh, load } = useContext(DataContext); - if (list !== undefined && dirCount !== undefined && file !== undefined && isLoading !== undefined && refresh && load) - return { list, dirCount, file, isLoading, refresh, load }; + if (list !== undefined && file !== undefined && isLoading !== undefined && refresh && load) + return { list, file, isLoading, refresh, load }; else throw new Error("Couldn't find context. Is your component inside a DataProvider?"); }; @@ -34,7 +33,6 @@ interface IDataContextProps { const DataContextProvider: FC> = ({ dataListener, children }) => { const [list, setList] = useState([]); - const [dirCount, setDirCount] = useState(0); const [file, setFile] = useState(''); const [isLoading, setIsLoading] = useState(true); @@ -51,8 +49,7 @@ const DataContextProvider: FC> = ({ dataLis const json = JSON.parse(args); switch (json.id) { case LIST: - setDirCount(json.count); - setList(json.data); + setList((json.data as IList[]).sort((a, b) => a.name.localeCompare(b.name))); window.dispatchEvent(new Event('resize')); break; case LOAD: @@ -66,9 +63,9 @@ const DataContextProvider: FC> = ({ dataLis setIsLoading(false); }, []); - const refresh = (path = '', offset = 0) => { + const refresh = (path = '') => { setIsLoading(true); - dataListener.call('COMM_BUS_WASM_CALLBACK', COMMANDS, JSON.stringify({ cmd: LIST, path, offset })); + dataListener.call('COMM_BUS_WASM_CALLBACK', COMMANDS, JSON.stringify({ cmd: LIST, path })); }; const load = (path: string) => { @@ -76,9 +73,7 @@ const DataContextProvider: FC> = ({ dataLis dataListener.call('COMM_BUS_WASM_CALLBACK', COMMANDS, JSON.stringify({ cmd: LOAD, file: path })); }; - return ( - {children} - ); + return {children}; }; export default DataContextProvider; diff --git a/PackageSources/js-bundle/src/pages/ListPage/ListPage.tsx b/PackageSources/js-bundle/src/pages/ListPage/ListPage.tsx index abd6c82..18b4a04 100644 --- a/PackageSources/js-bundle/src/pages/ListPage/ListPage.tsx +++ b/PackageSources/js-bundle/src/pages/ListPage/ListPage.tsx @@ -17,13 +17,13 @@ const getPages = (dirCount: number) => { const ListPage: FC = () => { const { navigate, getProps } = useRouter(); - const { list, dirCount, isLoading, refresh } = useData(); + const { list, isLoading, refresh } = useData(); const { path: _path } = getProps() as { path: string }; const guid = useRef(v4()); const [path, setPath] = useState(_path ?? '/'); - const [offset, setOffset] = useState([0]); + const [offset, setOffset] = useState(_path ? new Array(_path.split('/').length).fill(0) : [0]); const [pageJump, setPageJump] = useState('1'); return ( @@ -39,10 +39,10 @@ const ListPage: FC = () => { let newPath = prev.split('/').slice(0, -2).join('/') + '/'; if (newPath === '/') newPath = '/'; setOffset((prev) => { - const _offset = prev.pop(); - refresh(newPath, _offset); + prev.pop(); return [...prev]; }); + refresh(newPath); return newPath; }); }} @@ -76,9 +76,8 @@ const ListPage: FC = () => { try { let page = Number.parseInt(pageJump); if (isNaN(page)) page = offset.slice(-1)[0]; - page = Math.max(1, Math.min(getPages(dirCount) + 1, page)); + page = Math.max(1, Math.min(getPages(list.length) + 1, page)); if ((page - 1) * MAX_LIST !== offset.slice(-1)[0]) { - refresh(path, (page - 1) * MAX_LIST); setOffset((prev) => { prev.pop(); return [...prev, (page - 1) * MAX_LIST]; @@ -100,7 +99,6 @@ const ListPage: FC = () => { const curOffset = offset.slice(-1)[0]; const newOffset = curOffset - MAX_LIST >= 0 ? curOffset - MAX_LIST : 0; if (newOffset !== curOffset) { - refresh(path, newOffset); prev.pop(); return [...prev, newOffset]; } else return prev; @@ -110,15 +108,14 @@ const ListPage: FC = () => { - {offset.slice(-1)[0] / MAX_LIST + 1}/{getPages(dirCount) + 1} + {offset.slice(-1)[0] / MAX_LIST + 1}/{getPages(list.length) + 1} - + {entry.name} #include -#include #include "rapidjson/document.h" @@ -14,16 +13,6 @@ namespace khofmann { - /// - /// Exclude . and .. directory - /// - /// Entry to check - /// TRUE if not . or .., FALSE otherwise - static int excludeDotDirs(const struct dirent* entry) - { - return strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0; - } - /// /// Read a file and return file contents /// @@ -42,7 +31,9 @@ namespace khofmann fread(string, fsize, 1, file); fclose(file); - return rapidjson::Value(string, alloc); + rapidjson::Value retVal(string, alloc); + free(string); + return retVal; } return rapidjson::Value("", alloc); @@ -55,74 +46,60 @@ namespace khofmann /// Path of directory /// Pointer to files value object /// Allocator - /// Offset into file list - /// Total numbers of directories - static int enumerateDir(const char* path, rapidjson::Value *files, rapidjson::Document::AllocatorType& alloc, int offset) + static void enumerateDir(const char* path, rapidjson::Value *files, rapidjson::Document::AllocatorType& alloc) { - int count = 0; - int numDirs = 0; - DIR* d = opendir(path); if (d) { - struct dirent **dir; - numDirs = scandir(path, &dir, excludeDotDirs, alphasort); - if (numDirs == -1) + struct dirent* dir; + while ((dir = readdir(d)) != NULL) { - log(stdout, "Error: %i", (void*)errno); - } - for (int i = 0; i < numDirs; i++) - { - if (i >= offset && i < offset + MAX_LIST) - { - std::string dirPath(path); - dirPath += dir[i]->d_name; - std::string thumb(dirPath); - thumb += "/thumb.bjpg"; - FILE* check = fopen(thumb.c_str(), "r"); - if (check) - { - fclose(check); - DIR* f; - struct dirent* file; - f = opendir(dirPath.c_str()); - if (f) - { - log(stdout, "Found file %s\n", dir[i]->d_name); - while ((file = readdir(f)) != NULL) - { - if (file->d_type == DT_REG) - { - count++; - } - } - rapidjson::Value entry; - entry.SetObject(); - entry.AddMember("name", rapidjson::Value(dir[i]->d_name, alloc).Move(), alloc); - entry.AddMember("pages", count - 1, alloc); - entry.AddMember("thumb", readFile(thumb.c_str(), alloc).Move(), alloc); - entry.AddMember("type", "file", alloc); - files->PushBack(entry.Move(), alloc); - } - closedir(f); - } - else - { - log(stdout, "Found directory %s\n", dir[i]->d_name); + if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0) continue; + std::string dirPath(path); + dirPath += dir->d_name; + std::string thumb(dirPath); + thumb += "/thumb.bjpg"; + FILE* check = fopen(thumb.c_str(), "r"); + if (check) + { + fclose(check); + DIR* f; + struct dirent* file; + f = opendir(dirPath.c_str()); + if (f) + { + int count = 0; + log(stdout, "Found file %s\n", dir->d_name); + while ((file = readdir(f)) != NULL) + { + if (file->d_type == DT_REG && strstr(file->d_name, ".bjpg") != NULL) + { + count++; + } + } rapidjson::Value entry; entry.SetObject(); - entry.AddMember("name", rapidjson::Value(dir[i]->d_name, alloc).Move(), alloc); - entry.AddMember("type", "directory", alloc); + entry.AddMember("name", rapidjson::Value(dir->d_name, alloc).Move(), alloc); + entry.AddMember("pages", count - 1, alloc); + entry.AddMember("thumb", readFile(thumb.c_str(), alloc).Move(), alloc); + entry.AddMember("type", "file", alloc); files->PushBack(entry.Move(), alloc); } + closedir(f); + } + else if (dir->d_type == DT_DIR) + { + log(stdout, "Found directory %s\n", dir->d_name); + + rapidjson::Value entry; + entry.SetObject(); + entry.AddMember("name", rapidjson::Value(dir->d_name, alloc).Move(), alloc); + entry.AddMember("type", "directory", alloc); + files->PushBack(entry.Move(), alloc); } - free(dir[i]->d_name); } - free(dir); } closedir(d); - - return numDirs; } } \ No newline at end of file diff --git a/PackageSources/module/Module.cpp b/PackageSources/module/Module.cpp index e3a9dc6..b78abc6 100644 --- a/PackageSources/module/Module.cpp +++ b/PackageSources/module/Module.cpp @@ -63,8 +63,6 @@ extern "C" if (strcmp(cmd, "LIST") == 0) { - int offset = inDoc["offset"].GetInt(); - std::string path; path += PACKAGE_DIR; path += inDoc["path"].GetString(); @@ -77,8 +75,7 @@ extern "C" rapidjson::Value files; files.SetArray(); - int numDirs = khofmann::enumerateDir(path.c_str(), &files, allocator, offset); - outDoc.AddMember("count", numDirs, allocator); + khofmann::enumerateDir(path.c_str(), &files, allocator); outDoc.AddMember("data", files.Move(), allocator); rapidjson::StringBuffer strbuf;