Dienstag, 22. November 2016

Some thoughts about risks in TIFF file format

Introduction

TIFF in general is a very simple fileformat. It starts with a constant header entry, which indicates that the file is a TIFF and how it is encoded (byteorder).
The header contains an offset entry which points to the first image file directory (IFD). Each IFD has a field which counts the number of associated tags, followed by an array of these tags and an offset entry to the next IFD or to zero, which means there is no further IFD.
Each tag in the array is 12 Bytes long. The first 4 bytes indicate the tag itself, the next 2 bytes declare the value-type, followed by 2 bytes counting the values. The last 4 bytes are either an offset or hold the values themselves.

What makes a TIFF robust?

In the TIFF specification, there are some hints which help us to repair broken TIFFs.
The first hint is that all offset-addresses must be even. The second important rule is that the tags in an IFD must be sorted in an ascending order.
At last, the TIFF spec defines different areas in the tag range. This is to guarantee that the important values are well defined.
If we guarantee that a valid TIFF was stored, there is a good chance to detect and repair broken TIFFs using these three hints.

What are the caveats of TIFF?

As a proof of concept there is also a tool "checkit_tiff_risks" provided in this repository. Using this tool, users can analyze the layout of any baseline TIF file.
The most risky memory ranges are the offsets. If a bitflip occurs there, the user must search the complete 4GB range. In practise, the TIF files are smaller, and so this size is the searchspace for offsets.
The most risky offsets are the ones which are indirect offsets. This means the IFD0 offset and the StripOffset tag (code 273).
Here an example of a possible complex StripOffset encoding:
The problem in this example is that TIFF has no way to find out how many bytes are part of the pixel-data stream. The existing StripByteCounts tag only stores the expected pixel data length after decompression.
This makes the StripOffset tag very fragile. If a bitflip changes the offset of the StripOffset tag, the whole pixel information might be lost.
Also, if a bitflip occurs in the offset area that the StripOffset tag points to, the partial pixel data of the affected stripe is lost.
If compression is used, the risk of losing the whole picture is even higher, because the compression methods do not use an end-symbol. Instead, the buffer sizes as stored in the StripByteCount tag are used. Therefore, a bit-error in the Compression tag, the StripOffset tag, the StripByteCount tag or in the memory-map where StripOffset points to, could destroy the picture information.

Upcoming next…


In upcoming versions of checkit_tiff, we would provide a tool to analyze the distribution of risky offsets in given TIFF-files.  This will objectify the discussion about robust fileformats vs. compression.

Here a short preview:

$>  ./checkit_tiff_risk ../tiffs_should_pass/minimal_valid.tiff

This reports this kind of statistics:

[00], type=                  unused/unknown, bytes=         0, ratio=0.00000
[01], type=                        constant, bytes=         4, ratio=0.01238
[02], type=                             ifd, bytes=       130, ratio=0.40248
[03], type=                  offset_to_ifd0, bytes=         4, ratio=0.01238
[04], type=                   offset_to_ifd, bytes=         4, ratio=0.01238
[05], type= ifd_embedded_standardized_value, bytes=        52, ratio=0.16099
[06], type=   ifd_embedded_registered_value, bytes=         0, ratio=0.00000
[07], type=      ifd_embedded_private_value, bytes=         0, ratio=0.00000
[08], type=ifd_offset_to_standardized_value, bytes=        12, ratio=0.03715
[09], type=  ifd_offset_to_registered_value, bytes=         0, ratio=0.00000
[10], type=     ifd_offset_to_private_value, bytes=         0, ratio=0.00000
[11], type=      ifd_offset_to_stripoffsets, bytes=         0, ratio=0.00000
[12], type=               stripoffset_value, bytes=        30, ratio=0.09288
[13], type=              standardized_value, bytes=        87, ratio=0.26935
[14], type=                registered_value, bytes=         0, ratio=0.00000
[15], type=                   private_value, bytes=         0, ratio=0.00000
counted: 323 bytes, size: 323 bytes


In this example the StripOffset is encoded directly (there are only one stripe). The problematic bytes are the offset-addresses (affected 20 Bytes of 323 Bytes).

In opposite to this example, here a special file using multiple strips:

$>  ./checkit_tiff_risk ../tiffs_should_pass/minimal_valid_multiple_stripoffsets.tiff

This reports this kind of statistics:

