/** {@inheritDoc} */ @Override public void write(GatheringByteChannel outputchannel) { try { int numimages = numImages(); // Encode each image ByteBuffer[] images = new ByteBuffer[numimages]; for (int i = 0; i < images.length; i++) { ByteBuffer image = com.mikeduvall.redhorizon.util.ByteBufferFactory.createLittleEndianByteBuffer( shpimages[i].capacity()); CodecUtility.encodeFormat80(shpimages[i], image); images[i] = image; } // Construct image offset headers for each image ByteBuffer[] offsets = new ByteBuffer[numimages + 2]; int offsettotal = ShpFileHeaderCNC.HEADER_SIZE + (ShpImageOffsetCNC.OFFSET_SIZE * offsets.length); for (int i = 0; i < numImages(); i++) { offsets[i] = new ShpImageOffsetCNC(offsettotal, FORMAT80, 0, (byte) 0).toByteBuffer(); offsettotal += images[i].limit(); } // The 2 special image offsets at the end of the offset array offsets[numimages] = new ShpImageOffsetCNC(offsettotal, (byte) 0, 0, (byte) 0).toByteBuffer(); offsets[numimages + 1] = new ShpImageOffsetCNC(0, (byte) 0, 0, (byte) 0).toByteBuffer(); // Build header ByteBuffer header = shpfileheader.toByteBuffer(); // Write file try { outputchannel.write(header); outputchannel.write(offsets); outputchannel.write(images); } catch (IOException e) { throw new RuntimeException(e); } } finally { try { outputchannel.close(); } catch (IOException e) { throw new RuntimeException(e); } } }
/** {@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); } } }