rasterio "invalid dtype: 'bool'"

Yes, you can write a one bit raster with rasterio*.

You need to:

  1. write to a format that supports a 1bit dataset, such as GeoTIFF;
  2. ensure your numpy array is np.uint8/ubyte so rasterio doesnt raise the TypeError: invalid dtype: 'bool' exception; and
  3. pass the NBITS=1 creation option to tell the underlying GDAL GeoTIFF driver to create a one bit file.

import numpy as np
import rasterio as rio

with rio.open('test_byte.tif') as src:
    data = src.read()
    profile = src.profile

with rio.open('test_bit.tif', 'w', nbits=1, **profile) as dst:
    dst.write(data)
    # If your array is not a byte dtype, you need to cast it as ubyte/uint8
    # dst.write(data.astype(np.uint8))

$ ls -sh test_bit.tif
228K test_bit.tif

$ ls -sh test_byte.tif
1.8M test_byte.tif

$ gdalinfo test_bit.tif
Driver: GTiff/GeoTIFF
Files: test_bit.tif
Size is 1588, 1167
<snip...>
Band 1 Block=1588x41 Type=Byte, ColorInterp=Palette
  Image Structure Metadata:
    NBITS=1

$ gdalinfo test_byte.tif
Driver: GTiff/GeoTIFF
Files: test_byte.tif
Size is 1588, 1167
<snip...>
Band 1 Block=1588x5 Type=Byte, ColorInterp=Gray

* whether or not any software other than GDAL based can read it, I don't know...


If you call rasterio.dtypes.check_dtype(np.bool_) you'll see that it's not a known dtype, because gdal doesn't support a true 1-bit dtype. GDT_Byte is the smallest. The list that rasterio is checking against is:

dtype_fwd = {
0: None,            # GDT_Unknown
1: ubyte,           # GDT_Byte
2: uint16,          # GDT_UInt16
3: int16,           # GDT_Int16
4: uint32,          # GDT_UInt32
5: int32,           # GDT_Int32
6: float32,         # GDT_Float32
7: float64,         # GDT_Float64
8: complex_,        # GDT_CInt16
9: complex_,        # GDT_CInt32
10: complex64,      # GDT_CFloat32
11: complex128}    # GDT_CFloat64

uint8 and int8 are mapped to the ubyte, as seen here:

https://github.com/mapbox/rasterio/blob/master/rasterio/dtypes.py#L29-L45