public ByteBuffer unpredict(ByteBuffer imageData)
        throws IOException
    {
        List<byte[]> rows = new ArrayList<byte[]>();
        
        byte[] curLine = null;
        byte[] prevLine = null;
        
        // get the number of bytes per row
        int rowSize = getColumns() * getColors() * getBitsPerComponent();
        rowSize = (int) Math.ceil(rowSize / 8.0);
        
        while(imageData.remaining() >= rowSize + 1) {
            // the first byte determines the algorithm
            int algorithm = (int) (imageData.get() & 0xff);
            
            // read the rest of the line
            curLine = new byte[rowSize];
            imageData.get(curLine);
            
            // use the algorithm, Luke
            switch (algorithm) {
                case 0:
                    // none
                    break;
                case 1:
                    doSubLine(curLine);
                    break;
                case 2:
                    doUpLine(curLine, prevLine);
                    break;
                case 3:
                    doAverageLine(curLine, prevLine);
                    break;
                case 4:
                    doPaethLine(curLine, prevLine);
                    break;
            }
            
            rows.add(curLine);
            prevLine = curLine;
        }
        
        // turn into byte array
        ByteBuffer outBuf = ByteBuffer.allocate(rows.size() * rowSize);
        for (Iterator i = rows.iterator(); i.hasNext();) {
            outBuf.put((byte[]) i.next());
        }
        
        // reset start pointer
        outBuf.flip();
        
        // return
        return outBuf;
        
    }