com.neophob.sematrix.core.generator.Textwriter.java Source code

Java tutorial

Introduction

Here is the source code for com.neophob.sematrix.core.generator.Textwriter.java

Source

/**
 * Copyright (C) 2011-2013 Michael Vogt <michu@neophob.com>
 *
 * This file is part of PixelController.
 *
 * PixelController is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * PixelController is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with PixelController.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.neophob.sematrix.core.generator;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.lang3.StringUtils;

import com.neophob.sematrix.core.glue.FileUtils;
import com.neophob.sematrix.core.glue.MatrixData;
import com.neophob.sematrix.core.resize.Resize.ResizeName;

/**
 * The text is created once and stored to a buffer. The Scroller just change the X offset of the display window.
 *
 * @author mvogt
 */
public class Textwriter extends Generator {

    public static final String FONT_FILENAME = "font.filename";
    public static final String FONT_SIZE = "font.size";

    private static final String INITIAL_STRING = "PIXELCONTROLLER";

    public enum TextwriterMode {
        PINGPONG, LEFT,
        //SINGLE_CHARACTERS
    }

    /** The Constant TEXT_BUFFER_X_SIZE. */
    private static final int TEXT_BUFFER_X_SIZE = 128;

    /** The Constant CHANGE_SCROLLING_DIRECTION_TIMEOUT. */
    private static final int CHANGE_SCROLLING_DIRECTION_TIMEOUT = 12;

    /** The Constant SCROLL_AMMOUNT. */
    private static final int SCROLL_AMMOUNT = 4;

    /** The log. */
    private static final Logger LOG = Logger.getLogger(Textwriter.class.getName());

    /** The font. */
    private Font font;

    /** The xofs. */
    private int xofs;

    /** The max x pos. */
    private int maxXPos;

    /** The text stored as bitmap. */
    private int[] textAsImage;

    /** The text. */
    private String text;

    private AbstractScroller scroller;
    private int scrollerNr = 0;

