def imsave(filename, data, photometric=None, planarconfig=None,
           resolution=None, description=None, software='tifffile.py',
           byteorder=None, bigtiff=False):
    """Write image data to TIFF file.

    Image data are written uncompressed in one stripe per plane.
    Dimensions larger than 2 or 3 (depending on photometric mode and
    planar configuration) are flattened and saved as separate pages.

    Parameters
    ----------
    filename : str
        Name of file to write.
    data : array_like
        Input image. The last dimensions are assumed to be image height,
        width, and samples.
    photometric : {'minisblack', 'miniswhite', 'rgb'}
        The color space of the image data.
        By default this setting is inferred from the data shape.
    planarconfig : {'contig', 'planar'}
        Specifies if samples are stored contiguous or in separate planes.
        By default this setting is inferred from the data shape.
        'contig': last dimension contains samples.
        'planar': third last dimension contains samples.
    resolution : ((int, int), (int, int))
        X and Y resolution in dots per inch as rational numbers.
    description : str
        The subject of the image. Saved with the first page only.
    software : str
        Name of the software used to create the image.
        Saved with the first page only.
    byteorder : {'<', '>'}
        The endianness of the data in the file.
        By default this is the system's native byte order.
    bigtiff : bool
        If True the BigTIFF format is used.
        By default the standard TIFF format is used for data less than 2040 MB.

    Examples
    --------
    >>> data = numpy.random.rand(10, 3, 301, 219)
    >>> imsave('temp.tif', data)

    """
    assert(photometric in (None, 'minisblack', 'miniswhite', 'rgb'))
    assert(planarconfig in (None, 'contig', 'planar'))
    assert(byteorder in (None, '<', '>'))

    if byteorder is None:
        byteorder = '<' if sys.byteorder == 'little' else '>'

    data = numpy.asarray(data, dtype=byteorder+data.dtype.char, order='C')
    data_shape = shape = data.shape
    data = numpy.atleast_2d(data)

    if not bigtiff and data.size * data.dtype.itemsize < 2040*2**20:
        bigtiff = False
        offset_size = 4
        tag_size = 12
        numtag_format = 'H'
        offset_format = 'I'
        val_format = '4s'
    else:
        bigtiff = True
        offset_size = 8
        tag_size = 20
        numtag_format = 'Q'
        offset_format = 'Q'
        val_format = '8s'

    # unify shape of data
    samplesperpixel = 1
    extrasamples = 0
    if photometric is None:
        if data.ndim > 2 and (shape[-3] in (3, 4) or shape[-1] in (3, 4)):
            photometric = 'rgb'
        else:
            photometric = 'minisblack'
    if photometric == 'rgb':
        if len(shape) < 3:
            raise ValueError("not a RGB(A) image")
        if planarconfig is None:
            planarconfig = 'planar' if shape[-3] in (3, 4) else 'contig'
        if planarconfig == 'contig':
            if shape[-1] not in (3, 4):
                raise ValueError("not a contiguous RGB(A) image")
            data = data.reshape((-1, 1) + shape[-3:])
            samplesperpixel = shape[-1]
        else:
            if shape[-3] not in (3, 4):
                raise ValueError("not a planar RGB(A) image")
            data = data.reshape((-1, ) + shape[-3:] + (1, ))
            samplesperpixel = shape[-3]
        if samplesperpixel == 4:
            extrasamples = 1
    elif planarconfig and len(shape) > 2:
        if planarconfig == 'contig':
            data = data.reshape((-1, 1) + shape[-3:])
            samplesperpixel = shape[-1]
        else:
            data = data.reshape((-1, ) + shape[-3:] + (1, ))
            samplesperpixel = shape[-3]
        extrasamples = samplesperpixel - 1
    else:
        planarconfig = None
        data = data.reshape((-1, 1) + shape[-2:] + (1, ))

    shape = data.shape  # (pages, planes, height, width, contig samples)

    bytestr = bytes if sys.version[0] == '2' else lambda x: bytes(x, 'ascii')
    tifftypes = {'B': 1, 's': 2, 'H': 3, 'I': 4, '2I': 5, 'b': 6,
                 'h': 8, 'i': 9, 'f': 11, 'd': 12, 'Q': 16, 'q': 17}
    tifftags = {'new_subfile_type': 254, 'subfile_type': 255,
        'image_width': 256, 'image_length': 257, 'bits_per_sample': 258,
        'compression': 259, 'photometric': 262, 'fill_order': 266,
        'document_name': 269, 'image_description': 270, 'strip_offsets': 273,
        'orientation': 274, 'samples_per_pixel': 277, 'rows_per_strip': 278,
        'strip_byte_counts': 279, 'x_resolution': 282, 'y_resolution': 283,
        'planar_configuration': 284, 'page_name': 285, 'resolution_unit': 296,
        'software': 305, 'datetime': 306, 'predictor': 317, 'color_map': 320,
        'extra_samples': 338, 'sample_format': 339}

    tags = []
    tag_data = []

    def pack(fmt, *val):
        return struct.pack(byteorder+fmt, *val)

    def tag(name, dtype, number, value, offset=[0]):
        # append tag binary string to tags list
        # append (offset, value as binary string) to tag_data list
        # increment offset by tag_size
        if dtype == 's':
            value = bytestr(value) + b'\0'
            number = len(value)
            value = (value, )
        t = [pack('HH', tifftags[name], tifftypes[dtype]),
             pack(offset_format, number)]
        if len(dtype) > 1:
            number *= int(dtype[:-1])
            dtype = dtype[-1]
        if number == 1:
            if isinstance(value, (tuple, list)):
                value = value[0]
            t.append(pack(val_format, pack(dtype, value)))
        elif struct.calcsize(dtype) * number <= offset_size:
            t.append(pack(val_format, pack(str(number)+dtype, *value)))
        else:
            t.append(pack(offset_format, 0))
            tag_data.append((offset[0] + offset_size + 4,
                             pack(str(number)+dtype, *value)))
        tags.append(b''.join(t))
        offset[0] += tag_size

    if software:
        tag('software', 's', 0, software)
    if description:
        tag('image_description', 's', 0, description)
    elif shape != data_shape:
        tag('image_description', 's', 0,
            "shape=(%s)" % (",".join('%i' % i for i in data_shape)))
    tag('datetime', 's', 0,
        datetime.datetime.now().strftime("%Y:%m:%d %H:%M:%S"))
    # write previous tags only once
    writeonce = (len(tags), len(tag_data)) if shape[0] > 1 else None
    tag('compression', 'H', 1, 1)
    tag('orientation', 'H', 1, 1)
    tag('image_width', 'I', 1, shape[-2])
    tag('image_length', 'I', 1, shape[-3])
    tag('new_subfile_type', 'I', 1, 0 if shape[0] == 1 else 2)
    tag('sample_format', 'H', 1,
        {'u': 1, 'i': 2, 'f': 3, 'c': 6}[data.dtype.kind])
    tag('photometric', 'H', 1,
        {'miniswhite': 0, 'minisblack': 1, 'rgb': 2}[photometric])
    tag('samples_per_pixel', 'H', 1, samplesperpixel)
    if planarconfig:
        tag('planar_configuration', 'H', 1, 1 if planarconfig=='contig' else 2)
        tag('bits_per_sample', 'H', samplesperpixel,
            (data.dtype.itemsize * 8, ) * samplesperpixel)
    else:
        tag('bits_per_sample', 'H', 1, data.dtype.itemsize * 8)
    if extrasamples:
        if photometric == 'rgb':
            tag('extra_samples', 'H', 1, 1)  # alpha channel
        else:
            tag('extra_samples', 'H', extrasamples, (0, ) * extrasamples)
    if resolution:
        tag('x_resolution', '2I', 1, resolution[0])
        tag('y_resolution', '2I', 1, resolution[1])
        tag('resolution_unit', 'H', 1, 2)
    tag('rows_per_strip', 'I', 1, shape[-3])
    # use one strip per plane
    strip_byte_counts = (data[0, 0].size * data.dtype.itemsize, ) * shape[1]
    tag('strip_byte_counts', offset_format, shape[1], strip_byte_counts)
    # strip_offsets must be the last tag; will be updated later
    tag('strip_offsets', offset_format, shape[1], (0, ) * shape[1])

    fd = open(filename, 'wb')
    seek = fd.seek
    tell = fd.tell

    def write(arg, *args):
        fd.write(pack(arg, *args) if args else arg)

    write({'<': b'II', '>': b'MM'}[byteorder])
    if bigtiff:
        write('HHH', 43, 8, 0)
    else:
        write('H', 42)
    ifd_offset = tell()
    write(offset_format, 0)  # first IFD
    for i in range(shape[0]):
        # update pointer at ifd_offset
        pos = tell()
        seek(ifd_offset)
        write(offset_format, pos)
        seek(pos)
        # write tags
        write(numtag_format, len(tags))
        tag_offset = tell()
        write(b''.join(tags))
        ifd_offset = tell()
        write(offset_format, 0)  # offset to next ifd
        # write extra tag data and update pointers
        for off, dat in tag_data:
            pos = tell()
            seek(tag_offset + off)
            write(offset_format, pos)
            seek(pos)
            write(dat)
        # update strip_offsets
        pos = tell()
        if len(strip_byte_counts) == 1:
            seek(ifd_offset - offset_size)
            write(offset_format, pos)
        else:
            seek(pos - offset_size*shape[1])
            strip_offset = pos
            for size in strip_byte_counts:
                write(offset_format, strip_offset)
                strip_offset += size
        seek(pos)
        # write data
        data[i].tofile(fd)  # if this fails, try update Python and numpy
        fd.flush()
        # remove tags that should be written only once
        if writeonce:
            tags = tags[writeonce[0]:]
            d = writeonce[0] * tag_size
            tag_data = [(o-d, v) for (o, v) in tag_data[writeonce[1]:]]
            writeonce = None
    fd.close()
