simon-knuth / scanner

An all-in-one scanner app built for the Universal Windows Platform
https://simon-knuth.github.io/scanner/index
Mozilla Public License 2.0
492 stars 28 forks source link

Save/Export each page as separate PDF file when using a feed scanner #95

Open mrflory opened 2 years ago

mrflory commented 2 years ago

Is your feature request related to a problem? Please describe. When scanning multiple pages (e.g. multiple invoices) with a feed scanner, I need to split the consolidated PDF file with a 3rd party program into separate PDF files.

Describe the solution you'd like Add an option (maybe as filetype) to save each page separately as PDF file when using a feed scanner.

Describe alternatives you've considered Add a button to the "PDF editing" area to export each page as separate file.

Additional context Need this feature for upload invoices into a tax software that expects each invoice in a separate file.

simon-knuth commented 2 years ago

That's a great suggestion, saving individual PDFs is indeed a gap in the current feature set. I'll definitely take a look at this whenever I start working on another update, which may unfortunately not be this year (the implementation doesn't appear too difficult though, so perhaps someone else would like to tackle this earlier).

FlorianKohn commented 1 year ago

Hi @simon-knuth , I am also interested in this feature and willing to help. Could you give me hint on where to start?

simon-knuth commented 1 year ago

Hi @FlorianKohn, that would be awesome, I don't see myself getting a look at this over the next few months. If you'd like to help, I'd be more than happy to make sure the code gets to the Store.

The implementation detail here could be a difficult decision. I see 3 options:

  1. Offer a post-scan option to split the PDF. This could destroy the original or keep it. The resulting files are not updated by the app anymore, so this should be done after everything is in order (rotation, crop, etc.). The process would therefore be export-like, to communicate that completely separate files are created. It could be started from the page list toolbar, which would also allow it to make use of page selection (i.e. either export all pages or select some to export). image

  2. Offer a pre-scan option to save all pages individually. This could just be a new CheckBox in the "Feeder options" section that is only enabled when PDF is selected. The big disadvantage: You lose all editing capabilities, because the backend can't handle multiple PDF files right now. The user would lose control over their files, which could cause a lot of confusion. Would the app even show any result afterwards or just save the files and call it a day..? 🤔 image

  3. Offer the pre-scan option from 2 but with all editing functionality intact. The code is not designed to handle multiple PDF files, so enabling the editing features in a pre-scan scenario would probably be quite a bit of work. We'd introduce a whole new state to the app, which would touch almost every aspect of scanning, including additional pages being added.

Option 1 is definitely much easier to implement and imo very user-friendly. But if someone were to use this a lot, it could get tedious to always have to go to the page list and split the file. Option 2 is easy to implement as well, but not very user-friendly unless you were to go the extra mile and rework the backend to handle multiple PDF files as described in approach 3. I really wouldn't be super thrilled about approach 2 with the app's focus on ease-of-use to be honest. 90 % of the feature set would suddenly be unusable there.

Let me know if this still sounds like something you'd like to do and which approach you'd prefer. Or perhaps you even have another idea. I can take a look at the code and make a list of what would be relevant to get from A to B.

FlorianKohn commented 1 year ago

Wow, thank you for this detailed answer. While I think option 3 is the most compelling, I agree that it would not be worth the effort. Hence, I will for option 1.

simon-knuth commented 1 year ago

Great, I'll put together some notes that should prove helpful in untangling what my code does. The solution would include 3 parts, most of which should be quite straight-forward when tackled on their own.

1. Build the UI

We need to add an "Export page" button. My suggestion is placing it in the page list toolbar. You can find it in PageListView.xaml. Just copy the AppBarButtonShare and change its icon glyph to something that fits, e.g. . You can remove the Visibility, Opacity and OpacityTransition properties so that the button is visible at all times. Please keep the share button as the last command in the toolbar for consistency. Create a new export command in the PageListViewModel and bind it to the new button.

2. Prepare the full-trust process

Scanner uses a full-trust process included as the ImageToPDF project for PDF generation. The process is pretty dumb and just looks at a predetermined folder, grabs all images in it, puts them all into a PDF and then hands control back to the UWP app. This is a problem, since we now need it to handle another scenario as well. Fortunately, that's not a big deal: We can hand over indices of the pages we want exported by writing them to a LocalSettings property (see PdfService.cs:63). When an export is about to start, the UWP app should write the values there and then clear them when it is done. ImageToPDF can be changed to detect this and adapt its behavior to exporting single pages. Please don't instruct ImageToPDF to save the files to the target location. Save them to a temporary application folder (you can edit the AppDataService and add a new folder for that) and then let the UWP component move the files to their target folder. That way the user's file system will be protected.

3. Connect UI and full-trust process

The new communication with the full-trust process can be implemented as a method in PdfService.cs, inspired by GeneratePdfAsync(). The method would be called by another new method in ScanResult.cs. That method is called by a new method in the ScanResultService, which is in turn called by a new method in PageListViewModel. That method is then used in the command we created earlier. You can take inspiration from methods such as PageListViewModel.CopyAsync(). I know there is at least one too many steps here, but that way the codebase will stay uniform. 😅


That should be about it. I'm sure something will go wrong along the way, but at first glance it does seem feasible to me. This is the general flow just as an overview:

  1. AppBarButton on PageListView invokes command
  2. PageListViewModel command invokes method that collects the indices and asks the user for a folder using the Windows folder picker
  3. ScanResultService invokes PdfService
  4. PdfService saves indices to LocalSettings and launches full-trust process
  5. ImageToPDF detects that pages need to be exported and saves the files to a temporary folder
  6. PageListViewModel moves files to the target location

I hope this is helpful and I didn't go into too much detail! Even if you don't finish this for whatever reason I wouldn't mind merging your code and taking a look at it at a later time. You don't need to deal with localization or accessibility if you don't want to. Thank you for your help 🙂