MTGProxyPrinter

View Ticket
Login

View Ticket

Ticket Hash: 7d17f860bf9df5356590356efbd697173976626c
Title: Support duplex printing, including card back faces
Status: Verified Type: Feature_Request
Severity: Important Priority: High
Subsystem: Document_Model Resolution: Open
Last Modified: 2024-04-18 17:08:59
Version Found In:
User Comments:
thomas added on 2022-12-01 13:20:35:

Add support for duplex printing, including card back faces.

For single-faced cards, the appropriate back image has to be fetched.

Code changes

Document

When duplex mode is on, the page count will always be even. Front faces are on odd pages, back faces on even pages.

Back pages should be read-only. Do not allow the user to put cards on back pages.

Switching to/from duplex mode

  • Front and back sides should be linked, so this depends on ticket [465ddf469f].
  • Enable duplex:
    • Insert an empty page after each document page
    • Gather all back faces of douple-faced cards on odd pages
    • Insert the correct amount of back faces on each page. For each double-faced front card on the previous page, insert the matching back face.
  • Disable duplex:
    • Gather all back faces of double-faced cards on even pages
    • Place those on odd pages
    • Delete all even pages

Document shuffling

The shuffling algorithm has to be adjusted:

  • Zip the cards from odd and even pages to a list of tuples (front, back)
  • Shuffle these
  • Restore document

Adding pages

Pages must be added in multiples of 2 to maintain the odd=front, even=back invariant

Adding cards

When a card is added to an odd page, a back image has to be added to the next page

Special care has to be taken when a double-faced card gets added.

Removing cards

When a card is removed, it’s back has to be removed from the next page, too

Document compacting

The compacting algorithm has to be adapted to run on both sets of odd and even pages in parallel.

PageRenderer

The page renderer has to flip all even pages.

  • Flip left and right margin
  • Render columns right to left

AddCardWidget

The AddCardWidget has to disallow adding cards to read-only back pages.


thomas added on 2023-01-14 19:35:56:

On duplex documents, odd pages contain card fronts, even pages contain card back sides.

Idea for changes to the save file format

  • Add duplex_mode to the document settings.
    • off uses simplex printing
    • partial only prints double-faced cards, single-faced ones get white backs
    • full additionally prints card backs of regular cards
  • On duplex documents, even pages can be saved fully implicitly
    • Remove the NOT NULL constraint from the is_front column
    • If a NULL value is encountered, the spot on the odd pages takes the front image and the same spot on the even page takes the back image of the given scryfall id.

thomas added on 2023-04-23 22:23:23:

The back faces need images, so implement fetching them.

Managing back face images

Database

  • Each single-faced card holds a key card_back_id with a UUID value, pointing to a back face image
    • DFCs do not have this key
  • The back face ID has to be stored in the database.
  • The back face depends on the printing. E.g. 30th edition vs regular printing. Best location is probably the Printing table
    • Since the UUIDs are long and there are lots of duplicates, the best way is probably a new table with three columns: An integer ID, the UUID and the URL. Then link it via a foreign key relation. This should add ~1 byte for each entry in the Printing table, since the primary key should fit in 1 byte.
  • The CardDatabase class needs a method for obtaining the back of a single-faced card.

Scryfall API

The URLs to back face images aren't part of the regular bulk data.

  • I found no documentation for obtaining the back face URL. So the best way seems to be to generate it on the fly within the database via a GENERATED ALWAYS column.
  • The card back images are saved on backs.scryfall.io.
    • Sample URL: https://backs.scryfall.io/png/9/8/98d277bf-8635-4a02-ac2f-4d44ddc47993.png

Image database

  • The ImageDatabase needs to store back images somewhere. A good location is probably a dedicated directory
  • The ImageDatabase class needs a method for fetching the back face images

thomas added on 2023-04-26 09:18:15:

 

Fixing mixed-size pages has to handle duplex documents

The method _fix_mixed_pages() in the DocumentLoader Worker has to support working on duplex documents.

Idea for explicitly saving back pages

Instead of implicitly saving even pages in duplex mode, it is possible to explicitly save them by adding a type column to the Card table.

Card table type column

Add a type column to the Card table. This can be used as a string-based enum to identify the type of card.

  • 'r' is a regular, official magic product that has a scryfall id associated with and is included in the Scryfall bulk data file. Can be a regular card, oversized card, token card, etc.
  • 'd' is a generated check card for DFCs (TDB)
  • 'b' is a back face of a card. The Scryfall ID still refers to a front, for which the back face image can be looked up.

thomas added on 2023-04-28 14:08:25:

