content: package btools.mapcreator;
  
  import java.io.DataInputStream;
  import java.io.DataOutputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.OutputStream;
  
  import btools.util.MixCoderDataInputStream;
  import btools.util.MixCoderDataOutputStream;
  
  //
  // Encode/decode a raster
  //
  
  public class ElevationRasterCoder {
    public void encodeRaster(ElevationRaster raster, OutputStream os) throws IOException {
      DataOutputStream dos = new DataOutputStream(os);
  
      long t0 = System.currentTimeMillis();
  
      dos.writeInt(raster.ncols);
      dos.writeInt(raster.nrows);
      dos.writeBoolean(raster.halfcol);
      dos.writeDouble(raster.xllcorner);
      dos.writeDouble(raster.yllcorner);
      dos.writeDouble(raster.cellsize);
      dos.writeShort(raster.noDataValue);
  
      _encodeRaster(raster, os);
      long t1 = System.currentTimeMillis();
  
      System.out.println("finished encoding in " + (t1 - t0) + " ms");
    }
  
    public ElevationRaster decodeRaster(InputStream is) throws IOException {
      DataInputStream dis = new DataInputStream(is);
  
      long t0 = System.currentTimeMillis();
  
      ElevationRaster raster = new ElevationRaster();
      raster.ncols = dis.readInt();
      raster.nrows = dis.readInt();
      raster.halfcol = dis.readBoolean();
      raster.xllcorner = dis.readDouble();
      raster.yllcorner = dis.readDouble();
      raster.cellsize = dis.readDouble();
      raster.noDataValue = dis.readShort();
      raster.eval_array = new short[raster.ncols * raster.nrows];
  
      _decodeRaster(raster, is);
  
      raster.usingWeights = false; // raster.ncols > 6001;
  
      long t1 = System.currentTimeMillis();
      System.out.println("finished decoding in " + (t1 - t0) + " ms ncols=" + raster.ncols + " nrows=" + raster.nrows);
      return raster;
    }
  
  
    private void _encodeRaster(ElevationRaster raster, OutputStream os) throws IOException {
      MixCoderDataOutputStream mco = new MixCoderDataOutputStream(os);
      int nrows = raster.nrows;
      int ncols = raster.ncols;
      short[] pixels = raster.eval_array;
      int colstep = raster.halfcol ? 2 : 1;
  
      for (int row = 0; row < nrows; row++) {
        short lastval = Short.MIN_VALUE; // nodata
        for (int col = 0; col < ncols; col += colstep) {
          short val = pixels[row * ncols + col];
          if (val == -32766) {
            val = lastval; // replace remaining (border) skips
          } else {
            lastval = val;
          }
  
          // remap nodata
          int code = val == Short.MIN_VALUE ? -1 : (val < 0 ? val - 1 : val);
          mco.writeMixed(code);
        }
      }
      mco.flush();
    }
  
    private void _decodeRaster(ElevationRaster raster, InputStream is) throws IOException {
      MixCoderDataInputStream mci = new MixCoderDataInputStream(is);
      int nrows = raster.nrows;
      int ncols = raster.ncols;
      short[] pixels = raster.eval_array;
      int colstep = raster.halfcol ? 2 : 1;
  
      for (int row = 0; row < nrows; row++) {
        for (int col = 0; col < ncols; col += colstep) {
          int code = mci.readMixed();
  
          // remap nodata
          int v30 = code == -1 ? Short.MIN_VALUE : (code < 0 ? code + 1 : code);
          if (raster.usingWeights && v30 > -32766) {
            v30 *= 2;
          }
          pixels[row * ncols + col] = (short) (v30);
        }
        if (raster.halfcol) {
          for (int col = 1; col < ncols - 1; col += colstep) {
            int l = (int) pixels[row * ncols + col - 1];
            int r = (int) pixels[row * ncols + col + 1];
            short v30 = Short.MIN_VALUE; // nodata
            if (l > -32766 && r > -32766) {
              v30 = (short) ((l + r) / 2);
            }
            pixels[row * ncols + col] = v30;
          }
        }
      }
    }
  }
  