/** * Decodes a single frame of animation. Does not colour the frame with the palette afterwards. * * @param framenum The number of the frame to decode. * @param lastbytes Frame data of the last frame decoded. * @return Raw decoded frame data. */ private ByteBuffer decodeFrame(int framenum, ByteBuffer lastbytes) { int offset = wsaoffsets[framenum]; int sourcelength = wsaoffsets[framenum + 1] - offset; // Source frame data (is at frame offset + palette size) ByteBuffer sourcebytes = com.mikeduvall.redhorizon.util.ByteBufferFactory.createLittleEndianByteBuffer( sourcelength); try { inputchannel.read(sourcebytes); } catch (IOException e) { throw new RuntimeException(e); } sourcebytes.rewind(); // Intermediate and final frame data int framesize = width() * height(); ByteBuffer intbytes = com.mikeduvall.redhorizon.util.ByteBufferFactory.createLittleEndianByteBuffer(framesize); ByteBuffer framebytes = com.mikeduvall.redhorizon.util.ByteBufferFactory.createLittleEndianByteBuffer(framesize); // First decompress from Format80, then decode as Format40 CodecUtility.decodeFormat80(sourcebytes, intbytes); CodecUtility.decodeFormat40(intbytes, framebytes, lastbytes); return framebytes; }
/** * Constructor, creates a new shp file with the given name and file data. * * @param name The name of this file. * @param bytechannel Data of the file. */ public ShpFileCNC(String name, ReadableByteChannel bytechannel) { super(name); try { // Construct file header ByteBuffer headerbytes = com.mikeduvall.redhorizon.util.ByteBufferFactory.createLittleEndianByteBuffer( ShpFileHeaderCNC.HEADER_SIZE); try { bytechannel.read(headerbytes); } catch (IOException e) { throw new RuntimeException(e); } headerbytes.rewind(); shpfileheader = new ShpFileHeaderCNC(headerbytes); // numImages() + 2 for the 0 offset and EOF pointer ShpImageOffsetCNC[] offsets = new ShpImageOffsetCNC[numImages() + 2]; for (int i = 0; i < offsets.length; i++) { ByteBuffer offsetbytes = com.mikeduvall.redhorizon.util.ByteBufferFactory.createLittleEndianByteBuffer( ShpImageOffsetCNC.OFFSET_SIZE); try { bytechannel.read(offsetbytes); } catch (IOException e) { throw new RuntimeException(e); } offsets[i] = new ShpImageOffsetCNC((ByteBuffer) offsetbytes.rewind()); } // Decompresses the raw SHP data into palette-index data shpimages = new ByteBuffer[numImages()]; // Decompress every frame for (int i = 0; i < numImages(); i++) { ShpImageOffsetCNC imageoffset = offsets[i]; // Format conversion buffers ByteBuffer sourcebytes = com.mikeduvall.redhorizon.util.ByteBufferFactory.createLittleEndianByteBuffer( offsets[i + 1].offset - imageoffset.offset); try { bytechannel.read(sourcebytes); } catch (IOException e) { throw new RuntimeException(e); } sourcebytes.rewind(); ByteBuffer destbytes = com.mikeduvall.redhorizon.util.ByteBufferFactory.createLittleEndianByteBuffer( width() * height()); switch (imageoffset.offsetformat) { // Format80 image case FORMAT80: CodecUtility.decodeFormat80(sourcebytes, destbytes); break; // Format40 image case FORMAT40: int refoffset = imageoffset.refoff; int j; for (j = 0; j < numImages(); j++) { if (refoffset == offsets[j].offset) { break; } } CodecUtility.decodeFormat40(sourcebytes, destbytes, shpimages[j]); break; // Format20 image case FORMAT20: CodecUtility.decodeFormat20(sourcebytes, shpimages[i - 1], destbytes); break; } // Add the decompressed image to the image array shpimages[i] = destbytes; } } finally { try { bytechannel.close(); } catch (IOException e) { throw new RuntimeException(e); } } }