    /**
     * Instantiates a new textwriter.
     *
     * @param controller the controller
     * @param fontName the font name
     * @param fontSize the font size
     * @param text the text
     */
    public Textwriter(MatrixData matrix, String fontName, int fontSize, FileUtils fu) {
        super(matrix, GeneratorName.TEXTWRITER, ResizeName.PIXEL_RESIZE);
        String filename = fu.getDataDir() + File.separator + fontName;
        InputStream is = null;
        try {
            is = new FileInputStream(filename);
            textAsImage = new int[internalBuffer.length];
            font = Font.createFont(Font.TRUETYPE_FONT, is).deriveFont(Font.BOLD, (float) fontSize);
            LOG.log(Level.INFO, "Loaded font " + fontName + ", size: " + fontSize);
        } catch (Exception e) {
            LOG.log(Level.WARNING, "Failed to load font " + filename + ":", e);
            throw new IllegalArgumentException(
                    "Failed to load font " + filename + ". Check your config.properties file.");
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    LOG.log(Level.WARNING, "Failed to close InputStream.", e);
                }
            }
        }
        createTextImage(INITIAL_STRING);
        scroller = new PingPongScroller();
    }

    /**
     * create image.
     *
     * @param text the text
     */
    public void createTextImage(String text) {
        //only load if needed
        if (StringUtils.equals(text, this.text)) {
            return;
        }

        this.text = text;

        BufferedImage img = new BufferedImage(TEXT_BUFFER_X_SIZE, internalBufferYSize, BufferedImage.TYPE_INT_RGB);

        Graphics2D g2 = img.createGraphics();
        FontRenderContext frc = g2.getFontRenderContext();
        TextLayout layout = new TextLayout(text, font, frc);
        Rectangle2D rect = layout.getBounds();

        int h = (int) (0.5f + rect.getHeight());
        //head and tailing space
        maxXPos = (int) (0.5f + rect.getWidth()) + 2 * internalBufferXSize;
        int ypos = internalBufferYSize - (internalBufferYSize - h) / 2;

        img = new BufferedImage(maxXPos, internalBufferYSize, BufferedImage.TYPE_BYTE_GRAY);
        g2 = img.createGraphics();

        g2.setColor(new Color(128));
        g2.setFont(font);
        g2.setClip(0, 0, maxXPos, internalBufferYSize);

        g2.drawString(text, internalBufferXSize, ypos);
        DataBufferByte dbi = (DataBufferByte) img.getRaster().getDataBuffer();
        byte[] textBuffer = dbi.getData();
        g2.dispose();

        xofs = 0;

        textAsImage = new int[maxXPos * internalBufferYSize];
        for (int i = 0; i < textAsImage.length; i++) {
            if (textBuffer[i] > 10) {
                textAsImage[i] = 127;
            } else {
                textAsImage[i] = 0;
            }
        }

        //clear internalbuffer
        Arrays.fill(this.internalBuffer, 0);
    }

    /* (non-Javadoc)
     * @see com.neophob.sematrix.core.generator.Generator#update()
     */
    @Override
    public void update() {
        scroller.updateText();
    }

    /**
     * Gets the text.
     *
     * @return the text
     */
    public String getText() {
        return text;
    }

    /**
     * 
     * @param nr
     */
    public void setTextscroller(int nr) {
        if (nr == 0) {
            scroller = new PingPongScroller();
            scrollerNr = 0;
        } else {
            scroller = new LeftScroller();
            scrollerNr = 1;
        }
    }

    /**
     * 
     * @return
     */
    public int getTextscroller() {
        return scrollerNr;
    }

    /**
     * this interface is used by all text scrollers
     * 
     * @author mvogt
     *
     */
    interface Textscroller {
        void updateText();
    }

    /**
     * abstract class for text scrollers
     * @author mvogt
     *
     */
    abstract class AbstractScroller implements Textscroller {
        /** The wait. */
        protected int wait = 0;

        protected abstract void scroll();

        @Override
        public void updateText() {
            //is scrolling needed?
            if (wait > 0) {
                wait--;
            } else {
                if (maxXPos < getInternalBufferXSize()) {
                    //no need to scroll
                    xofs = (getInternalBufferXSize() - maxXPos) / 2;
                    wait = 99999;
                } else {
                    scroll();
                }
            }

            copyDataToBuffer();
        }

        private void copyDataToBuffer() {
            int srcOfs = xofs;
            int dstOfs = 0;
            try {
                if (maxXPos < getInternalBufferXSize()) {
                    //text image smaller than internal buffer
                    srcOfs = 0;
                    dstOfs = xofs;
                    for (int y = 0; y < internalBufferYSize; y++) {
                        System.arraycopy(textAsImage, srcOfs, internalBuffer, dstOfs, maxXPos);
                        dstOfs += internalBufferXSize;
                        srcOfs += maxXPos;
                    }
                } else {
                    for (int y = 0; y < internalBufferYSize; y++) {
                        System.arraycopy(textAsImage, srcOfs, internalBuffer, dstOfs, internalBufferXSize);
                        dstOfs += internalBufferXSize;
                        srcOfs += maxXPos;
                    }
                }
            } catch (Exception e) {
                //if the image is resized, this could lead to an arrayoutofboundexception!
            }

        }
    }

    /**
     * scoll left, wait, scoll right, wait, repeat
     * @author mvogt
     *
     */
    class PingPongScroller extends AbstractScroller {
        /** The scroll right. */
        private boolean scrollRight = false;

        public PingPongScroller() {
            xofs = internalBufferXSize;
        }

        protected void scroll() {
            if (scrollRight) {
                xofs += SCROLL_AMMOUNT;
                if (xofs > maxXPos - internalBufferXSize * 2) {
                    scrollRight = false;
                    xofs = maxXPos - internalBufferXSize * 2;
                    wait = CHANGE_SCROLLING_DIRECTION_TIMEOUT;
                }
            } else {
                xofs -= SCROLL_AMMOUNT;
                if (xofs < 1 + internalBufferXSize) {
                    scrollRight = true;
                    xofs = internalBufferXSize;
                    wait = CHANGE_SCROLLING_DIRECTION_TIMEOUT;
                }
            }

        }

    }

    /**
     * Scroll the text to the left, jump to left side if finished
     * 
     * @author mvogt
     *
     */
    class LeftScroller extends AbstractScroller {
        boolean flipNext = false;

        public void scroll() {
            if (flipNext) {
                xofs = 0;
                flipNext = false;
                return;
            }

            xofs += SCROLL_AMMOUNT;
            if (xofs + internalBufferXSize > maxXPos) {
                flipNext = true;
                wait = CHANGE_SCROLLING_DIRECTION_TIMEOUT;
            }
        }
    }

    /**
     * 
     * @author mvogt
     *
     */
    class SingleCharScroller extends AbstractScroller {
        public void scroll() {

        }
    }

}