* @param out
     * @param width
     */
    public static void Group4Decode(InputStream in, OutputStream out, int width, boolean blackIs1) {
        BitStream inb = new BitStream(in);
        BitStream outb = new BitStream(out);
        // assign default colour mapping
        black = 0;
        white = 1;

        // apply blackIs1, which inverts the colour pallet
        if (blackIs1) {
            black = 1;
            white = 0;
        }

        Code code = new Code();

        try {
            G4State graphicState = new G4State(width);
            while (!inb.atEndOfFile()) {
                int mode = readmode(inb, code);
                switch (mode) {
                    case 0:                     // P
                        decodePass(graphicState);
                        continue;
                    case 1:                     // H
                        decodeHorizontal(inb, outb, graphicState, code);
                        decodeHorizontal(inb, outb, graphicState, code);
                        detectB1(graphicState);
                        break;
                    case 2:                     // V0
                        detectB1(graphicState);
                        addRun(graphicState.b1 - graphicState.a0, graphicState, outb);
                        graphicState.white = !graphicState.white;
                        graphicState.b1 += graphicState.ref[graphicState.refIndex++];
                        break;
                    case 3:                     // VR1
                        detectB1(graphicState);
                        addRun(graphicState.b1 - graphicState.a0 + 1, graphicState, outb);
                        graphicState.white = !graphicState.white;
                        graphicState.b1 += graphicState.ref[graphicState.refIndex++];
                        break;
                    case 4:                     // VR2
                        detectB1(graphicState);
                        addRun(graphicState.b1 - graphicState.a0 + 2, graphicState, outb);
                        graphicState.white = !graphicState.white;
                        graphicState.b1 += graphicState.ref[graphicState.refIndex++];
                        break;
                    case 5:                     // VR3
                        detectB1(graphicState);
                        addRun(graphicState.b1 - graphicState.a0 + 3, graphicState, outb);
                        graphicState.white = !graphicState.white;
                        graphicState.b1 += graphicState.ref[graphicState.refIndex++];
                        break;
                    case 6:                     // VL1
                        detectB1(graphicState);
                        addRun(graphicState.b1 - graphicState.a0 - 1, graphicState, outb);
                        graphicState.white = !graphicState.white;
                        if (graphicState.refIndex > 0)
                            graphicState.b1 -= graphicState.ref[--graphicState.refIndex];
                        break;
                    case 7:                     // VL2
                        detectB1(graphicState);
                        addRun(graphicState.b1 - graphicState.a0 - 2, graphicState, outb);
                        graphicState.white = !graphicState.white;
                        if (graphicState.refIndex > 0)
                            graphicState.b1 -= graphicState.ref[--graphicState.refIndex];
                        break;
                    case 8:                     // VL3
                        detectB1(graphicState);
                        addRun(graphicState.b1 - graphicState.a0 - 3, graphicState, outb);
                        graphicState.white = !graphicState.white;
                        if (graphicState.refIndex > 0)
                            graphicState.b1 -= graphicState.ref[--graphicState.refIndex];
                        break;
                    case 11:                    // EOL
                        resetRuns(outb, graphicState);
                        break;
                    default:
                        //System.err.println("UNK! "+mode);
                }
                if (graphicState.a0 >= graphicState.width) {
                    resetRuns(outb, graphicState);
                }
            }
            // do a little memory clean up.
            inb.close();
            outb.close();
            in.close();
            // out.flush(); // need this for further proccessing
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }