/** {@inheritDoc} */
  @Override
  public void write(GatheringByteChannel outputchannel) {

    int numimages = numImages();

    // Build header
    ByteBuffer header = wsaheader.toByteBuffer();

    // Build palette
    ByteBuffer palette = wsapalette.toByteBuffer();

    // Encode each frame, construct matching offsets
    ByteBuffer[] frames = new ByteBuffer[isLooping() ? numimages + 1 : numimages];
    ByteBuffer lastbytes =
        com.mikeduvall.redhorizon.util.ByteBufferFactory.createLittleEndianByteBuffer(
            width() * height());

    ByteBuffer frameoffsets =
        com.mikeduvall.redhorizon.util.ByteBufferFactory.createLittleEndianByteBuffer(
            (numimages + 2) * 4);
    int offsettotal = WsaFileHeaderCNC.HEADER_SIZE + ((numimages + 2) * 4);

    for (int i = 0; i < frames.length; i++) {
      ByteBuffer framebytes = wsaframes[i];
      ByteBuffer frameint =
          com.mikeduvall.redhorizon.util.ByteBufferFactory.createLittleEndianByteBuffer(
              (int) (framebytes.capacity() * 1.5));
      ByteBuffer frame =
          com.mikeduvall.redhorizon.util.ByteBufferFactory.createLittleEndianByteBuffer(
              (int) (framebytes.capacity() * 1.5));

      // First encode in Format40, then Format80
      CodecUtility.encodeFormat40(framebytes, frameint, lastbytes);
      CodecUtility.encodeFormat80(frameint, frame);

      frames[i] = frame;
      lastbytes = framebytes;

      frameoffsets.putInt(offsettotal);
      offsettotal += frame.limit();
    }

    // Last offset for EOF
    frameoffsets.putInt(offsettotal);
    frameoffsets.rewind();

    // Write file to disk
    try {
      outputchannel.write(header);
      outputchannel.write(frameoffsets);
      outputchannel.write(palette);
      outputchannel.write(frames);
    } catch (IOException e) {
      throw new RuntimeException(e);
    }

    // Generate high-res colour lookup table
    if (!srcnohires) {

      // Figure-out the appropriate file name
      String lookupname =
          filename.contains(".")
              ? filename.substring(0, filename.lastIndexOf('.')) + ".pal"
              : filename + ".pal";

      // Write the index of the closest interpolated palette colour
      // TODO: Perform proper colour interpolation
      ByteBuffer lookup =
          com.mikeduvall.redhorizon.util.ByteBufferFactory.createLittleEndianByteBuffer(256);
      for (int i = 0; i < 256; i++) {
        lookup.put((byte) i);
      }
      lookup.rewind();

      try (FileChannel lookupfile = FileChannel.open(Paths.get(lookupname), WRITE)) {
        for (int i = 0; i < 256; i++) {
          lookupfile.write(lookup);
        }
      }
      // TODO: Should be able to soften the auto-close without needing this
      catch (IOException ex) {
        throw new RuntimeException(ex);
      }
    }
  }