[ome-devel] TIFF pyramid support in Bio-Formats - reference files for review

Damir Sudar dsudar at lbl.gov
Sat Mar 24 19:47:41 GMT 2018


Hi Roger,

I meanwhile found my mistake in makepyramid.ptif. Enclosed one that 
works correctly.

- Damir

On 3/23/2018 10:55, Damir Sudar wrote:
> Hi Roger,
>
> On 3/23/2018 2:46, Roger Leigh wrote:
>> On 23/03/18 01:40, Damir Sudar wrote:
>>> TIFFWriteDirectoryTagSubifd: Illegal value for SubIFD tag.
>>> TIFFWriteDirectoryTagSubifd: Illegal value for SubIFD tag.
>>> I'm using libtiff 4.0.9 and its associated tools on Ubuntu 14.04. The
>>> error does not happen with the scn files provided. Could it be related
>>> to having an offset value that is too large for a non-BigTIFF file?
>> Yes, you need to apply this change to libtiff:
>>   https://gitlab.com/libtiff/libtiff/merge_requests/25/diffs
>> Hopefully this will be in libtiff 4.0.10.  We must be the first users of
>> tiffset with BigTIFF images to run into this problem.
>>
> Indeed, with your merge request applied, it works correctly for svs 
> files and almost for my ptifs. I'm still chasing a small bug around 
> line 133 that causes the subresolutions pyramid to appear in its own 
> top-level IFD instead of all being stuck as SubIFDs into the single 
> top-level IFD. I'll keep chasing but in case you see my mistake?
>
>> I should also mention that the scripts have only been tested on Linux,
>> and might not run on other systems.  Hopefully they will be short-lived;
>> as soon as we have bfconvert supporting pyramids they can be forgotten.
>
> Yes, but for their intended purpose, these scripts are great.
> Once I get the ptif one to work correctly, I'll mock up some more 
> example files including some with larger numbers of channels, Z and t.
>
>> - also, all these examples carry some of those ancillary images such as
>>> slide labels, overview images, etc. While the scripts handled those
>>> correctly as far as I can see, a reader would have to be pretty 
>>> smart to
>>> figure out which of the contents of such an output file is the actual
>>> image and which are those ancillary images.
>>
>> Absolutely.  We will need to do something about these as a followup
>> task, to add the metadata to identify these as labels, overviews, etc.
>>
> Ok, I'll start looking at options how to do so.
>
> Cheers,
> - Damir
>>
>> Kind regards,
>> Roger
>>
>> The University of Dundee is a registered Scottish Charity, No: SC015096
>

-- 
Damir Sudar - Affiliate Scientist
Lawrence Berkeley Natl Laboratory / MBIB
One Cyclotron Road, MS 977, Berkeley, CA 94720, USA
T: 510/486-5346 - F: 510/486-5586 - E: DSudar at lbl.gov
http://biosciences.lbl.gov/profiles/damir-sudar-2/

Visiting Scientist, Oregon Health & Science University

-------------- next part --------------
#!/bin/bash

set -e
set -x

# Check if file is BigTIFF
# $1 file
bigtiff() {
    if [ "0000000 4949 002b" != "$(dd if="$1" iflag=count_bytes count=4 | od -x | head -n1)" ]; then
        return 1
    fi
    return 0
}

# Get fieldoffset for TIFF
# $1 file
fieldoffset() {
    if bigtiff "$1"; then
        echo 8
    else
        echo 2
    fi
}

# Get fieldsize for TIFF
# $1 file
fieldsize() {
    if bigtiff "$1"; then
        echo 20
    else
        echo 12
    fi
}

# Get IFD offsets
# $1=IFD number
# $2=file
diroffsets() {
    tiffinfo "$dest" | grep "TIFF Directory at offset" | sed -e 's;.*(\(.*\))$;\1;'
}

# Get offset for IFD
# $1=IFD number
# $2=file
diroffset() {
    diroffsets "$2" | head -n$(($1 + 1)) | tail -n1
}

# Get number of tags in directory
# $1=IFD offset
# $2=file
ntags() {
    echo "od -j $1 -N 2 -d \"$2\"" >&2
  od -j $1 -N 2 -d "$2" | head -n1 | sed -e 's;^[0-9]* *\(.*\);\1;'
}

# Offset of next pointer in IFD
# $1=IFD offset
# $2=file
nextoffset() {
    echo "$(($1 + $(fieldoffset "$2") + ($(ntags $1 "$2") * $(fieldsize "$2"))))"
}

# Write uint64 little endian value to binary file
# $1=value
# $2=destination file
# $3=offset in file
update_uint64_le() {
    if bigtiff "$2"; then
        printf "$(printf %.16x $1 | sed -e 's;\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)\(..\);\8\7\6\5\4\3\2\1;' | sed -e 's;\(..\);\\x\1;g')" | dd of="$2" conv=notrunc,nocreat oflag=seek_bytes seek=$3
    else
        printf "$(printf %.8x $1 | sed -e 's;\(..\)\(..\)\(..\)\(..\);\4\3\2\1;' | sed -e 's;\(..\);\\x\1;g')" | dd of="$2" conv=notrunc,nocreat oflag=seek_bytes seek=$3
    fi
}

makeuuid() {
    echo "urn:uuid:$(uuidgen)"
}

src="$(ls -1 orig/*.ptif)"
mkdir -p new

