# Exporting band data

This tutorial shows how to convert ENVISAT raster information from dataset and generate flat binary rasters using PyEPR.

The program generates as many raster as the dataset specified in input.

The example code (`examples/write_bands.py`) is a direct translation of the C sample program write_bands.c bundled with the EPR API distribution.

The program is invoked as follows:

    $ python write_bands.py <envisat-product> \
    <output directory for the raster file> <dataset name 1> \
    [<dataset name 2> ... <dataset name N>]

## Import section

To use the Python EPR API one have to import `epr` module.

At first import time the underlaying C library is opportunely initialized.

    #!/usr/bin/env python3

    # This program is a direct translation of the sample program
    # "write_bands.c" bundled with the EPR-API distribution.
    #
    # Source code of the C program is available at:
    # https://github.com/bcdev/epr-api/blob/master/src/examples/write_bands.c

    from __future__ import print_function

    import os
    import sys
    import epr

## The main program

The main program in quite simple (this is just an example).

    def main(*argv):
        '''A program for converting producing ENVI raster information from
        dataset.

        It generates as many raster as there are dataset entrance parameters.

        Call::

            $ write_bands.py <envisat-product>
                             <output directory for the raster file>
                             <dataset name 1>
                             [<dataset name 2> ... <dataset name N>]

        Example::

            $ write_bands.py \
            MER_RR__1PNPDK20020415_103725_000002702005_00094_00649_1059.N1 \
            . latitude

        '''

        if not argv:
            argv = sys.argv

        if len(argv) <= 3:
            print('Usage: write_bands.py <envisat-product> <output-dir> '
                  '<dataset-name-1>')
            print('                      [<dataset-name-2> ... <dataset-name-N>]')
            print('  where envisat-product is the input filename')
            print('  and output-dir is the output directory')
            print('  and dataset-name-1 is the name of the first band to be '
                  'extracted (mandatory)')
            print('  and dataset-name-2 ... dataset-name-N are the names of '
                  'further bands to be extracted (optional)')
            print('Example:')
            print('  write_bands MER_RR__2P_TEST.N1 . latitude')
            print()
            sys.exit(1)

        product_file_path = argv[1]
        output_dir_path = argv[2]

        # Open the product; an argument is a path to product data file
        with epr.open(product_file_path) as product:
            for band_name in argv[3:]:
                write_raw_image(output_dir_path, product, band_name)

    if __name__ == '__main__':
        main()

It performs some basic command line arguments handling and then open the input product.

        # Open the product; an argument is a path to product data file
        with epr.open(product_file_path) as product:

Finally the core function (`write_raw_image()`) is called on each band specified on the command:

            for band_name in argv[3:]:
                write_raw_image(output_dir_path, product, band_name)

## The `write_raw_image()` core function

The core function is `write_raw_image()`.

    def write_raw_image(output_dir, product, band_name):
        '''Generate the ENVI binary pattern image file for an actual DS.

        The first parameter is the output directory path.

        '''

        # Build ENVI file path, DS name specifically
        image_file_path = os.path.join(output_dir, band_name + '.raw')

        band = product.get_band(band_name)
        source_w = product.get_scene_width()
        source_h = product.get_scene_height()
        source_step_x = 1
        source_step_y = 1

        raster = band.create_compatible_raster(source_w, source_h,
                                               source_step_x, source_step_y)

        print('Reading band "%s"...' % band_name)
        raster = band.read_raster(0, 0, raster)

        out_stream = open(image_file_path, 'wb')

        for line in raster.data:
            out_stream.write(line.tostring())
        # or better: raster.data.tofile(out_stream)

        out_stream.close()

        print('Raw image data successfully written to "%s".' % image_file_path)
        print('C data type is "%s", element size %u byte(s), '
              'raster size is %u x %u pixels.' % (
              epr.data_type_id_to_str(raster.data_type),
              raster.get_elem_size(),
              raster.get_width(),
              raster.get_height()))

It generates a flat binary file with data of a single band whose name is specified as input parameter.

First the output file name is computed using the `os` module.

        # Build ENVI file path, DS name specifically
        image_file_path = os.path.join(output_dir, band_name + '.raw')

Then the desired band is retrieved using the `epr.Product.get_band()` method and some of its parameters are loaded in to local variables:

        band = product.get_band(band_name)

Band data are accessed by means of a `epr.Raster` object.

See also

`epr.Band.read_as_array()`

The `epr.Band.create_compatible_raster()` is a facility method that allows to instantiate a `epr.Raster` object with a data type compatible with the band data:

        raster = band.create_compatible_raster(source_w, source_h,
                                               source_step_x, source_step_y)

Then data are read using the `epr.Band.read_raster()` method:

        print('Reading band "%s"...' % band_name)
        raster = band.read_raster(0, 0, raster)

Then the output file object is created (in binary mode of course)

        out_stream = open(image_file_path, 'wb')

and data are copied to the output file one line at time

        for line in raster.data:
            out_stream.write(line.tostring())

Please note that it has been used `epr.Raster.data` attribute of the `epr.Raster` objects that exposes `epr.Raster` data with the powerful `numpy.ndarray` interface.

Note

copying one line at time is not the best way to perform the task in Python. It has been done just to mimic the original C code:

    out_stream = fopen(image_file_path, "wb");
    if (out_stream == NULL) {
        printf("Error: can't open '%s'\n", image_file_path);
        return 3;
    }

    for (y = 0; y < (uint)raster->raster_height; ++y) {
        numwritten = fwrite(epr_get_raster_line_addr(raster, y),
                            raster->elem_size,
                            raster->raster_width,
                            out_stream);

        if (numwritten != raster->raster_width) {
            printf("Error: can't write to %s\n", image_file_path);
            return 4;
        }
    }
    fclose(out_stream);

A by far more pythonic solution would be:

    raster.data.tofile(out_stream)