[00], type=                  unused/unknown, bytes=         0, ratio=0.00000
[01], type=                        constant, bytes=         4, ratio=0.01250
[02], type=                             ifd, bytes=       122, ratio=0.38125
[03], type=                  offset_to_ifd0, bytes=         4, ratio=0.01250
[04], type=                   offset_to_ifd, bytes=         4, ratio=0.01250
[05], type= ifd_embedded_standardized_value, bytes=        44, ratio=0.13750
[06], type=   ifd_embedded_registered_value, bytes=         0, ratio=0.00000
[07], type=      ifd_embedded_private_value, bytes=         0, ratio=0.00000
[08], type=ifd_offset_to_standardized_value, bytes=        16, ratio=0.05000
[09], type=  ifd_offset_to_registered_value, bytes=         0, ratio=0.00000
[10], type=     ifd_offset_to_private_value, bytes=         0, ratio=0.00000
[11], type=      ifd_offset_to_stripoffsets, bytes=        40, ratio=0.12500
[12], type=               stripoffset_value, bytes=        30, ratio=0.09375
[13], type=              standardized_value, bytes=        56, ratio=0.17500
[14], type=                registered_value, bytes=         0, ratio=0.00000
[15], type=                   private_value, bytes=         0, ratio=0.00000
counted: 320 bytes, size: 320 bytes


Here you can see we have the type 11, which points StripOffset to an array of offset adresses, where the pixel data could be found. This is similar to the diagram above. In this case we have 40 bytes with high bitflipping risk.




Montag, 12. September 2016

Die schlechten ins Kröpfchen, die guten ins Töpfchen

(english version below)
Quelle: Wikisource, public domain
Diese Woche wurde die Bitte an uns herangetragen, uns zu überlegen, wie wir mit invaliden Dateien umgehen, für die wir im Rahmen einer Dienstleistung die Langzeitarchivierung anbieten.

Die Frage kam auf, weil mit dem Dienstnehmer gerade die Übernahmevereinbarung verhandelt wird und wir für unsere eigenen Workflows strenge Validitätskriterien ansetzen.

Zuerst waren wir verunsichert. "Ja, man müsste die validen und invaliden Dateien ja im gleichen Speicher zusammenhalten", aber auch "wenn, dann müssten wir diese Dateien aber als valide oder invalide markieren".

Oder auch: "Die Submission Application könnte doch validieren und je nach Ergebnis die Daten in den einen oder anderen Workflow schieben".

Wir beide haben uns hingesetzt, nochmal unser LZA-System angeschaut und uns intensiver Gedanken dazu gemacht.

Unsere Software erlaubt es nicht, invalide Dateien in das LZA zu lassen. Man muss sich vorher für einen Workflow die Qualitätsparameter überlegen. Wenn wir eigene Validatoren benutzen, können die Qualitätsparameter (Policies) frei gewählt sein. Wir könnten jeden Mist durchlassen oder eben nur streng definierte Qualitätsperlen.
Für diesen Workflow wird all das Material ins Archiv gelassen, das diese erfüllt.

Sind die Anforderungen nicht erfüllt, landen die SIPs beim 'technical analyst', der nur die Wahl hat zwischen
  • "Reject", also Zurückweisung mit Option des erneuten Ingests 
  • "Decline" als generelle Abweisung oder 
  • direkte Reparatur innerhalb der 'technical analyst'-Workbench
Ein Verschieben von IEs durch den 'technical analyst' zwischen verschiedenen Workflows ist nicht möglich.

Eine Mischung von "validen" und "invaliden" Dateien bleibt aber auch nach längerer Überlegung nicht sinnvoll:
Die strikte Trennung der Workflows in unserem Archivsystem dient ja gerade dazu, die IEs à la Aschenputtel "die schlechten ins Kröpfchen, die guten ins Töpfchen" zu sortieren.

Damit steigt die Grundqualität in den  jeweiligen Workflows und, dies ist entscheidend, man hat im Falle der Formatmigration weniger Fehlerfälle und geringeren Aufwand.

Durch eine, wie auch immer geartete, Markierung, die in unserem System aber nicht direkt möglich ist, würden wir die Einhaltung unserer eigenen Policies gefährden.
Dies führte dann auch dazu, dass man sich von der Maxime leiten ließe, "später (wenn wir mehr Personal/Zeit/bessere Technik haben) können wir das ja vielleicht mal reparieren". Dass dieser Ansatz funktionieren soll, konnte uns bisher kein Archiv zeigen.