The MissingImagesManager has to also handle missing back images, in case fetching those failed before printing


thomas added on 2023-05-07 14:21:20:

Progress report

Implemented

  • Added a duplex mode setting to the PageLayoutSettings
    • A default can be set in the application settings
    • The document-specific value is saved with the document
  • Rendering of front/back sides, on screen, paper and PDF
    • Back faces render cut markers from the right border and flip the card column order

TODO

  • Layout conversion to/from duplex mode
  • Limiting write access to back pages
  • Adapting the ImageDatabase
    • Fetching back images
    • Loading back images from disk
  • card database work
    • storing the back face ids for printings
    • storing the back face uris
    • Requesting back faces for a given card instance
  • Adapting the shuffle algorithm
  • Adding DFCs in duplex mode
  • Removing cards

thomas added on 2023-05-23 10:56:47:

Handle reversible cards:

There are a few reversible cards printed in the SLD set. Those have the same single-sided card on both front and back side. For example: https://scryfall.com/card/sld/1122

Those have to be supported properly when switching between printings in duplex mode. I.e. when switching the front to the SLD printing, the regular card back has to be replaced with the SLD printing back side. When switching away, the back has to be replaced with a regular card back.


thomas added on 2023-12-24 22:48:15:

Idea for handling of cards in duplex mode:

Redefine the current "Card" class

Currently, the Card class does not represent an actual MTG card, but rather a singular face of it. So fix that.

  • Rename Card to CardFace
  • Introduce a new class Card that holds two CardFace instances, "front" and "back". Implement similar to the CheckCard class.
  • The front has priority for all fields. So a DFC Card holds two CardFace instances, one front and one back, but behaves just as if it were the front CardFace
  • If the front is None, return the back side instead.

Duplex handling

Document

The Document instance only holds one Card instance for each card in the document. With that, back sides are fully transparent and implicit.

PageScene

In duplex mode, the PageScene uses the front of each Card on the current page when rendering an odd page, and the back, when rendering an even page.

Simplex

Document

In simplex mode, the document holds two Card instances for each DFC, one with the front&back set, and one with only the back. Maybe use a plain CardFace for the back only. Ensure that the same object for both back face instances is used.

Also ensure that the proper change signals are emitted. With that change, a single edit can alter two rows, even across pages.

Linking backs to fronts

To easily find the other face for the purpose of updating DFCs or switching to duplex mode, evaluate if QPersistentModelIndex can be used to hold links between the two faces.

Print switching

When switching a printing, do so for both front and back

Enabling duplex

When enabling duplex, scan the document for DFC Cards and singular backs. For each DFC card, delete the backs based on object identity, and keep the full Card instances. For all remaining back sides (those had no front in the original document), construct a full Card instance and place them there.

Disabling duplex

For each DFC, add a plain back side CardFace in the document. Maybe insert right after the front.


thomas added on 2024-01-12 00:15:13:

The Document model does not even need to actually hold Page instances for even/back pages.

While in duplex mode, the list index of the currently active page can be computed by floor(active_page_number/2)


thomas added on 2024-01-18 12:19:20:

Disabling duplex mode

Remove all non-unique back faces, then re-flow the document, then remove empty pages.

Unique back faces

All back faces that are only used by a single printing are unique. This includes meld card back sides and DFC back sides. The BackFace class should hold this property as a boolean.

Re-flow

  • For each kept back face, insert it next to the front
  • Delete even pages
  • Re-flow overflowing pages. Implement [fae56bc9b847f2c0] to keep the document order mostly intact.

thomas added on 2024-02-04 10:09:37:

Empty back pages in DFC-only mode should not draw cut helper lines, document titles and page numbers. Those pages should be completely empty

If the user prints a DFC-only duplex mode document on a simplex printer, the app should not print an empty cut helper grid on all back pages without actual images. These pages should be left completely blank, so that the sheets can be put back into the printer paper feed.


thomas added on 2024-04-18 17:08:59:

Alternate idea, which should solve most issues:

Replace the Document class

Completely replace the document class.

1. The document is split into 4 sections

  • Regular-sized double-sided cards
  • Over-sized double-sided cards (Currently none exist)
  • Regular-sized single-sided cards
  • Over-sized single-sided cards

Each section holds cards as a list. Each individual card can hold it's front face and back face

2. Paginate via a QSortFilterProxyModel

Implement a custom QSortFilterProxyModel that converts the base Document into a list of pages.

Enabling/disabling duplex printing can then do an easy full re-structuring of the proxy model. When duplex is enabled, the double-sided sections can be projected into the target format, be it straight duplex or printing in a way that allows some folding adjacent prints to form double-sided print-outs.