public Shapes parseTextBlocks(InputStream source) {

        // great a parser to get tokens for stream
        Parser parser = new Parser(source);
        Shapes shapes = new Shapes();

        if (graphicState == null) {
            graphicState = new GraphicsState(shapes);
        }

//        long startTime = System.currentTimeMillis();
        try {

            // loop through each token returned form the parser
            Object tok = parser.getStreamObject();
            Stack<Object> stack = new Stack<Object>();
            double yBTstart = 0;
            while (tok != null) {

                // add any names and numbers and every thing else on the
                // stack for future reference
                if (tok instanceof String) {

                    if (tok.equals(PdfOps.BT_TOKEN)) {
                        // start parseText, which parses until ET is reached
                        yBTstart = parseText(parser, shapes, yBTstart);
                        // free up some memory along the way. we don't need
                        // a full stack consume Tf tokens.
                        stack.clear();
                    }
                    // for malformed core docs we need to consume any font
                    // to ensure we can result toUnicode values.
                    else if (tok.equals(PdfOps.Tf_TOKEN)) {
                        consume_Tf(graphicState, stack, resources);
                        stack.clear();
                    }
                    // pick up on xObject content streams.
                    else if (tok.equals(PdfOps.Do_TOKEN)){
                        consume_Do(graphicState, stack, shapes, resources, false);
                        stack.clear();
                    }
                } else {
                    stack.push(tok);
                }
                tok = parser.getStreamObject();
            }
            // clear our temporary stack.
            stack.clear();
        } catch (IOException e) {
            // eat the result as it a normal occurrence
            logger.finer("End of Content Stream");
        }
//        long endTime = System.currentTimeMillis();
//        System.out.println("Extraction Duration " + (endTime - startTime));
        shapes.contract();
        return shapes;
    }