def imsave ( filename , data , photometric = None , planarconfig = None , resolution = None , description = None , software = 'tifffile.py' , byteorder = None , bigtiff = False ) : assert ( photometric in ( None , 'minisblack' , 'miniswhite' , 'rgb' ) ) assert ( planarconfig in ( None , 'contig' , 'planar' ) ) assert ( byteorder in ( None , '<' , '>' ) ) if byteorder is None : byteorder = '<' if sys . byteorder == 'little' else '>' data = numpy . asarray ( data , dtype = byteorder + data . dtype . char , order = 'C' ) data_shape = shape = data . shape data = numpy . atleast_2d ( data ) if not bigtiff and data . size * data . dtype . itemsize < 2040 * 2 ** 20 : bigtiff = False offset_size = 4 tag_size = 12 numtag_format = 'H' offset_format = 'I' val_format = '4s' else : bigtiff = True offset_size = 8 tag_size = 20 numtag_format = 'Q' offset_format = 'Q' val_format = '8s' samplesperpixel = 1 extrasamples = 0 if photometric is None : if data . ndim > 2 and ( shape [ - 3 ] in ( 3 , 4 ) or shape [ - 1 ] in ( 3 , 4 ) ) : photometric = 'rgb' else : photometric = 'minisblack' if photometric == 'rgb' : if len ( shape ) < 3 : raise ValueError ( "not a RGB(A) image" ) if planarconfig is None : planarconfig = 'planar' if shape [ - 3 ] in ( 3 , 4 ) else 'contig' if planarconfig == 'contig' : if shape [ - 1 ] not in ( 3 , 4 ) : raise ValueError ( "not a contiguous RGB(A) image" ) data = data . reshape ( ( - 1 , 1 ) + shape [ - 3 : ] ) samplesperpixel = shape [ - 1 ] else : if shape [ - 3 ] not in ( 3 , 4 ) : raise ValueError ( "not a planar RGB(A) image" ) data = data . reshape ( ( - 1 , ) + shape [ - 3 : ] + ( 1 , ) ) samplesperpixel = shape [ - 3 ] if samplesperpixel == 4 : extrasamples = 1 elif planarconfig and len ( shape ) > 2 : if planarconfig == 'contig' : data = data . reshape ( ( - 1 , 1 ) + shape [ - 3 : ] ) samplesperpixel = shape [ - 1 ] else : data = data . reshape ( ( - 1 , ) + shape [ - 3 : ] + ( 1 , ) ) samplesperpixel = shape [ - 3 ] extrasamples = samplesperpixel - 1 else : planarconfig = None data = data . reshape ( ( - 1 , 1 ) + shape [ - 2 : ] + ( 1 , ) ) shape = data . shape bytestr = bytes if sys . version [ 0 ] == '2' else lambda x : bytes ( x , 'ascii' ) tifftypes = { 'B' : 1 , 's' : 2 , 'H' : 3 , 'I' : 4 , '2I' : 5 , 'b' : 6 , 'h' : 8 , 'i' : 9 , 'f' : 11 , 'd' : 12 , 'Q' : 16 , 'q' : 17 } tifftags = { 'new_subfile_type' : 254 , 'subfile_type' : 255 , 'image_width' : 256 , 'image_length' : 257 , 'bits_per_sample' : 258 , 'compression' : 259 , 'photometric' : 262 , 'fill_order' : 266 , 'document_name' : 269 , 'image_description' : 270 , 'strip_offsets' : 273 , 'orientation' : 274 , 'samples_per_pixel' : 277 , 'rows_per_strip' : 278 , 'strip_byte_counts' : 279 , 'x_resolution' : 282 , 'y_resolution' : 283 , 'planar_configuration' : 284 , 'page_name' : 285 , 'resolution_unit' : 296 , 'software' : 305 , 'datetime' : 306 , 'predictor' : 317 , 'color_map' : 320 , 'extra_samples' : 338 , 'sample_format' : 339 } tags = [ ] tag_data = [ ] def pack ( fmt , * val ) : return struct . pack ( byteorder + fmt , * val ) def tag ( name , dtype , number , value , offset = [ 0 ] ) : if dtype == 's' : value = bytestr ( value ) + b'\0' number = len ( value ) value = ( value , ) t = [ pack ( 'HH' , tifftags [ name ] , tifftypes [ dtype ] ) , pack ( offset_format , number ) ] if len ( dtype ) > 1 : number *= int ( dtype [ : - 1 ] ) dtype = dtype [ - 1 ] if number == 1 : if isinstance ( value , ( tuple , list ) ) : value = value [ 0 ] t . append ( pack ( val_format , pack ( dtype , value ) ) ) elif struct . calcsize ( dtype ) * number <= offset_size : t . append ( pack ( val_format , pack ( str ( number ) + dtype , * value ) ) ) else : t . append ( pack ( offset_format , 0 ) ) tag_data . append ( ( offset [ 0 ] + offset_size + 4 , pack ( str ( number ) + dtype , * value ) ) ) tags . append ( b'' . join ( t ) ) offset [ 0 ] += tag_size if software : tag ( 'software' , 's' , 0 , software ) if description : tag ( 'image_description' , 's' , 0 , description ) elif shape != data_shape : tag ( 'image_description' , 's' , 0 , "shape=(%s)" % ( "," . join ( '%i' % i for i in data_shape ) ) ) tag ( 'datetime' , 's' , 0 , datetime . datetime . now ( ) . strftime ( "%Y:%m:%d %H:%M:%S" ) ) writeonce = ( len ( tags ) , len ( tag_data ) ) if shape [ 0 ] > 1 else None tag ( 'compression' , 'H' , 1 , 1 ) tag ( 'orientation' , 'H' , 1 , 1 ) tag ( 'image_width' , 'I' , 1 , shape [ - 2 ] ) tag ( 'image_length' , 'I' , 1 , shape [ - 3 ] ) tag ( 'new_subfile_type' , 'I' , 1 , 0 if shape [ 0 ] == 1 else 2 ) tag ( 'sample_format' , 'H' , 1 , { 'u' : 1 , 'i' : 2 , 'f' : 3 , 'c' : 6 } [ data . dtype . kind ] ) tag ( 'photometric' , 'H' , 1 , { 'miniswhite' : 0 , 'minisblack' : 1 , 'rgb' : 2 } [ photometric ] ) tag ( 'samples_per_pixel' , 'H' , 1 , samplesperpixel ) if planarconfig : tag ( 'planar_configuration' , 'H' , 1 , 1 if planarconfig == 'contig' else 2 ) tag ( 'bits_per_sample' , 'H' , samplesperpixel , ( data . dtype . itemsize * 8 , ) * samplesperpixel ) else : tag ( 'bits_per_sample' , 'H' , 1 , data . dtype . itemsize * 8 ) if extrasamples : if photometric == 'rgb' : tag ( 'extra_samples' , 'H' , 1 , 1 ) else : tag ( 'extra_samples' , 'H' , extrasamples , ( 0 , ) * extrasamples ) if resolution : tag ( 'x_resolution' , '2I' , 1 , resolution [ 0 ] ) tag ( 'y_resolution' , '2I' , 1 , resolution [ 1 ] ) tag ( 'resolution_unit' , 'H' , 1 , 2 ) tag ( 'rows_per_strip' , 'I' , 1 , shape [ - 3 ] ) strip_byte_counts = ( data [ 0 , 0 ] . size * data . dtype . itemsize , ) * shape [ 1 ] tag ( 'strip_byte_counts' , offset_format , shape [ 1 ] , strip_byte_counts ) tag ( 'strip_offsets' , offset_format , shape [ 1 ] , ( 0 , ) * shape [ 1 ] ) fd = open ( filename , 'wb' ) seek = fd . seek tell = fd . tell def write ( arg , * args ) : fd . write ( pack ( arg , * args ) if args else arg ) write ( { '<' : b'II' , '>' : b'MM' } [ byteorder ] ) if bigtiff : write ( 'HHH' , 43 , 8 , 0 ) else : write ( 'H' , 42 ) ifd_offset = tell ( ) write ( offset_format , 0 ) for i in range ( shape [ 0 ] ) : pos = tell ( ) seek ( ifd_offset ) write ( offset_format , pos ) seek ( pos ) write ( numtag_format , len ( tags ) ) tag_offset = tell ( ) write ( b'' . join ( tags ) ) ifd_offset = tell ( ) write ( offset_format , 0 ) for off , dat in tag_data : pos = tell ( ) seek ( tag_offset + off ) write ( offset_format , pos ) seek ( pos ) write ( dat ) pos = tell ( ) if len ( strip_byte_counts ) == 1 : seek ( ifd_offset - offset_size ) write ( offset_format , pos ) else : seek ( pos - offset_size * shape [ 1 ] ) strip_offset = pos for size in strip_byte_counts : write ( offset_format , strip_offset ) strip_offset += size seek ( pos ) data [ i ] . tofile ( fd ) fd . flush ( ) if writeonce : tags = tags [ writeonce [ 0 ] : ] d = writeonce [ 0 ] * tag_size tag_data = [ ( o - d , v ) for ( o , v ) in tag_data [ writeonce [ 1 ] : ] ] writeonce = None fd . close ( )
Write image data to TIFF file.

    Image data are written uncompressed in one stripe per plane.
    Dimensions larger than 2 or 3 (depending on photometric mode and
    planar configuration) are flattened and saved as separate pages.

    Parameters
    ----------
    filename : str
        Name of file to write.
    data : array_like
        Input image. The last dimensions are assumed to be image height,
        width, and samples.
    photometric : {'minisblack', 'miniswhite', 'rgb'}
        The color space of the image data.
        By default this setting is inferred from the data shape.
    planarconfig : {'contig', 'planar'}
        Specifies if samples are stored contiguous or in separate planes.
        By default this setting is inferred from the data shape.
        'contig': last dimension contains samples.
        'planar': third last dimension contains samples.
    resolution : ((int, int), (int, int))
        X and Y resolution in dots per inch as rational numbers.
    description : str
        The subject of the image. Saved with the first page only.
    software : str
        Name of the software used to create the image.
        Saved with the first page only.
    byteorder : {'<', '>'}
        The endianness of the data in the file.
        By default this is the system's native byte order.
    bigtiff : bool
        If True the BigTIFF format is used.
        By default the standard TIFF format is used for data less than 2040 MB.

    Examples
    --------
    >>> data = numpy.random.rand(10, 3, 301, 219)
    >>> imsave('temp.tif', data)