Eine Validierung innerhalb der Submission Application ist genauso wenig  sinnvoll. Sie soll weder jetzt noch zukünftig die Aufgaben des Archivsystems übernehmen.  Dies würde sonst dazu führen, dass man Teile des bestehenden LZA-Systems selbst nachbauen würde.

Gegenüber dem Dienstnehmer würden wir so argumentieren, dass dieser ja bei uns die Dienstleistung "Langzeitarchivierung" einkauft. Wir werden bezahlt, ihre Qualität hochzuhalten, oder in Prosa: "Der regelmäßige Tritt in den Hintern des Dienstnehmers führt zu Glücksgefühlen und ist ihm viel Geld wert."
Wer das nicht für sinnvoll erachtet, dem dürfte ein einfacher Sicherungsdienst ausreichen. Dafür gibt es genügend Anbieter am Markt.

Fazit

Manchmal braucht es ein paar Minuten nochmal über die eigene Rolle als Langzeitarchivar nachzudenken. Und es ist gut, wenn wir uns auch unter Druck diese Zeit nehmen.

Nachtrag

Eine weitere Möglichkeit wäre, in unserem Langzeitarchivsystem den Speicherbereich, in dem die Fälle des 'technical analyst' landen, stärker abzusichern (zB. durch 3-fache Kopien).

Damit würden all die IEs, die valide sind weiter in den Langzeitspeicher wandern und wären bestens langzeitarchiviert.

Und all jene IEs, die nicht vollumfänglich valide sind, landen im Speicherbereich des 'technical analyst' und würden bei Reparatur oder nach spätestens 10 Jahren dort gelöscht. Dieser Speicherbereich sichert dann dem Dienstnehmer  nur 'bitstream preservation' zu und für diesen bleibt das Risiko und der Reparaturaufwand transparent.

Der Druck die IEs sauber ins LZA-System einzuliefern kommt durch die deutlich höheren Speicherkosten für den Zwischenspeicherbereich zustande, da dieser auf auf Festplatten und nicht auf Band  basiert.

The good must be put in the dish, the bad you may eat if you wish.

Just this week we were asked to develop a stretegy for treating invalid data that we provide a digital preservation service for. The question arose because we currently are in the negotiations of the transfer agreement with our customer and we set a very strict quality policy for our own workflows. At first, we were a little uneasy. "Yes, valid and invalid data would need to be kept in the same storage.", but also "if we do this, then we'd have to flag valid and invalid files to keep them apart." Or in other words: "The Submission Application could run the validation and move the data through different workflows, depending on the validation result." So we both sat down, took a deeper look into our preservation system and contemplated a little longer on this problem.

Our software does not allow invalid data into the permanent repository. The quality parameters for each workflow have to be concepted in advance. If we use our own validators, the policy for the quality parameters can be chosen freely. We either could allow any crap or just maticulously chosen pearls of quality through to our permanent repository. For the workflow that will be configured, all material that complies with whatever policy we set up will be let through to the permanent storage. If the requirements aren't met, the SIPs end up with the 'technical analyst', who now has to choose between:

  • "Reject"ing the ingest with optional re-ingest
  • "Decline"ing the ingest and disallowing re-ingest
  • immediate repair inside of the 'technical analyst' workbench

The 'technical analyst' cannot move the SIP between workflows.

In conclusion, mixing "valid" and "invalid" files doesn't seem sensible. The strict workflow separation in our preservation system is there for the sole purpose of sorting the SIPs like Cinderella dit with the lenses: "The good must be put in the dish, the bad you may eat if you wish." This increases the basic quality level for corresponding workflow and, this is very important, lowers the efforts and number of error cases in case of a format migration.