for srcfile in $src; do
    base="$(basename $srcfile)"
    dest="new/${base%.ptif}-subifds.tiff"

    cp "$srcfile" "$dest"

    nifds=$(tiffinfo "$dest" | grep "TIFF Directory at offset" | wc -l)
    echo "IFD count: $nifds"

    ifds=$(seq 0 $(($nifds - 1)))
    mainifd=$(echo "$ifds" | head -n1)
#    otherifds=$(echo "$ifds" | tail -n2)
    otherifds=''
    subifds=$(echo "$ifds" | tail -n$((nifds-1)))
    nsubifds=$(echo "$subifds" | wc -l)
    echo "IFDs: $ifds"
    echo "Main IFDs: $mainifd"
    echo "Other IFDs: $otherifds"
    echo "SUBIFDs: $subifds"

    # Main header
    tiffset -d 0 -s 270 "OME Pyramid TIFF test (from $base)" "$dest"
    tiffset -d 0 -s 305 "A gnarly shell script (makepyramid-ptif)" "$dest"
    tiffset -d 0 -s 315 "Roger Leigh <rleigh at dundee.ac.uk>" "$dest"

    # NewSubFileType
    for ifd in $mainifd $otherifds; do
        tiffset -d $ifd -s 254 0 "$dest"
    done
    for ifd in $subifds; do
        tiffset -d $ifd -s 254 1 "$dest"
    done

    # SubIFDs
    subifds_diroffs=$(echo $(tiffinfo "$dest" | grep "TIFF Directory at offset" | sed -e 's;.*(\(.*\))$;\1;' | tail -n$((nifds-1))))
    echo "SubIFDs for series 0: $subifds_diroffs"
    tiffset -d 0 -s 330 $nsubifds $subifds_diroffs "$dest"
    subifds_diroffs=$(echo $(tiffinfo "$dest" | grep "TIFF Directory at offset" | sed -e 's;.*(\(.*\))$;\1;' | tail -n$((nifds-1))))
    echo "Updated SubIFDs for series 0: $subifds_diroffs"

    echo "New directories:"
    diroffsets "$dest"

    dest2="${dest%.tiff}-flat.tiff"
    cp "$dest" "$dest2"

    # Relink IFDs to elide SubIFDs
    series0dir="$(diroffset 0 "$dest")"
    echo "s0dir $series0dir"
# assumption: only one real IFD per file - this needs revision if multiple real IFDs
#    seriesndir="$(diroffset $(echo "$otherifds" | head -n1) "$dest")"
#    echo "sndir $seriesndir"

    noffset="$(nextoffset $series0dir "$dest")"
#    echo "UPDATE: $series0dir $noffset -> [$seriesndir]"
#    update_uint64_le $seriesndir "$dest" $noffset
    echo "UPDATE: $series0dir $noffset -> 0"
    update_uint64_le 0 "$dest" $noffset

    for offset in $subifds_diroffs; do
        c="$(ntags $offset "$dest")"
        echo "NTAGS: $c"
        noffset="$(nextoffset $offset "$dest")"
        echo "UPDATE: $offset $noffset -> 0"
        update_uint64_le 0 "$dest" $noffset
    done

    tiffinfo "$dest"

    # Create OME-XML metadata for the files.
    dest_ometiff="${dest%.tiff}.ome.tiff"
    dest2_ometiff="${dest2%.tiff}.ome.tiff"
    cp "$dest" "$dest_ometiff"
    cp "$dest2" "$dest2_ometiff"

    bfomexml="$(showinf -nopix -noflat -omexml -omexml-only "$srcfile")"

    # Add TiffData elements.
    uuid="$(makeuuid)"
    ome_attr="Creator=\"makepyramid-ptif\" UUID=\"${uuid}\""
    tiffdata_fmt="<TiffData FirstC=\"0\" FirstT=\"0\" FirstZ=\"0\" IFD=\"%d\" PlaneCount=\"1\"><UUID FileName=\"$(basename "${dest_ometiff}")\">${uuid}</UUID></TiffData>"
    tiffdata_fmt_flat="<TiffData FirstC=\"0\" FirstT=\"0\" FirstZ=\"0\" IFD=\"%d\" PlaneCount=\"1\"><UUID FileName=\"$(basename "${dest2_ometiff}")\">${uuid}</UUID></TiffData>"

    omexml_fmt="$(echo "$bfomexml" | sed -e "s;\(<OME.*\)\(\">\);\1\" ${ome_attr}>;" -e "s;<MetadataOnly\/>;${tiffdata_fmt};")"
    omexml_fmt_flat="$(echo "$bfomexml" | sed -e "s;\(<OME.*\)\(\">\);\1\" ${ome_attr}>;" -e "s;<MetadataOnly\/>;${tiffdata_fmt_flat};")"

# assumption: one real IFD per file - original was based on SVS file which has label and macro image as well
#    ifds="0 1 2"
    ifds="0"
    omexml="$(printf "$omexml_fmt" $ifds)"

    flatifds="$(echo $mainifd $otherifds)"
    omexml_flat="$(printf "$omexml_fmt" $flatifds)"

    tiffset -d 0 -s 270 "$omexml" "$dest_ometiff"
    tiffset -d 0 -s 270 "$omexml_flat" "$dest2_ometiff"
done


More information about the ome-devel mailing list