@@ -780,6 +780,49 @@ def run(self, image):
780780 return (bar .identifier , bar .content_hash , image )
781781
782782
783+ class MememageDecodeAll :
784+ """Read EVERY Mememage bar in an image — for composites that carry more than one.
785+
786+ The plain **Mememage Decode** reads the single bottom bar (the common case: one
787+ image, one record). This reads them all: an image assembled from several barred
788+ pictures (a collage, a contact sheet, a paste-up) carries a bar per source, at
789+ whatever height each sits. A forensic reader — "what provenanced images are in
790+ here" — closer in spirit to the validator's Observatory than to the mint pipeline.
791+
792+ `identifiers` and `content_hashes` are LIST outputs (bottom-most bar first, index-
793+ aligned), so wiring either into Load Record / Verify makes that node **run once
794+ per bar automatically** — no loop node. `count` is the plain number found (0 when
795+ the image has no bar), handy to gate on. The image passes through unchanged.
796+
797+ A false positive would have to beat the magic bytes, CRC-16, and Reed-Solomon at
798+ once, so bar-ish noise is dropped, not misread. Reads the first image of a batch,
799+ same as Decode.
800+ """
801+
802+ @classmethod
803+ def INPUT_TYPES (cls ):
804+ return {"required" : {"image" : ("IMAGE" ,)}}
805+
806+ RETURN_TYPES = ("STRING" , "STRING" , "INT" , "IMAGE" )
807+ RETURN_NAMES = ("identifiers" , "content_hashes" , "count" , "image" )
808+ OUTPUT_IS_LIST = (True , True , False , False ) # ids + hashes fan out; count + image are scalar
809+ FUNCTION = "run"
810+ CATEGORY = "Mememage"
811+ DESCRIPTION = ("Read every Mememage bar in an image (for composites). identifiers + "
812+ "content_hashes are lists that fan out to Load Record / Verify; count is "
813+ "how many were found." )
814+
815+ def run (self , image ):
816+ import mememage
817+ np , torch , Image = _deps ()
818+ pil = _tensor_to_pil (image [0 ], np , Image )
819+
820+ bars = mememage .decode (pil , all_bars = True ) # list of Bar, bottom-most first
821+ identifiers = [b .identifier for b in bars ]
822+ content_hashes = [b .content_hash for b in bars ]
823+ return (identifiers , content_hashes , len (bars ), image )
824+
825+
783826class MememageReserveId :
784827 """A reserved identifier — a stable pointer you keep pointing at new versions.
785828
@@ -1476,6 +1519,7 @@ async def _mememage_pick_file(request):
14761519 "MememageField" : MememageField ,
14771520 "MememageFieldList" : MememageFieldList ,
14781521 "MememageDecode" : MememageDecode ,
1522+ "MememageDecodeAll" : MememageDecodeAll ,
14791523 "MememageLoadRecord" : MememageLoadRecord ,
14801524 "MememageFindRecord" : MememageFindRecord ,
14811525 "MememageFetchRecord" : MememageFetchRecord ,
@@ -1493,6 +1537,7 @@ async def _mememage_pick_file(request):
14931537 "MememageField" : "Mememage Field" ,
14941538 "MememageFieldList" : "Mememage Fields" , # friendly name — "the node your fields go into"
14951539 "MememageDecode" : "Mememage Decode" ,
1540+ "MememageDecodeAll" : "Mememage Decode All" ,
14961541 "MememageLoadRecord" : "Mememage Load Record" ,
14971542 "MememageFindRecord" : "Mememage Find Record" ,
14981543 "MememageFetchRecord" : "Mememage Fetch Record" ,
0 commit comments