By using whatever kind of flagging (which isn't possible with our current system), we would endanger the enforcement of our own policies. This would make us follow the maxime that "we can fix this later, once we have more personnel/time/better technology". However, until now, no archive could show us proof that this concept actually worked.

Running the validation inside of the Submission Application isn't sensible, either. It's not the Submission Application's job to take over any tasks from the preservation system. Memory institutions generally will want to avoid re-implementing parts of the preservation system.

In a discussion with our customer we would argue that they are paying us for the service of preserving their content and keeping it useable over long time periods. We are paid to keep their quality high, or to paraphrase: "Kicking the customers' bottoms is part of the service that you are paying us a lot of money for and is useful for both sides alike." Any institutions that don't think this is necessary will be better off using one of plenty of normal backup services available on the market.

Conclusion

It sometimes might take a few extra minutes to contemplate one's own role as a digital preservationist. And it's good to take this time even and especially when we're under pressure.

Adendum

Another alternative of solving this issue could be to further secure the storage area of our preservation system that is reserved for SIPs that end up in the 'technical analyst' workbench, i.e. by providing three copies on storage layer. All valid IEs would keep going directly to the permanent repository and be cared for perfectly. All those IEs that are not fully valid would end up in the 'technical analyst's storage, where they could be stored for no longer than 10 years before being deleted. For this storage area, we'd only guarantee 'bitstream preservation', with the risk and the effort needed for repair operations being transparent for the customer. A further incentive to ingest "clean" IEs only into the preservation system is generated by the considerabely higher cost of for this storage area, as it is based on hard disk drives instead of the cheaper tape storage.

Freitag, 19. August 2016

Image File Directories reparieren

(english version below)

Vor Kurzem hatten mein Kollege Andreas und ich eine Diskussion darüber, wie man das defekte Image File Directory (IFD) einer TIFF-Datei reparieren könnte. Er hatte dazu eine Änderung in fixit_tiff eingebaut, die ein neues und korrigiertes IFD an das Ende der TIFF-Datei schreibt und das IFD-Offset einfach auf das neue IFD zeigen lässt, so wie es auch in der libtiff vorgesehen ist. Das ursprüngliche (defekte) IFD, das üblicherweise irgendwo am Anfang der Datei steht, wird dabei nicht verändert und liegt auch in der neuen Datei wieder vor. Der einzige Unterschied ist, dass jetzt das IFD-Offset nicht mehr auf das alte IFD zeigt und es damit von TIFF-Readern nicht mehr ausgelesen wird. Die Datei wächst also mit jeder Änderung am IFD an und es bleibt immer mehr "Müll" in der Datei zurück. Andererseits hat man aber auch eine Art Historie, weil alle bisherigen IFD-Versionen erhalten bleiben.

Für mich fühlte sich diese Methode unsauber an, weil ich den Meinung bin, dass Dateien keinen unreferenzierten Datenmüll enthalten sollten; insbesondere im Kontext der Langzeitarchivierung. Nicht nur ist es eine Verschwendung von Speicher, sondern späteren Datenarchäologen könnten daraus auch Probleme erwachsen, wenn sie versuchen, die Dateien zu interpretieren und dabei unreferenzierte Datenblöcke vorfinden.

Überraschenderweise (zumindest für mich) ist das Vorgehen aber völlig konform mit der Spezifikation und hat darüber hinaus noch weitere Vorteile.
  1. Die Änderung ist schnell und billig. An die bestehende Datei müssen nur ein paar Kilobytes angefügt und der IFD-Offset im Dateiheader korrigiert werden.
  2. Wie erwähnt bleibt die "Historie" erhalten.
  3. Alle anderen Offsets, die in der Datei verwendet werden, können unverändert bestehen bleiben. Dadurch wird das Verfahren sehr robust und fehlerunanfällig.
Inzwischen ist nun die Implementierung geändert worden. Da wir meist nur TIFF-Tags ändern oder löschen ist es unwahrscheinlich, dass das IFD sich vergrößert. Daher wird nun das IFD an Ort und Stelle verändert. Nun entsteht zwar zwischen dem IFD und den Bild-/Nutzdaten ein Leerraum, in dem potentiell Datenmüll steht, aber auch das wäre laut TIFF-Spezifikation erlaubt. Außerdem ist der Leerraum bedeutend kleiner als der große Block des ursprünglichen IFDs.

Es gibt aber noch eine dritte Möglichkeit, das Problem zu lösen. Dabei würde man die TIFF-Datei komplett neu schreiben, so dass keine Lücken zurückbleiben würden. Nach meinem Dafürhalten ist das die sauberste Option. Sie hat allerdings handfeste Nachteile.
  1. Der Entwicklungsaufwand ist hoch. Um die ganze Datei zu lesen, die einzelnen Bestandteile sicher zu verwalten und zu ändern, muss einiges an Programmcode geschrieben werden.
  2. Alle Offsets müssen geändert werden. Dieser Prozess ist fehleranfällig und bewegen die Datei weiter vom Original weg. Außerdem müssen auch Offsets innerhalb von privaten Tags geändert werden. Da dort aber die innere Struktur oft unbekannt ist, kann nicht sichergestellt werden, dass alle Offsets nach dem Schreiben noch korrekt sind.
  3. Die Datei muss neu geschrieben werden. Dabei steigt die Wahrscheinlichkeit, dass Bitfehler auftreten.
  4. Die Daten können nicht mehr verarbeitet werden, ohne die komplette Datei in den Speicher zu laden.
  5. Durch den hohen Aufwand wird ein höherer Datendurchsatz benötigt, die Hardware wird stärker belastet und es entsteht mehr Rechenzeit. Bei großen Mengen an zu korrigierenden Dateien kann sich dieser Mehraufwand deutlich bemerkbar machen.
Mich würde vor allem interessieren, ob es in der Community dazu schon Meinungen oder Best Practices gibt, und wie diese lauten. Welche Variante wird bevorzugt? Ein neues IFD anhängen, das bestehende IFD an Ort und Stelle ändern, oder die Datei komplett neu schreiben?
Ich selbst bin immer noch hin und her gerissen zwischen meinem Qualitätsanspruch einerseits und den hohen Kosten dafür andererseits.



english version

My colleagure Andreas and I recently had a discussion about the best way to fix the broken Image File Directory (IFD) of a TIF file. He had implemented a change in fixit_tiff to write a new corrected IFD to the end of the TIF-file and correct the IFD offset, just the way it is stipulatey by the libtiff. The original (defective) IFD, that is usually placed somewhere in the beginning of the file, is not changed at all and can be found in the new file as well. The key difference is that the IFD offset doesn't point to the old IFD anymore, making TIFF readers ignore it. Hence, the file grows with every change in the IFD and more and more "garbage" is kept in the file. On the other hand, a kind of version history is created inside of the TIFF itself, because all former IFD versions are kept.

For me, this method seemed unclean, because I think that files should not contain any unreferenced garbage date; especially so in the context of digital preservation. It's not only a waste of storage, but might lead to problems if data archaeologists one day try to interpret the data and find unreferenced blocks.

Most surprisingly (at least for me), this method completely complies with the TIFF specification and also brings some further advantages:
  1. It's a fast and cheap change. Only a few kilobytes need to be added to the file, and the IFD offset needs to be corrected.
  2. As mentioned before, the "history" stays intact.
  3. All other offsets used in the file can remain the same as before, which makes this method quite robust and sturdy.
In the meantime, the implementation has been changed. Given that we usually just change or delete TIFF tags, it's improbable that the IFD grows in size. Hence, now the IFD is changed in-place. Now there's a little free space between the IFD and the payload data, but that's supported by the TIFF specification as well. Moreover, the space is much smaller than the large block of the original IFD that remained when using the first method.

There is a third method to solve the problem. A TIFF writer could completely rewrite the entire file, leaving no free spaces whatsoever. In my opinion, this is the most elegant option. It does, however, have some serious disadvantages.

  1. The development would be quite an effort. A lot of code needs to be written to read, manage and alter all componentes of the file.
  2. All offsets need to be altered. This process is error prone and brings the files further from their original state. Furthermore, offsets inside of private tags need to be changed as well. However, as their inner structure is often unknown, no-one can make sure that all offsets are still correct after writing the file.
  3. The entire file needs be be rewritten. During this process, bit flip errors might occur.
  4. The files cannot be processed without loading the whole file into the RAM.
  5. Larger I/O capacities are needed, the hardware is stressed more and more CPU cycles are burnt. If there are larger amounts of files the need correction, this effort will surely be noticeable.
I would be most interested if the community already has opinions or best practices on this matter, and what these are. Which option do you prefer? Attaching a new IFD, altering the existing IFD in-place, or re-writing the whole file?
I myself am torn between my personal demand for high quality standards on the one hand and the high costs to reach them on the other hand.

Montag, 25. Juli 2016

ICC Farbprofile von TIFFs prüfen


Kaputte ICC Einbettung in TIFFs



Bei einigen TIFFs sind uns Fehler aufgefallen, weil die Größenangaben des ICC Profils nicht mit denen des TIFFs übereinstimmten.

Aus diesem Grunde hatten wir checkit_tiff eine Prüfroutine für die ICC-Header verpasst.

Hier ein Beispiel einer Ausgabe:


$ ./checkit_tiff -c /tmp/00000056.tif ../example_configs/cit_tiff6_baseline_SLUB.cfg
'./checkit_tiff' version: master
    revision: 85
licensed under conditions of libtiff (see http://libtiff.maptools.org/misc.html)
cfg_file=../example_configs/cit_tiff6_baseline_SLUB.cfg
tiff file=/tmp/00000056.tif
check if all IFDs are word aligned
check if only one IFD exists
check if tags are in ascending order
check if all offsets are used once only
check if all offsets are word aligned
check if tag 306 (DateTime) is correct
check if tag 34675 (ICC Profile) is correct
==> tag 34675 (ICC Profile) should have value pointing to valid ICC profile, but has value (values or count) preferred cmmtype ('APPL') should be empty or (possibly, because ICC validation is alpha code) one of following strings: 'ADBE' 'ACMS' 'appl' 'CCMS' 'UCCM' 'UCMS' 'EFI ' 'FF  ' 'EXAC' 'HCMM' 'argl' 'LgoS' 'HDM ' 'lcms' 'KCMS' 'MCML' 'WCS ' 'SIGN' 'RGMS' 'SICC' 'TCMM' '32BT' 'WTG ' 'zc00'
check if tag 256 (ImageWidth) has value in range 1 - 4294967295
check if tag 256 (ImageWidth) has valid type
check if tag 257 (ImageLength) has value in range 1 - 4294967295
check if tag 257 (ImageLength) has valid type
check if tag 258 (BitsPerSample) has these 3-values: 8, 8, 8
check if tag 258 (BitsPerSample) has valid type
check if tag 259 (Compression) has value
check if tag 259 (Compression) has valid type
check if tag 262 (Photometric) has value in range 0 - 2
check if tag 262 (Photometric) has valid type
check if tag 273 (StripOffsets) exists
check if tag 273 (StripOffsets) has valid type
check if tag 277 (SamplesPerPixel) has value
check if tag 277 (SamplesPerPixel) has valid type
check if tag 278 (RowsPerStrip) has value in range 1 - 4294967295
check if tag 278 (RowsPerStrip) has valid type
check if tag 279 (StripByteCounts) has value in range 1 - 4294967295
check if tag 279 (StripByteCounts) has valid type
check if tag 282 (XResolution) has value in range 300 - 1200
check if tag 282 (XResolution) has valid type
check if tag 283 (YResolution) has value in range 300 - 1200
check if tag 283 (YResolution) has valid type
check if tag 296 (ResolutionUnit) has value
check if tag 296 (ResolutionUnit) has valid type
check if tag 254 (SubFileType) has value
check if tag 254 (SubFileType) has valid type
check if tag 266 (FillOrder) has value
check if tag 266 (FillOrder) has valid type
check if tag 271 (Make) has  value matching regex '^[[:print:]]*$'
check if tag 272 (Model) has  value matching regex '^[[:print:]]*$'
check if tag 274 (Orientation) has value
check if tag 274 (Orientation) has valid type
check if tag 284 (PlanarConfig) has value
check if tag 284 (PlanarConfig) has valid type
check if tag 305 (Software) has  value matching regex '^[[:print:]]*$'
check if tag 306 (DateTime) has  value matching regex '^[12][901][0-9][0-9]:[01][0-9]:[0-3][0-9] [012][0-9]:[0-5][0-9]:[0-6][0-9]$'
check if tag 34675 (ICC Profile) exists
check if tag 34675 (ICC Profile) has valid type
check if forbidden tags are still existing
found 1 errors

Extraktion und Weitergehende Analyse  des ICC-Profils


Für eine weitergehende Analyse kann man ff. Vorgehen wählen:
  • Mit dem Werkzeug "exiftool" das ICC-Profil extrahieren:
    exiftool -icc_profile -b -w icc /tmp/kaputt.tiff
  • Mit dem ICC Profiler "profiledump" das extrahierte ICC-Profil "/tmp/kaputt.icc" laden und validieren:
    Windows: wxProfileDump.exe
    Linux: wine wxProfileDump.exe 
Hier die Beispielausgabe:


Montag, 11. Juli 2016

Warum "AIPUpdate" notwendig ist

In der Diskussion mit Archivaren ist mir in letzter Zeit immer wieder aufgefallen, dass diese mit dem Begriff "AIPUpdate" nichts anzufangen wissen und daher auch nicht verstehen, warum aus der Sicht von Bibliotheken das Thema "AIPUpdate" in der Überarbeitung des OAIS Referenzmodells mit aufgenommen werden sollte.

Klassische Archive


Ein klassisches Archiv arbeitet nach dem Provinienzprinzip, d.h. Archivalien werden nach ihrer Herkunft bzw. Entstehung geordnet. Meist erfolgt diese Ordnung in Form von Akten durch die schriftgutbildende Behörde. Wenn dieses Schriftgut an das Archiv übergeben wird, so handelt es sich dabei um abgeschlossene Dokumente.

Aus Sicht der klassischen Archive sind Änderungen am Archivgut nicht mehr zu erwarten. Diese Überzeugung hat sich auch im Bereich der digitalen Langzeitarchive erhalten.

Bibliotheken und Museen


Anders die Situation in den Bibliotheken und Museen. Diese arbeiten in aller Regel nach dem Pertinenzprinzip, d.h. der Ordnung nach Sachgruppen. Durch die damit einhergehende unterschiedliche Erschließung nach Sachgruppen können Dokumente zu unterschiedlichen Zeiten unterschiedlich gut tiefenerschlossen sein. Die Erschließung ist auch nicht immer perfekt, weil für viele Quellen bestimmte Informationen erst nach und nach durch die Geschichtswissenschaften ermittelt werden können.

Hinzu kommt, dass durch die schiere Menge von Digitalisaten allein im Projekt VD18 Fehler in der Digitalisierung entstehen, die nicht immer sofort auffallen.

Außerdem müssen Bibliotheken und v.a. auch Museen digitale Dokumente (z.B. elektronische Installationen) schon heute noch während der eigentlichen Lebenszeit langzeitarchivieren.

All diese Punkte führen dazu, dass im Gegensatz zu Archiven die Langzeitarchivierung in diesem Bereich mit teilweise unvollständigen, sich noch ändernden Dokumenten oder Dokumententeilen zu tun hat.

Mit dem AIPUpdate ist es möglich, zu einem bereits im Langzeitarchiv gesicherten Stand nachträglich eine vergessene Seite hinzuzufügen, einen Fehler zu korrigieren oder Metadaten zu ergänzen.

Prinzipien AIPUpdate


Damit AIPUpdate funktioniert, bedarf es in Langzeitarchivsystemen der Einhaltung folgender Prinzipien:
  1. Saubere Verwaltung eines persistenten Identifiers für die korrekte Zuordnung des Update zu im Langzeitarchiv befindlichen Vorgang
  2. Versionsverwaltung der AIPs im Langzeitarchiv
  3. Verbot der Löschung von "alten" AIPs (damit alle Versionen nachvollziehbar bleiben)
Da ein AIPUpdate immer auch eine Belastung für das Langzeitarchivsystem darstellt (z.B. Schreib-Lesevorgänge auf Bandspeichern, aber auch durch das Processing), sollten solche Operationen möglichst gebündelt ausgeführt werden.

Donnerstag, 9. Juni 2016

Formatidentifikation vs. Formatvalidierung - Wem glauben wir eigentlich?

Deutsch (english version below)


Wer in der Lage sein will, die Daten in seinem digitalen Langzeitarchiv auch in Zukunft noch durch Migrationen verfügbar zu halten, muss schon beim Ingest darauf achten, dass die eingelieferten Dateien auch den einschlägigen Standards und Spezifikationen entsprechen.

Bisher fährt man dafür einen zweistufigen Ansatz. Zuerst identifiziert man den Dateityp einer Datei (z. B. anhand der Dateiendung oder einer Signatur) mit einem Werkzeug wie DROID, dann prüft man sie mit einem Formatvalidator. Dieser Ansatz stellt den Anwender aber vor ein fundamentales Problem: was passiert, wenn eine Datei die Formatvalidierung nicht besteht? Wer hat Recht? Hat nicht gerade die Formatidentifizierung ergeben, dass man eine Datei eines bestimmten Formates vor sich hat? Warum widerspricht der Validator dann? Momentan speichert das Archivsystem das erkannte Format in den Metadaten ab, selbst wenn die Datei die Formatvalidierung nicht besteht.

Man kann also nur dann davon ausgehen, dass man z. B. eine TIFF-Datei vor sich hat, wenn der Aufbau der Datei auch der TIFF-Spezifikation entspricht. Ist das nicht der Fall, dann hat man auch kein TIFF vor sich, denn der innere Aufbau ist ja sehr eindeutig spezifiziert. Man hat also etwas vor sich, das nur ungefähr so aussieht wie eine TIFF-Datei, aber keine echte TIFF-Datei.

Eigentlich richtig wäre deshalb der restriktivere Ansatz. Die Formatidentifikation darf hier nur ein Hilfsmittel sein, um das richtige Validierungswerkzeug auszuwählen. Nur wenn die Validierung erfolgreich ist, darf auch das erkannte Dateiformat in den Metadaten festgehalten werden; die verbindliche Formatidentifikation findet also implizit bei der Formatvalidierung mit statt. Ist die Validierung nicht erfolgreich, dann könnte man noch das Formatidentifizierungswerkzeug befragen, ob evtl. eine ähnliche Signatur für einen anderen Dateityp hinterlegt ist, und dann die Validierung wiederholen. Ist das nicht der Fall, dann muss man von einem unbekannten Dateityp ausgehen und ggf. die Datei beim Ingest zurückweisen.

Zusatz für ganz Unerschrockene: viele Formate haben eingebettete Formate, Unterformate oder sind selbst Container für andere Formate. Genau genommen müsste man nicht nur das äußerste Format prüfen, sondern auch die korrekte Einbettung der Unterformate und deren eigene Validität. In das Langzeitarchiv dürften die Dateien nur dann aufgenommen werden, wenn auch alle ihre eingebetteten Dateien korrekt validiert werden können. Was das für TIFF (eingebettete ICC-Profile, XMP- & IPTC-Metadaten, ...), OpenOffice Dokumente (XML und Bilder in ZIP eingebettet), PDF (alle möglichen eingebetteten Dateiformate und Codeschnipsel, dazu Links zu externen Quellen), das Webarchivformat WARC (buchstäblich alle Formate, die auf Webseiten vorkommen können) und viele andere Formate bedeutet, mag sich jeder selbst in seinen Alpträumen von der Formathölle ausmalen. Klar ist: im Moment tun wir auch in Ermangelung geeigneter Werkzeuge viel zu wenig um sicherzustellen, dass nur valide Dateien in unsere Langzeitarchive gelangen.


Dienstag, 7. Juni 2016

Validating TIFFs with embedded color profiles

About ICC profile validation


In the last days we enhanced our baseline TIFF conformance checking tool "checkit_tiff" with support to validate TIFFs containing embedded ICC profiles.

There are two specifications of ICC profiles. The first and older one is from the year 2001 and available at http://www.color.org/ICC_Minor_Revision_for_Web.pdf. The second one (and current version) is  http://www.color.org/specification/ICC1v43_2010-12.pdf.

The ICC profile standards are very complex and do not really fit in the design of the checkit_tiff configuration files, so we decided to check only the headers of the embedded ICC profiles for now.

Because the differences between the headers of both standards are very marginal at first sight, this could be simple enough to additionally implement it in checkit_tiff.

For more detailed checks we would need a plugin system to delegate validation of embedded standards (as ICC, XMP and so on) to more highly specialized validators.

Ooops, our tool finds more broken TIFFs again


To test the validation, we ran checkit_tiff against some old tiffs from our digitization collection. As you can see in the following picture, the checkit_tiff tool detects a discrepancy between the size of the embedded ICC-profile as reported in TIFF-tag (34675) and the size reported by the ICC profile itself:





After some analysis we made an interesting observation. The given TIFF reports a size of 13691 bytes (in hex: 0x357b), but the ICC itself (tag "profile size") reports a size of 669051 bytes (in hex: 0xa357b). We thought we had a bug in our TIFF tag or ICC header decoding, but other tools (exiftool or tiffdump) also reported this difference.

As we saw in previous TIFFs, some TIFF implementations are wrong and often some information were missing because of off-by-one errors. In this case, it seems that the software "Omniscan 12.8 Build2476" does not correctly fill the Tiff-tag 34675 for ICC-profile, leaving out the most significant byte (here: '0xa').

We need your help


Anyway. Writing a conformance checker is a tough job and sometimes we introduce bugs in this kind of software as well. Therefore, please have a look at the code of checkit_tiff, test it and send us bug reports if you find any bugs.
The code can be found on https://github.com/SLUB-digitalpreservation/checkit_tiff.

Here are some open questions about ICC profiles that we have encountered:


  • We found some TIFFs which reported ICC version 4.2.0, but on http://www.color.org we only found versions 4.3.0 and 2.4.0. Could you help us to find out the differences in the headers for the different versions?



  • The meaning of the field "preferred CMM type" is unclear. We assume that the list of allowed strings is part of the document http://www.color.org/registry/signature/TagRegistry-2016-05.pdf. But we have also found a TIFF where the string 'Lino' is set for this ICC header field. Are we interpreting the document in a wrong way, or has the tag been set to an incorrect value?