@Override
    public BufferedImage renderFile(String fileName, InputStream input) throws IOException {
        ByteCountingDataInputStream in = new ByteCountingDataInputStream(input);
        PriorityQueue<Integer> chunkIndexes = new PriorityQueue<>(
            new Comparator<Integer>() {

                @Override
                public int compare(Integer o1, Integer o2) {
                    return Integer.compare(o1, o2);
                }
            }
        );
        for (int k = 0; k < SECTOR_INTS; ++k) {
            int offset = in.readInt();
            if (offset != 0) {
                int sectorNumber = offset >> 8;
                chunkIndexes.add(sectorNumber * SECTOR_BYTES);
            }
        }
        assert in.getReadBytes() == SECTOR_BYTES;
        this.skipFully(in, SECTOR_BYTES);
        assert in.getReadBytes() == SECTOR_BYTES * 2;

        short[][] blockId = new short[MAX_CHUNK_SECTIONS][4096];
        byte[][] blockData = new byte[MAX_CHUNK_SECTIONS][4096];
        boolean[] sectionsUsedList = new boolean[MAX_CHUNK_SECTIONS];
        byte[] biomes = new byte[256];
        int[] imageColorArray = new int[512 * 512];
        short[] imageShadeArray = new short[512 * 512];
        int regionZ;
        int regionX;
        int globalX;
        int globalZ;
        long lastUpdate;
        Integer lowestChunkIndex;
        CompoundTag globalTag;
        CompoundTag levelTag;
        byte[] data = new byte[4 * KIBIBYTE];
        while ((lowestChunkIndex = chunkIndexes.poll()) != null) {
            long chunkIndex = lowestChunkIndex;
            long bytesRead = in.getReadBytes();
            if (bytesRead > chunkIndex) {
                throw new IOException("We already read " + bytesRead + " but a chunk exisists at byte index " + chunkIndex);
            } else if (bytesRead < chunkIndex) {
                this.skipFully(in, chunkIndex - bytesRead);
            }
            assert in.getReadBytes() == chunkIndex;
            int chunkLength = in.readInt();
            if (data.length < chunkLength) {
                data = new byte[(chunkLength / KIBIBYTE + 1) * KIBIBYTE];
            }
            in.readFully(data, 0, chunkLength);
            byte version = data[0];
            InputStream chunkStream = new ByteArrayInputStream(data, 1, data.length);
            switch (version) {
                case VERSION_GZIP:
                    chunkStream = new GZIPInputStream(chunkStream);
                    break;
                case VERSION_DEFLATE:
                    chunkStream = new InflaterInputStream(chunkStream);
                    break;
                default:
                    throw new IOException("Invalid format: " + version);
            }
            globalTag = (CompoundTag) new NBTInputStream(
                new DataInputStream(chunkStream)).readTag();
            levelTag = (CompoundTag) globalTag.getValue().get("Level");
            globalX = ((IntTag) levelTag.getValue().get("xPos")).getValue();
            globalZ = ((IntTag) levelTag.getValue().get("zPos")).getValue();
            lastUpdate = ((LongTag) levelTag.getValue().get("LastUpdate")).getValue();
            regionX = calculateChunkPos(globalX);
            regionZ = calculateChunkPos(globalZ);

            loadChunkData(levelTag,
                blockId, blockData, sectionsUsedList, biomes);
            preRenderChunk(
                blockId, blockData, sectionsUsedList, biomes, blockMap, 
                biomeMap, regionX, regionZ, imageColorArray, imageShadeArray);
        }
        demultiplyAlpha(imageColorArray);
        shade(imageShadeArray, imageColorArray);

        BufferedImage localBufferedImage = new BufferedImage(512, 512, BufferedImage.TYPE_INT_ARGB);
        for (int k = 0; k < 512; k++) {
            localBufferedImage.setRGB(0, k, 512, 1, imageColorArray, 512 * k, 512);
        }
        return localBufferedImage;
    }