May 30, 2021 plug-ins OLED

THETA Z1 OLED Drawing Library

THETA Z1 OLED Drawing Library

Introduction

Original article appeared in Japanese here.

This is Ricoh’s @ KA-2.

RICOH manufactures a camera called RICOH THETA that can shoot in 360° - in all directions.

RICOH THETA V and RICOH THETA Z1 use Android as the OS. You can customize them as if you were making an Android app, which are called “plug-ins” (see the end of this article for details).

The RICOH THETA Z1, which went on sale in Japan on May 24, 2019, is equipped with an OLED display.

z1

The basic method of manipulating the OLED through a THETA plug-in is introduced in this article (in Japanese). Along with this article, you can read the API for manipulating the OLED (please see the section “Control the OLEDs” in “Broadcast Intent”) THETA Plug-in API documentation. If you use the API as-is, be aware of the following issues:

  • It is difficult to draw basic figures such as points, lines, squares, and circles. (It’s just a matter of packing data in the Bitmap class…)
  • When a color image is input, the brightness threshold for binarization cannot be specified.
  • The image display is only for the area that can be controlled by the plug-in (bottom 128 x 24 dots). Partial display is not possible.
  • Images and text cannot be mixed.
  • When displaying text, even if lowercase letters are specified, they are converted to uppercase letters.
  • Since it is not a monospaced font, when a changing value is displayed, the display may sway from side to side, or the vertical lines may not be aligned, resulting in poor appearance.

As a quick start, I pulled together something like an “OLED drawing library.”

drawing library

I think these are similar to electronic work clusters that have been used as graphical black and white displays.

“Drawing turn (create display data) → display the completed data”

Since this is the flow, you can also make more elaborate screens by matching the library with the drawing turn.

The following video is an example of what you can create with the library: https://www.youtube.com/watch?v=7eYaUrlwmGk

Library Description

The title of this article is “THETA Z1 OLED Drawing Library.” This might make you think that the source code is included in the “plug-in library” used by the THETA Plugin SDK. However, it is not included as of the end of May 2019.

Please take some time to look through the library and see if there is anything useful missing.

Prepared Methods

Classification Name of Method Summary
Constructor Oled (Context context) Pass the context of MainActivity from the argument.
Official OLED API wrapper displaySet(String mode)
brightness (int value)
hide ()
blink (int msec)
This is a wrapping of the OLED-related Broadcast Intent published here so that it can be easily called.
Basic Processing draw ()
clear() *two types of different arguments
invert (boolean invFlag)
draw is a process to display drawing processed data with the official OLED API (Broadcast Intent).
clear clears the drawing data.
invert inverts the drawing data.
Image Drawing setBitmap() *four types of different arguments Draw by specifying the brightness threshold and the image file name in the assets folder, or the Bitmap object. There are two types, one that draws on the entire OLED and one that allows detailed display area specification.
All image file formats that can be handled are those that can be decoded by BitmapFactory.decodeStream (). It can handle bmp, jpg, png, etc.
Draw a Dot pixel() *two types of different arguments Draws a point at the specified position.
There is also an option for color (white / black) and an option to invert the color when the specified color and the background are the same.
Draw a Line line() *two types of different arguments
lineH() *two types of different arguments
lineV() *two types of different arguments
Draw a line between the two specified points.
There is also an option for color (white / black) and an option to invert the color when the specified color and the background are the same.
The name ending with “H” is horizontal and “V” is a process specialized for vertical.
Draw a Square rect() *two types of different arguments
rectFill() *two types of different arguments
Draw a square by specifying the upper left coordinates, width, and height.
If the name has “Fill” in it, fill in the contents.
There is also an option for color (white / black) and an option to invert the color when the specified color and the background are the same.
Draw a Circle circle() *two types of different arguments
circleFill() *two types of different arguments
Draw a circle by specifying the center coordinates and radius.
If the name has “Fill” in it, fill in the contents.
There is also an option for color (white / black) and an option to invert the color when the specified color and the background are the same.
However, for circleFill (), the option to invert with the background color is disabled for the reason described in the comment in the source code.
Draw a Character (string) setChar() *two types of different arguments
setString() *two types of different arguments
Draws a character from the specified coordinates. You can draw ASCII code from 0x20 to 0x7E and some extra symbols. One character is 5x7 dot (display area is a 6x8 dot). Up to 21 characters x 3 lines can be displayed.
There is also an option for color (white / black) and an option to invert the color when the specified color and the background are the same.
It does not scroll.

For reference, here is a display example covering ASCII codes from 0x20 to 0x7E.

ascii 1

ascii 2

If you have a request or a comment such as “I don’t like this font,” “I want a font with larger characters,” “I want a Japanese font,” etc., please add it in, referring to the source code posted in this article. Please try!

And when this library is released on GitHub, it would be great if you could do a pull request!

Oled.java Full Source Code

The source code of the library part is as follows.

/**

  • Copyright 2018 Ricoh Company, Ltd.

*

  • Licensed under the Apache License, Version 2.0 (the “License”);

  • you may not use this file except in compliance with the License.

  • You may obtain a copy of the License at

*

  • http://www.apache.org/licenses/LICENSE-2.0

*

  • Unless required by applicable law or agreed to in writing, software

  • distributed under the License is distributed on an “AS IS” BASIS,

  • WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

  • See the License for the specific language governing permissions and

  • limitations under the License.

*/

package com.theta360.pluginapplication.oled;

import android.content.Context;

import android.content.Intent;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.content.res.*;

import android.util.Log;

import java.io.InputStream;

import java.io.IOException;

public class Oled {

private final Context context;

private static final String ACTION_OLED_DISPLAY_SET = "com.theta360.plugin.ACTION_OLED_DISPLAY_SET";

private static final String ACTION_OLED_BRIGHTNESS_SET = "com.theta360.plugin.ACTION_LED_BRIGHTNESS_SET";

private static final String ACTION_OLED_IMAGE_SHOW = "com.theta360.plugin.ACTION_OLED_IMAGE_SHOW";

private static final String ACTION_OLED_IMAGE_BLINK = "com.theta360.plugin.ACTION_OLED_IMAGE_BLINK";

private static final String ACTION_OLED_HIDE = "com.theta360.plugin.ACTION_OLED_HIDE";

public static final String DISPLAY_SET_PLUGIN = "plug-in";

public static final String DISPLAY_SET_BASIC = "basic";

public static final int OLED_WIDTH = 128;

public static final int OLED_HEIGHT = 24;

public int black = 0xFF000000 ;

public int white = 0xFFFFFFFF ;

private Bitmap screen = null;

public int imgWidth = 0;

public int imgHeight = 0;

public Oled (Context context) {

    this.context = context;

    screen = Bitmap.createBitmap(OLED_WIDTH, OLED_HEIGHT, Bitmap.Config.ARGB_8888 );

}

public void displaySet(String mode) {

    Intent oledIntentSet = new Intent(ACTION_OLED_DISPLAY_SET);

    if ( mode.equals(DISPLAY_SET_PLUGIN) ) {

        oledIntentSet.putExtra("display", DISPLAY_SET_PLUGIN);

    } else {

        oledIntentSet.putExtra("display", DISPLAY_SET_BASIC);

    }

    this.context.sendBroadcast(oledIntentSet);

}

public void brightness (int value) {

    if (value<0) {

        value = 0;

    }

    if (value>100) {

        value=100;

    }

    Intent oledBrightnessIntent = new Intent(ACTION_OLED_BRIGHTNESS_SET);

    oledBrightnessIntent.putExtra("target", "OLED");

    oledBrightnessIntent.putExtra("brightness",  value);

    context.sendBroadcast(oledBrightnessIntent);

}

public void hide () {

    Intent imageIntent = new Intent(ACTION_OLED_HIDE);

    context.sendBroadcast(imageIntent);

}

public void blink (int msec) {

    if (msec<250) {

        msec=250;

    }

    if (msec>2000) {

        msec=2000;

    }

    Intent imageIntent = new Intent(ACTION_OLED_IMAGE_BLINK);

    imageIntent.putExtra("bitmap", screen);

    imageIntent.putExtra("period", msec);

    context.sendBroadcast(imageIntent);

}

public void draw () {

    Intent imageIntent = new Intent(ACTION_OLED_IMAGE_SHOW);

    imageIntent.putExtra("bitmap", screen);

    context.sendBroadcast(imageIntent);

}

public void clear () {

    clear(black);

}

public void clear (int color) {

    for (int width=0; width<OLED_WIDTH; width++) {

        for (int height = 0; height < OLED_HEIGHT; height++) {

            screen.setPixel(width, height, color);

        }

    }

}

public void invert (boolean invFlag) {

    if (invFlag) {

        Intent imageIntent = new Intent(ACTION_OLED_IMAGE_SHOW);

        Bitmap invertScreen = Bitmap.createBitmap(OLED_WIDTH, OLED_HEIGHT, Bitmap.Config.ARGB_8888 );

        for (int width=0; width<OLED_WIDTH; width++) {

            for (int height = 0; height < OLED_HEIGHT; height++) {

                if ( screen.getPixel(width, height) == white ) {

                    invertScreen.setPixel(width, height, black);

                } else {

                    invertScreen.setPixel(width, height, white);

                }

            }

        }

        imageIntent.putExtra("bitmap", invertScreen);

        context.sendBroadcast(imageIntent);

    } else {

        draw();

    }

}

public void setBitmap(int threshold, String assetsFileName) {

    setBitmap(0, 0, OLED_WIDTH, OLED_HEIGHT, 0, 0, threshold, assetsFileName) ;

}

public void setBitmap(int threshold, Bitmap inBitmap) {

    setBitmap(0, 0, OLED_WIDTH, OLED_HEIGHT, 0, 0, threshold, inBitmap) ;

}

public void setBitmap(int scnX, int scnY, int scnWidth, int scnHeight, int imgX, int imgY, int threshold, String assetsFileName) {

    AssetManager assetManager = context.getAssets();

    InputStream inputStream;

    Bitmap fileBitmap = null;

    try {

        inputStream = assetManager.open(assetsFileName);

        fileBitmap = BitmapFactory.decodeStream(inputStream);

        setBitmap(scnX, scnY, scnWidth, scnHeight, imgX, imgY, threshold, fileBitmap) ;

    } catch (IOException e) {

        e.printStackTrace();

    }

}

public void setBitmap(int scnX, int scnY, int scnWidth, int scnHeight, int imgX, int imgY, int threshold, Bitmap inBitmap) {

    int xStart;

    int xEnd;

    int yStart;

    int yEnd;

    int scnOffsetX=scnX;

    int scnOffsetY=scnY;

    if (    ( (0<=scnX) && (scnX<OLED_WIDTH) ) && ( (0<scnWidth) || ((scnX+scnWidth)<=OLED_WIDTH) ) &&

            ( (0<=scnY) && (scnY<OLED_HEIGHT) ) && ( (0<scnHeight) || ((scnY+scnHeight)<=OLED_HEIGHT) )  )

    {

        xStart = scnX;

        xEnd = scnX+scnWidth;

        yStart = scnY;

        yEnd = scnY+scnHeight;

    } else {

        return;

    }

    imgWidth = inBitmap.getWidth();

    imgHeight = inBitmap.getHeight();

    int imgOffsetX = 0;

    int imgOffsetY = 0;

    if (    ( (0<=imgX) && (imgX<imgWidth) ) && ((imgX+scnWidth)<=imgWidth) &&

            ( (0<=imgY) && (imgY<imgHeight) ) && ((imgY+scnHeight)<=imgHeight) )

    {

        imgOffsetX = imgX;

        imgOffsetY = imgY;

    } else {

        return ;

    }

    for (int width=xStart; width<xEnd; width++) {

        for (int height=yStart; height<yEnd; height++) {

            int iColor = inBitmap.getPixel(imgOffsetX+(width-scnOffsetX), +imgOffsetY+(height-scnOffsetY) );

            // int color = (A & 0xff) &lt;< 24 | (B & 0xff) &lt;< 16 | (G & 0xff) &lt;< 8 | (R & 0xff);

            //Y =  0.299 x R + 0.587  x G + 0.114  x B

            double dY = 0.299*(iColor&0x000000FF) + 0.587*((iColor&0x0000FF00)>>8) + 0.114*((iColor&0x00FF0000)>>16);

            int Y = (int)(dY+0.5);

            if (Y&lt;0) { Y = 0 ;}

            if (Y>255) { Y = 255 ;}

            if ( Y &lt; threshold ) {

                screen.setPixel(width, height, black);

            } else {

                screen.setPixel(width, height, white);

            }

        }

    }

}

public void pixel(int x, int y) {

    pixel(x, y, white, false);

}

public void pixel(int x, int y, int color, boolean xor) {

    if (    ( (0&lt;=x) && (x&lt;OLED_WIDTH) )  &&

            ( (0&lt;=y) && (y&lt;OLED_HEIGHT) )  )

    {

        if (xor) {

            if ( color == white ) {

                if ( screen.getPixel(x, y) == white ) {

                    screen.setPixel(x, y, black);

                } else {

                    screen.setPixel(x, y, white);

                }

            }

        } else {

            screen.setPixel(x, y, color);

        }

    }

}

public void line(int x0, int y0, int x1, int y1) {

    line(x0, y0, x1, y1, white, false);

}

public void line(int x0, int y0, int x1, int y1, int color, boolean xor) {

    int tmp ;

    int dx;

    int dy;

    boolean steep = (Math.abs(y1 - y0) > Math.abs(x1 - x0) );

    if ( steep ) {

        //swap x0,y0

        tmp = x0;

        x0 = y0;

        y0 = tmp;

        //swap x1,y1

        tmp = x1;

        x1 = y1;

        y1 = tmp;

    }

    if (x0>x1) {

        //swap x0,x1

        tmp = x0;

        x0 = x1;

        x1 = tmp;

        //swap y0,y1

        tmp = y0;

        y0 = y1;

        y1 = tmp;

    }

    dx = x1 - x0;

    dy = Math.abs(y1 - y0);

    int err = dx/2;

    int ystep ;

    if (y0 &lt; y1) {

        ystep = 1;

    } else {

        ystep = -1;

    }

    int y = y0;

    for (int x=x0; x&lt;x1; x++) {

        if (steep) {

            pixel(y, x, color, xor);

        } else {

            pixel(x, y, color, xor);

        }

        err -= dy;

        if (err &lt; 0) {

            y += ystep;

            err += dx;

        }

    }

}

public void lineH(int x, int y, int width) {

    line(x, y,(x+width), y);

}

public void lineH(int x, int y, int width, int color, boolean xor) {

    line(x, y,(x+width), y, color, xor);

}

public void lineV(int x, int y, int height) {

    line(x, y, x,(y+height));

}

public void lineV(int x, int y, int height, int color, boolean xor) {

    line(x, y, x,(y+height), color, xor);

}

public void rect(int x, int y, int width, int height) {

    rect(x, y, width, height, white, false);

}

public void rect(int x, int y, int width, int height, int color, boolean xor) {

    lineH(x,y, width, color, xor);

    lineH(x,y+height-1, width, color, xor);

    int tempHeight = height-2;

    if ( tempHeight >= 1 ) {

        lineV(x,y+1, tempHeight, color, xor);

        lineV(x+width-1, y+1, tempHeight, color, xor);

    }

}

public void rectFill(int x, int y, int width, int height) {

    rectFill(x, y, width, height, white, false);

}

public void rectFill(int x, int y, int width, int height, int color, boolean xor) {

    for (int i=y; i&lt;y+height; i++) {

        lineH(x, i, width, color, xor);

    }

}

public void circle(int x0, int y0, int radius) {

    circle(x0, y0, radius, white, false);

}

public void circle(int x0, int y0, int radius, int color, boolean xor) {

    int f = 1 - radius;

    int ddF_x = 1;

    int ddF_y = -2 * radius;

    int x = 0;

    int y = radius;

    pixel(x0, y0+radius, color, xor);

    pixel(x0, y0-radius, color, xor);

    pixel(x0+radius, y0, color, xor);

    pixel(x0-radius, y0, color, xor);

    while ( x &lt; y ) {

        if (f >= 0) {

            y--;

            ddF_y += 2;

            f += ddF_y;

        }

        x++;

        ddF_x += 2;

        f += ddF_x;

        pixel(x0 + x, y0 + y, color, xor);

        pixel(x0 - x, y0 + y, color, xor);

        pixel(x0 + x, y0 - y, color, xor);

        pixel(x0 - x, y0 - y, color, xor);

        pixel(x0 + y, y0 + x, color, xor);

        pixel(x0 - y, y0 + x, color, xor);

        pixel(x0 + y, y0 - x, color, xor);

        pixel(x0 - y, y0 - x, color, xor);

    }

}

public void circleFill(int x0, int y0, int radius) {

    circleFill(x0, y0, radius, white, false);

}

public void circleFill(int x0, int y0, int radius, int color, boolean xor) {

    int f = 1 - radius;

    int ddF_x = 1;

    int ddF_y = -2 * radius;

    int x = 0;

    int y = radius;

    //Problem: duplicated drawing part is multiple inverted

    //I haven't solved it in a simple way

    //Temporarily turning off xor mode

    if (xor) { return; }

    for (int i=y0-radius; i&lt;=y0+radius; i++) {

        pixel(x0, i, color, xor);

    }

    while (x&lt;y) {

        if (f >= 0) {

            y--;

            ddF_y += 2;

            f += ddF_y;

        }

        x++;

        ddF_x += 2;

        f += ddF_x;

        for (int i=y0-y; i&lt;=y0+y; i++) {

            pixel(x0+x, i, color, xor);

            pixel(x0-x, i, color, xor);

        }

        for (int i=y0-x; i&lt;=y0+x; i++) {

            pixel(x0+y, i, color, xor);

            pixel(x0-y, i, color, xor);

        }

    }

}

public static final int FONT_WIDTH = 6;

public static final int FONT_HEIGHT = 8;

private static final short ASCII[][] = {

        {0x00, 0x00, 0x00, 0x00, 0x00},

        {0x3E, 0x5B, 0x4F, 0x5B, 0x3E},

        {0x3E, 0x6B, 0x4F, 0x6B, 0x3E},

        {0x1C, 0x3E, 0x7C, 0x3E, 0x1C},

        {0x18, 0x3C, 0x7E, 0x3C, 0x18},

        {0x1C, 0x57, 0x7D, 0x57, 0x1C},

        {0x1C, 0x5E, 0x7F, 0x5E, 0x1C},

        {0x00, 0x18, 0x3C, 0x18, 0x00},

        {0xFF, 0xE7, 0xC3, 0xE7, 0xFF},

        {0x00, 0x18, 0x24, 0x18, 0x00},

        {0xFF, 0xE7, 0xDB, 0xE7, 0xFF},

        {0x30, 0x48, 0x3A, 0x06, 0x0E},

        {0x26, 0x29, 0x79, 0x29, 0x26},

        {0x40, 0x7F, 0x05, 0x05, 0x07},

        {0x40, 0x7F, 0x05, 0x25, 0x3F},

        {0x5A, 0x3C, 0xE7, 0x3C, 0x5A},

        {0x7F, 0x3E, 0x1C, 0x1C, 0x08},

        {0x08, 0x1C, 0x1C, 0x3E, 0x7F},

        {0x14, 0x22, 0x7F, 0x22, 0x14},

        {0x5F, 0x5F, 0x00, 0x5F, 0x5F},

        {0x06, 0x09, 0x7F, 0x01, 0x7F},

        {0x00, 0x66, 0x89, 0x95, 0x6A},

        {0x60, 0x60, 0x60, 0x60, 0x60},

        {0x94, 0xA2, 0xFF, 0xA2, 0x94},

        {0x08, 0x04, 0x7E, 0x04, 0x08},

        {0x10, 0x20, 0x7E, 0x20, 0x10},

        {0x08, 0x08, 0x2A, 0x1C, 0x08},

        {0x08, 0x1C, 0x2A, 0x08, 0x08},

        {0x1E, 0x10, 0x10, 0x10, 0x10},

        {0x0C, 0x1E, 0x0C, 0x1E, 0x0C},

        {0x30, 0x38, 0x3E, 0x38, 0x30},

        {0x06, 0x0E, 0x3E, 0x0E, 0x06},

        {0x00, 0x00, 0x00, 0x00, 0x00},

        {0x00, 0x00, 0x5F, 0x00, 0x00},

        {0x00, 0x07, 0x00, 0x07, 0x00},

        {0x14, 0x7F, 0x14, 0x7F, 0x14},

        {0x24, 0x2A, 0x7F, 0x2A, 0x12},

        {0x23, 0x13, 0x08, 0x64, 0x62},

        {0x36, 0x49, 0x56, 0x20, 0x50},

        {0x00, 0x08, 0x07, 0x03, 0x00},

        {0x00, 0x1C, 0x22, 0x41, 0x00},

        {0x00, 0x41, 0x22, 0x1C, 0x00},

        {0x2A, 0x1C, 0x7F, 0x1C, 0x2A},

        {0x08, 0x08, 0x3E, 0x08, 0x08},

        {0x00, 0x80, 0x70, 0x30, 0x00},

        {0x08, 0x08, 0x08, 0x08, 0x08},

        {0x00, 0x00, 0x60, 0x60, 0x00},

        {0x20, 0x10, 0x08, 0x04, 0x02},

        {0x3E, 0x51, 0x49, 0x45, 0x3E},

        {0x00, 0x42, 0x7F, 0x40, 0x00},

        {0x72, 0x49, 0x49, 0x49, 0x46},

        {0x21, 0x41, 0x49, 0x4D, 0x33},

        {0x18, 0x14, 0x12, 0x7F, 0x10},

        {0x27, 0x45, 0x45, 0x45, 0x39},

        {0x3C, 0x4A, 0x49, 0x49, 0x31},

        {0x41, 0x21, 0x11, 0x09, 0x07},

        {0x36, 0x49, 0x49, 0x49, 0x36},

        {0x46, 0x49, 0x49, 0x29, 0x1E},

        {0x00, 0x00, 0x14, 0x00, 0x00},

        {0x00, 0x40, 0x34, 0x00, 0x00},

        {0x00, 0x08, 0x14, 0x22, 0x41},

        {0x14, 0x14, 0x14, 0x14, 0x14},

        {0x00, 0x41, 0x22, 0x14, 0x08},

        {0x02, 0x01, 0x59, 0x09, 0x06},

        {0x3E, 0x41, 0x5D, 0x59, 0x4E},

        {0x7C, 0x12, 0x11, 0x12, 0x7C},

        {0x7F, 0x49, 0x49, 0x49, 0x36},

        {0x3E, 0x41, 0x41, 0x41, 0x22},

        {0x7F, 0x41, 0x41, 0x41, 0x3E},

        {0x7F, 0x49, 0x49, 0x49, 0x41},

        {0x7F, 0x09, 0x09, 0x09, 0x01},

        {0x3E, 0x41, 0x41, 0x51, 0x73},

        {0x7F, 0x08, 0x08, 0x08, 0x7F},

        {0x00, 0x41, 0x7F, 0x41, 0x00},

        {0x20, 0x40, 0x41, 0x3F, 0x01},

        {0x7F, 0x08, 0x14, 0x22, 0x41},

        {0x7F, 0x40, 0x40, 0x40, 0x40},

        {0x7F, 0x02, 0x1C, 0x02, 0x7F},

        {0x7F, 0x04, 0x08, 0x10, 0x7F},

        {0x3E, 0x41, 0x41, 0x41, 0x3E},

        {0x7F, 0x09, 0x09, 0x09, 0x06},

        {0x3E, 0x41, 0x51, 0x21, 0x5E},

        {0x7F, 0x09, 0x19, 0x29, 0x46},

        {0x26, 0x49, 0x49, 0x49, 0x32},

        {0x03, 0x01, 0x7F, 0x01, 0x03},

        {0x3F, 0x40, 0x40, 0x40, 0x3F},

        {0x1F, 0x20, 0x40, 0x20, 0x1F},

        {0x3F, 0x40, 0x38, 0x40, 0x3F},

        {0x63, 0x14, 0x08, 0x14, 0x63},

        {0x03, 0x04, 0x78, 0x04, 0x03},

        {0x61, 0x59, 0x49, 0x4D, 0x43},

        {0x00, 0x7F, 0x41, 0x41, 0x41},

        {0x02, 0x04, 0x08, 0x10, 0x20},

        {0x00, 0x41, 0x41, 0x41, 0x7F},

        {0x04, 0x02, 0x01, 0x02, 0x04},

        {0x40, 0x40, 0x40, 0x40, 0x40},

        {0x00, 0x03, 0x07, 0x08, 0x00},

        {0x20, 0x54, 0x54, 0x78, 0x40},

        {0x7F, 0x28, 0x44, 0x44, 0x38},

        {0x38, 0x44, 0x44, 0x44, 0x28},

        {0x38, 0x44, 0x44, 0x28, 0x7F},

        {0x38, 0x54, 0x54, 0x54, 0x18},

        {0x00, 0x08, 0x7E, 0x09, 0x02},

        {0x18, 0xA4, 0xA4, 0x9C, 0x78},

        {0x7F, 0x08, 0x04, 0x04, 0x78},

        {0x00, 0x44, 0x7D, 0x40, 0x00},

        {0x20, 0x40, 0x40, 0x3D, 0x00},

        {0x7F, 0x10, 0x28, 0x44, 0x00},

        {0x00, 0x41, 0x7F, 0x40, 0x00},

        {0x7C, 0x04, 0x78, 0x04, 0x78},

        {0x7C, 0x08, 0x04, 0x04, 0x78},

        {0x38, 0x44, 0x44, 0x44, 0x38},

        {0xFC, 0x18, 0x24, 0x24, 0x18},

        {0x18, 0x24, 0x24, 0x18, 0xFC},

        {0x7C, 0x08, 0x04, 0x04, 0x08},

        {0x48, 0x54, 0x54, 0x54, 0x24},

        {0x04, 0x04, 0x3F, 0x44, 0x24},

        {0x3C, 0x40, 0x40, 0x20, 0x7C},

        {0x1C, 0x20, 0x40, 0x20, 0x1C},

        {0x3C, 0x40, 0x30, 0x40, 0x3C},

        {0x44, 0x28, 0x10, 0x28, 0x44},

        {0x4C, 0x90, 0x90, 0x90, 0x7C},

        {0x44, 0x64, 0x54, 0x4C, 0x44},

        {0x00, 0x08, 0x36, 0x41, 0x00},

        {0x00, 0x00, 0x77, 0x00, 0x00},

        {0x00, 0x41, 0x36, 0x08, 0x00},

        {0x02, 0x01, 0x02, 0x04, 0x02},

        {0x3C, 0x26, 0x23, 0x26, 0x3C},

        {0x1E, 0xA1, 0xA1, 0x61, 0x12},

        {0x3A, 0x40, 0x40, 0x20, 0x7A},

        {0x38, 0x54, 0x54, 0x55, 0x59},

        {0x21, 0x55, 0x55, 0x79, 0x41},

        {0x21, 0x54, 0x54, 0x78, 0x41},

        {0x21, 0x55, 0x54, 0x78, 0x40},

        {0x20, 0x54, 0x55, 0x79, 0x40},

        {0x0C, 0x1E, 0x52, 0x72, 0x12},

        {0x39, 0x55, 0x55, 0x55, 0x59},

        {0x39, 0x54, 0x54, 0x54, 0x59},

        {0x39, 0x55, 0x54, 0x54, 0x58},

        {0x00, 0x00, 0x45, 0x7C, 0x41},

        {0x00, 0x02, 0x45, 0x7D, 0x42},

        {0x00, 0x01, 0x45, 0x7C, 0x40},

        {0xF0, 0x29, 0x24, 0x29, 0xF0},

        {0xF0, 0x28, 0x25, 0x28, 0xF0},

        {0x7C, 0x54, 0x55, 0x45, 0x00},

        {0x20, 0x54, 0x54, 0x7C, 0x54},

        {0x7C, 0x0A, 0x09, 0x7F, 0x49},

        {0x32, 0x49, 0x49, 0x49, 0x32},

        {0x32, 0x48, 0x48, 0x48, 0x32},

        {0x32, 0x4A, 0x48, 0x48, 0x30},

        {0x3A, 0x41, 0x41, 0x21, 0x7A},

        {0x3A, 0x42, 0x40, 0x20, 0x78},

        {0x00, 0x9D, 0xA0, 0xA0, 0x7D},

        {0x39, 0x44, 0x44, 0x44, 0x39},

        {0x3D, 0x40, 0x40, 0x40, 0x3D},

        {0x3C, 0x24, 0xFF, 0x24, 0x24},

        {0x48, 0x7E, 0x49, 0x43, 0x66},

        {0x2B, 0x2F, 0xFC, 0x2F, 0x2B},

        {0xFF, 0x09, 0x29, 0xF6, 0x20},

        {0xC0, 0x88, 0x7E, 0x09, 0x03},

        {0x20, 0x54, 0x54, 0x79, 0x41},

        {0x00, 0x00, 0x44, 0x7D, 0x41},

        {0x30, 0x48, 0x48, 0x4A, 0x32},

        {0x38, 0x40, 0x40, 0x22, 0x7A},

        {0x00, 0x7A, 0x0A, 0x0A, 0x72},

        {0x7D, 0x0D, 0x19, 0x31, 0x7D},

        {0x26, 0x29, 0x29, 0x2F, 0x28},

        {0x26, 0x29, 0x29, 0x29, 0x26},

        {0x30, 0x48, 0x4D, 0x40, 0x20},

        {0x38, 0x08, 0x08, 0x08, 0x08},

        {0x08, 0x08, 0x08, 0x08, 0x38},

        {0x2F, 0x10, 0xC8, 0xAC, 0xBA},

        {0x2F, 0x10, 0x28, 0x34, 0xFA},

        {0x00, 0x00, 0x7B, 0x00, 0x00},

        {0x08, 0x14, 0x2A, 0x14, 0x22},

        {0x22, 0x14, 0x2A, 0x14, 0x08},

        {0xAA, 0x00, 0x55, 0x00, 0xAA},

        {0xAA, 0x55, 0xAA, 0x55, 0xAA},

        {0x00, 0x00, 0x00, 0xFF, 0x00},

        {0x10, 0x10, 0x10, 0xFF, 0x00},

        {0x14, 0x14, 0x14, 0xFF, 0x00},

        {0x10, 0x10, 0xFF, 0x00, 0xFF},

        {0x10, 0x10, 0xF0, 0x10, 0xF0},

        {0x14, 0x14, 0x14, 0xFC, 0x00},

        {0x14, 0x14, 0xF7, 0x00, 0xFF},

        {0x00, 0x00, 0xFF, 0x00, 0xFF},

        {0x14, 0x14, 0xF4, 0x04, 0xFC},

        {0x14, 0x14, 0x17, 0x10, 0x1F},

        {0x10, 0x10, 0x1F, 0x10, 0x1F},

        {0x14, 0x14, 0x14, 0x1F, 0x00},

        {0x10, 0x10, 0x10, 0xF0, 0x00},

        {0x00, 0x00, 0x00, 0x1F, 0x10},

        {0x10, 0x10, 0x10, 0x1F, 0x10},

        {0x10, 0x10, 0x10, 0xF0, 0x10},

        {0x00, 0x00, 0x00, 0xFF, 0x10},

        {0x10, 0x10, 0x10, 0x10, 0x10},

        {0x10, 0x10, 0x10, 0xFF, 0x10},

        {0x00, 0x00, 0x00, 0xFF, 0x14},

        {0x00, 0x00, 0xFF, 0x00, 0xFF},

        {0x00, 0x00, 0x1F, 0x10, 0x17},

        {0x00, 0x00, 0xFC, 0x04, 0xF4},

        {0x14, 0x14, 0x17, 0x10, 0x17},

        {0x14, 0x14, 0xF4, 0x04, 0xF4},

        {0x00, 0x00, 0xFF, 0x00, 0xF7},

        {0x14, 0x14, 0x14, 0x14, 0x14},

        {0x14, 0x14, 0xF7, 0x00, 0xF7},

        {0x14, 0x14, 0x14, 0x17, 0x14},

        {0x10, 0x10, 0x1F, 0x10, 0x1F},

        {0x14, 0x14, 0x14, 0xF4, 0x14},

        {0x10, 0x10, 0xF0, 0x10, 0xF0},

        {0x00, 0x00, 0x1F, 0x10, 0x1F},

        {0x00, 0x00, 0x00, 0x1F, 0x14},

        {0x00, 0x00, 0x00, 0xFC, 0x14},

        {0x00, 0x00, 0xF0, 0x10, 0xF0},

        {0x10, 0x10, 0xFF, 0x10, 0xFF},

        {0x14, 0x14, 0x14, 0xFF, 0x14},

        {0x10, 0x10, 0x10, 0x1F, 0x00},

        {0x00, 0x00, 0x00, 0xF0, 0x10},

        {0xFF, 0xFF, 0xFF, 0xFF, 0xFF},

        {0xF0, 0xF0, 0xF0, 0xF0, 0xF0},

        {0xFF, 0xFF, 0xFF, 0x00, 0x00},

        {0x00, 0x00, 0x00, 0xFF, 0xFF},

        {0x0F, 0x0F, 0x0F, 0x0F, 0x0F},

        {0x38, 0x44, 0x44, 0x38, 0x44},

        {0x7C, 0x2A, 0x2A, 0x3E, 0x14},

        {0x7E, 0x02, 0x02, 0x06, 0x06},

        {0x02, 0x7E, 0x02, 0x7E, 0x02},

        {0x63, 0x55, 0x49, 0x41, 0x63},

        {0x38, 0x44, 0x44, 0x3C, 0x04},

        {0x40, 0x7E, 0x20, 0x1E, 0x20},

        {0x06, 0x02, 0x7E, 0x02, 0x02},

        {0x99, 0xA5, 0xE7, 0xA5, 0x99},

        {0x1C, 0x2A, 0x49, 0x2A, 0x1C},

        {0x4C, 0x72, 0x01, 0x72, 0x4C},

        {0x30, 0x4A, 0x4D, 0x4D, 0x30},

        {0x30, 0x48, 0x78, 0x48, 0x30},

        {0xBC, 0x62, 0x5A, 0x46, 0x3D},

        {0x3E, 0x49, 0x49, 0x49, 0x00},

        {0x7E, 0x01, 0x01, 0x01, 0x7E},

        {0x2A, 0x2A, 0x2A, 0x2A, 0x2A},

        {0x44, 0x44, 0x5F, 0x44, 0x44},

        {0x40, 0x51, 0x4A, 0x44, 0x40},

        {0x40, 0x44, 0x4A, 0x51, 0x40},

        {0x00, 0x00, 0xFF, 0x01, 0x03},

        {0xE0, 0x80, 0xFF, 0x00, 0x00},

        {0x08, 0x08, 0x6B, 0x6B, 0x08},

        {0x36, 0x12, 0x36, 0x24, 0x36},

        {0x06, 0x0F, 0x09, 0x0F, 0x06},

        {0x00, 0x00, 0x18, 0x18, 0x00},

        {0x00, 0x00, 0x10, 0x10, 0x00},

        {0x30, 0x40, 0xFF, 0x01, 0x01},

        {0x00, 0x1F, 0x01, 0x01, 0x1E},

        {0x00, 0x19, 0x1D, 0x17, 0x12},

        {0x00, 0x3C, 0x3C, 0x3C, 0x3C},

        {0x00, 0x00, 0x00, 0x00, 0x00}

};

public void setChar(int x, int y, char c) {

    setChar(x, y, c, white, false);

}

public void setChar(int x, int y, char c, int color, boolean xor) {

    int asciiOffset =  0x00;

    int bitMask = 0x80;

    int charPos = c - asciiOffset;

    if ( (x+(FONT_WIDTH-1)) > OLED_WIDTH ) { return; }

    if ( (y+FONT_HEIGHT) > OLED_HEIGHT ) { return; }

    if ( 0x00&lt;=c && c&lt;=0xFE ) {

        for (int x0 = 0; x0&lt;(FONT_WIDTH-1); x0++) {

            int asciiChar = ASCII[charPos][x0];

            for (int y0=0; y0&lt;FONT_HEIGHT; y0++) {

                int bit = (asciiChar&lt;<y0) & bitMask ;

                if (bit==bitMask) {

                    pixel((x+x0), (y+FONT_HEIGHT-y0), color, xor);

                }

            }

        }

    }

}

public void setString(int x, int y, String str) {

    setString(x, y, str, white, false);

}

public void setString(int x, int y, String str, int color, boolean xor) {

    int posX = x;

    int posY = y;

    if ( (x+FONT_WIDTH) > OLED_WIDTH ) { return; }

    if ( (y+FONT_HEIGHT) > OLED_HEIGHT ) { return; }

    for (int pos=0; pos&lt;str.length(); pos++) {

        char c = str.charAt(pos);

        setChar( posX, posY, c, color, xor);

        posX += FONT_WIDTH ;

        if (posX>=OLED_WIDTH) {

            break;

        }

    }

}

}

How to Use the Library

  1. Create an “oled” folder and place Oled.java in the folder

oled

  1. Import the OLED library into MainActivity.java

import com.theta360.pluginapplication.oled.Oled;

  1. Create an “asset folder” and place images there to handling image files

You can create the asset folder from the Android Studio menu:

[File]-> [New]-> [Folder]-> [Assets Folder]

  1. All you have to do is use the source code from the sample provided here.

Library Call Examples

Below is the first of three examples of library calls in the order of “Explanation of operation (including images such as animated GIF)” and “Source code.” The second and third examples will be supplied in Part II of this blog post.

In the first two examples, the full source code is available but a detailed explanation is omitted.

This leads to the natural question: “How does this display call the library?”

Please use it like checking the calling location by looking at the behavior.

All cases are based on this sample project.

Demo Drawing (mixed figures and images and characters)

Screen saver-like thing

This is the demonstration that is displayed when you first start this sample plug-in. Actually, the movement is smoother than shown here, this animated GIF drops a certain amount of frames. Please see the tweet video at the beginning of this article.

demo

Simple image viewer

If you press the Wi-Fi button or Mode button, it will be in the state of the simple image viewer. You can return to the above state by shooting.

The displayed color image is a 192 x 170 pixels jpeg.

teddy

Again, the movement is smoother than seen in this animated GIF.

teddy 2

Full Source code

You don’t have to look at the demoDraw () that corresponds to the “screensaver-like thing” at the end. It’s a moly-moly code that I just wanted to make the demo flashy …

/**

  • Copyright 2018 Ricoh Company, Ltd.

*

  • Licensed under the Apache License, Version 2.0 (the “License”);

  • you may not use this file except in compliance with the License.

  • You may obtain a copy of the License at

*

  • http://www.apache.org/licenses/LICENSE-2.0

*

  • Unless required by applicable law or agreed to in writing, software

  • distributed under the License is distributed on an “AS IS” BASIS,

  • WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

  • See the License for the specific language governing permissions and

  • limitations under the License.

*/

package com.theta360.pluginapplication;

import android.graphics.Bitmap;

import android.os.Bundle;

import android.util.Log;

import android.view.KeyEvent;

import com.theta360.pluginapplication.task.TakePictureTask;

import com.theta360.pluginapplication.task.TakePictureTask.Callback;

import com.theta360.pluginlibrary.activity.PluginActivity;

import com.theta360.pluginlibrary.callback.KeyCallback;

import com.theta360.pluginlibrary.receiver.KeyReceiver;

import com.theta360.pluginlibrary.values.LedColor;

import com.theta360.pluginlibrary.values.LedTarget;

import com.theta360.pluginapplication.oled.Oled;

public class MainActivity extends PluginActivity {

private TakePictureTask.Callback mTakePictureTaskCallback = new Callback() {

    @Override

    public void onTakePicture(String fileUrl) {

    }

};

//Z1 specific Fn button key code definition

private static final int KEYCODE_FUNCTION = 119;

//For long press operation recognition with onKeyUp()

boolean longPressWLAN = false;

boolean longPressFUNC = false;

Oled oledDisplay = null;        //OLED drawing class

boolean oledInvert = false;   //OLED black and white inverted state

//OLED display operation mode related

private static final int OLED_MODE_MOVE_H = 0;

private static final int OLED_MODE_MOVE_V = 1;

private static final int OLED_MODE_CANGE_THRESH = 2;

int oledMode = OLED_MODE_MOVE_H;

int oledModeTmp = oledMode;

int dispX = 0;              //Photo display area start position x

int dispY = 0;              //Photo display area start position y

int dispWidth = 92;        //Photo display area width

int dispHeight = 24;        //Photo display area height

String srcFileName = "kuma7_192.jpg";

int bitmapThresh = 92;     //Luminance threshold of display image

int srcX = 48;              //Display image start point x

int srcY = 36;              //Display image start point y

int textStartX = dispWidth + 1;  //Character area Horizontal start position x

int textLine1 = 0;              //Character area 1st line height

int textLine2 = 8;              //Character area 2nd line height

int textLine3 = 16;             //Character area 3rd line height

//For OLED display thread termination

private boolean mFinished;

private boolean demoDisplay;

@Override

protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);

    // Set enable to close by pluginlibrary, If you set false, please call close() after finishing your end processing.

    setAutoClose(true);

    //New OLED drawing class

    oledDisplay = new Oled(getApplicationContext());

    oledDisplay.brightness(100);     //Brightness setting

    oledDisplay.clear(oledDisplay.black); //Display area clear setting

    oledDisplay.draw();                     //Reflects the result of clearing the display area

    // Set a callback when a button operation event is acquired.

    setKeyCallback(new KeyCallback() {

        @Override

        public void onKeyDown(int keyCode, KeyEvent event) {

            if (keyCode == KeyReceiver.KEYCODE_CAMERA) {

                /*

                 * To take a static picture, use the takePicture method.

                 * You can receive a fileUrl of the static picture in the callback.

                 */

                new TakePictureTask(mTakePictureTaskCallback).execute();

            }

        }

        @Override

        public void onKeyUp(int keyCode, KeyEvent event) {

            /**

             * You can control the LED of the camera.

             * It is possible to change the way of lighting, the cycle of blinking, the color of light emission.

             * Light emitting color can be changed only LED3.

             */

            notificationLedBlink(LedTarget.LED3, LedColor.BLUE, 1000);

            if (keyCode == KeyReceiver.KEYCODE_CAMERA) {

                //Demo mode when shooting

                demoDisplay = true;

            } else if (keyCode != KEYCODE_FUNCTION) {

                //Demonstration mode is canceled by other than Fn button operation

                demoDisplay = false;

            }

            if (keyCode == KEYCODE_FUNCTION) {

                if (longPressFUNC) {

                    longPressFUNC = false;

                } else {

                    if (oledInvert) {

                        oledInvert = false;

                    } else {

                        oledInvert = true;

                    }

                }

            } else if (keyCode == KeyReceiver.KEYCODE_MEDIA_RECORD) {

                if (oledMode == OLED_MODE_MOVE_V) {

                    srcY += 4;

                    if (srcY > (oledDisplay.imgHeight - dispHeight)) {

                        srcY = oledDisplay.imgHeight - dispHeight;

                    }

                } else if (oledMode == OLED_MODE_MOVE_H) {

                    srcX += 4;

                    if (srcX > (oledDisplay.imgWidth - dispWidth)) {

                        srcX = oledDisplay.imgWidth - dispWidth;

                    }

                } else if (oledMode == OLED_MODE_CANGE_THRESH) {

                    bitmapThresh += 8;

                    if (bitmapThresh > 256) {

                        bitmapThresh = 256;

                    }

                }

            } else if (keyCode == KeyReceiver.KEYCODE_WLAN_ON_OFF) {

                if (longPressWLAN) {

                    longPressWLAN = false;

                } else {

                    if (oledMode == OLED_MODE_MOVE_V) {

                        srcY -= 4;

                        if (srcY &lt; 0) {

                            srcY = 0;

                        }

                    } else if (oledMode == OLED_MODE_MOVE_H) {

                        srcX -= 4;

                        if (srcX &lt; 0) {

                            srcX = 0;

                        }

                    } else if (oledMode == OLED_MODE_CANGE_THRESH) {

                        bitmapThresh -= 8;

                        if (bitmapThresh &lt; 0) {

                            bitmapThresh = 0;

                        }

                    }

                }

            }

        }

        @Override

        public void onKeyLongPress(int keyCode, KeyEvent event) {

            if (keyCode == KEYCODE_FUNCTION) {

                longPressFUNC = true;

                if (oledMode == OLED_MODE_MOVE_H) {

                    oledMode = OLED_MODE_MOVE_V;

                } else {

                    oledMode = OLED_MODE_MOVE_H;

                }

            } else if (keyCode == KeyReceiver.KEYCODE_WLAN_ON_OFF) {

                longPressWLAN = true;

                if (oledMode == OLED_MODE_CANGE_THRESH) {

                    oledMode = oledModeTmp;

                } else {

                    oledModeTmp = oledMode;

                    oledMode = OLED_MODE_CANGE_THRESH;

                }

            }

        }

    });

}

@Override

protected void onResume() {

    super.onResume();

    if (isApConnected()) {

    }

    //Demo display start setting

    demoDisplay = true;

    //Thread start

    mFinished = false;

    drawOledThread();

}

@Override

protected void onPause() {

    // Do end processing

    //close();

    //Instructions to end the thread. I'm not waiting for the end.

    mFinished = true;

    super.onPause();

}

//OLED drawing thread

public void drawOledThread() {

    new Thread(new Runnable() {

        @Override

        public void run() {

            //Drawing loop

            while (mFinished == false) {

                try {

                    if (demoDisplay) {

                        demoDraw();

                    } else {

                        drawImageControl();

                    }

                    //Sleep 5ms to prevent drawing too often

                    Thread.sleep(5);

                } catch (InterruptedException e) {

                    // Deal with error.

                    e.printStackTrace();

                } finally {

                }

            }

        }

    }).start();

}

private void drawImageControl() {

    //Photo display area drawing

    oledDisplay.setBitmap(dispX, dispY, dispWidth, dispHeight, srcX, srcY, bitmapThresh, srcFileName);

    //Character display area clear

    oledDisplay.rectFill(textStartX, textLine1, Oled.OLED_WIDTH - dispWidth, dispHeight, oledDisplay.black, false);

    //Draw '*' to the left of operable parameters

    if (oledMode == OLED_MODE_MOVE_H) {

        oledDisplay.setString(textStartX, textLine1, "*");

    } else if (oledMode == OLED_MODE_MOVE_V) {

        oledDisplay.setString(textStartX, textLine2, "*");

    } else if (oledMode == OLED_MODE_CANGE_THRESH) {

        oledDisplay.setString(textStartX, textLine3, "*");

    }

    //Draw each parameter

    int dispNumX = textStartX + Oled.FONT_WIDTH;

    oledDisplay.setString(dispNumX, textLine1, "X=" + Integer.toString(srcX));

    oledDisplay.setString(dispNumX, textLine2, "Y=" + Integer.toString(srcY));

    oledDisplay.setString(dispNumX, textLine3, "T=" + Integer.toString(bitmapThresh));

    //Output instruction to OLED (oledInvert == false is the same as draw() )

    oledDisplay.invert(oledInvert);

}

//============================================

// Below this, demonstration drawing (too much)

//============================================

boolean lineRollDir = true;

int demoMode = 0;

int demoModeBack = 0;

int demoX0=0;

int demoY0=0;

int demoX1=Oled.OLED_WIDTH-1;

int demoY1=0;

int demoX2=Oled.OLED_WIDTH-1;

int demoY2=Oled.OLED_HEIGHT-1;

int demoX3=0;

int demoY3=Oled.OLED_HEIGHT-1;

int demoThresh = 0;

int demoThreshStep = 2;

int demoImgX = 0;

int demoImgY = 0;

int demoStepX = 1;

int demoStepY = 1;

String demoText = "Demo";

int demoTextX = 52;

int demoTextY = 8;

int demoTextStepX = 1;

int demoTextStepY = -1;

private void demoDraw() {

    oledDisplay.clear();

    if (demoMode!=4) {

        oledDisplay.circleFill(demoX0,demoY0,11);

        oledDisplay.circleFill(demoX2,demoY2,11);

        oledDisplay.circle(demoX1,demoY1, 22);

        oledDisplay.circle(demoX3,demoY3, 22);

        oledDisplay.rect(demoX2-11,demoY0-11, 22,22, oledDisplay.white,true);

        oledDisplay.rect(demoX0-11,demoY2-11, 22,22, oledDisplay.white,true);

        oledDisplay.rectFill(demoX3-23,demoY1-23, 47,47, oledDisplay.white,true);

        oledDisplay.rectFill(demoX1-23,demoY3-23, 47,47, oledDisplay.white,true);

        if (lineRollDir) {

            oledDisplay.line(demoX0,demoY0,demoX1,demoY1, oledDisplay.white,true);

            oledDisplay.line(demoX2,demoY2,demoX3,demoY3, oledDisplay.white,true);

            oledDisplay.line(demoX1,demoY1,demoX2,demoY2, oledDisplay.white,true);

            oledDisplay.line(demoX3,demoY3,demoX0,demoY0, oledDisplay.white,true);

        } else {

            oledDisplay.line(demoX2,demoY0,demoX3,demoY1, oledDisplay.white,true);

            oledDisplay.line(demoX0,demoY2,demoX1,demoY3, oledDisplay.white,true);

            oledDisplay.line(demoX3,demoY1,demoX0,demoY2, oledDisplay.white,true);

            oledDisplay.line(demoX1,demoY3,demoX2,demoY0, oledDisplay.white,true);

        }

    } else {

        oledDisplay.setBitmap(dispX, dispY, Oled.OLED_WIDTH, Oled.OLED_HEIGHT, demoImgX, demoImgY, demoThresh, srcFileName);

    }

    if (demoMode==0) {

        if (demoY1&lt;(Oled.OLED_HEIGHT-1)) {

            demoY1++;

            demoY3=(Oled.OLED_HEIGHT-1)-demoY1;

        } else {

            if (demoX1>0){

                demoX1--;

                demoX3=(Oled.OLED_WIDTH-1)-demoX1;

            } else {

                demoModeBack=1;

                demoMode=4;

            }

        }

    } else if (demoMode==1) {

        if (demoX0&lt;(Oled.OLED_WIDTH-1)) {

            demoX0++;

            demoX2=(Oled.OLED_WIDTH-1)-demoX0;

        } else {

            if ( demoY0&lt;(Oled.OLED_HEIGHT-1) ) {

                demoY0++;

                demoY2=(Oled.OLED_HEIGHT-1)-demoY0;

            } else {

                demoModeBack=2;

                demoImgX = oledDisplay.imgWidth-Oled.OLED_WIDTH;

                demoStepX=-1;

                demoMode=4;

            }

        }

    } else if (demoMode==2) {

        if (demoY1>0) {

            demoY1--;

            demoY3=(Oled.OLED_HEIGHT-1)-demoY1;

        } else {

            if (demoX1&lt;(Oled.OLED_WIDTH-1)) {

                demoX1++;

                demoX3=(Oled.OLED_WIDTH-1)-demoX1;

            } else {

                demoModeBack=3;

                demoImgY = oledDisplay.imgHeight-Oled.OLED_HEIGHT;

                demoStepY = -1;

                demoMode=4;

            }

        }

    } else if (demoMode==3) {

        if ( demoX0>0 ) {

            demoX0--;

            demoX2=(Oled.OLED_WIDTH-1)-demoX0;

        } else {

            if ( demoY0>0 ) {

                demoY0--;

                demoY2=(Oled.OLED_HEIGHT-1)-demoY0;

            } else {

                if (lineRollDir) {

                    lineRollDir = false;

                } else {

                    lineRollDir = true;

                }

                demoModeBack=0;

                demoImgX = oledDisplay.imgWidth-Oled.OLED_WIDTH;

                demoStepX=-1;

                demoImgY = oledDisplay.imgHeight-Oled.OLED_HEIGHT;

                demoStepY = -1;

                demoMode=4;

            }

        }

    } else if (demoMode==4) {

        demoThresh+=demoThreshStep;

        if (demoThresh>256) {

            demoThresh=256;

            demoThreshStep*=-1;

            demoImgX = 0;

            demoImgY = 0;

            demoMode = demoModeBack;

        } else if (demoThresh&lt;0) {

            demoThresh=0;

            demoThreshStep*=-1;

            demoImgX = 0;

            demoImgY = 0;

            demoMode = demoModeBack;

        }

        demoImgX+=demoStepX;

        if (demoImgX>(oledDisplay.imgWidth-Oled.OLED_WIDTH)) {

            demoImgX = oledDisplay.imgWidth-Oled.OLED_WIDTH;

            demoStepX=-1;

        } else if ( demoImgX &lt; 0 ) {

            demoImgX = 0;

            demoStepX = 1;

        }

        demoImgY+=demoStepY;

        if (demoImgY>(oledDisplay.imgHeight-Oled.OLED_HEIGHT)) {

            demoImgY = oledDisplay.imgHeight-Oled.OLED_HEIGHT;

            demoStepY = -1;

        } else if ( demoImgY &lt; 0 ) {

            demoImgY = 0;

            demoStepY = 1;

        }

    }

    oledDisplay.setString(demoTextX, demoTextY, demoText, oledDisplay.white,true);

    demoTextX += demoTextStepX ;

    if ( demoTextX > (Oled.OLED_WIDTH - (demoText.length()*Oled.FONT_WIDTH) ) ) {

        demoTextX = Oled.OLED_WIDTH - (demoText.length()*Oled.FONT_WIDTH) ;

        demoTextStepX *= -1;

    } else if ( demoTextX &lt; 0 ) {

        demoTextX = 0;

        demoTextStepX *= -1;

    }

    demoTextY += demoTextStepY ;

    if ( demoTextY > (Oled.OLED_HEIGHT - Oled.FONT_HEIGHT ) ) {

        demoTextY = Oled.OLED_HEIGHT - Oled.FONT_HEIGHT ;

        demoTextStepY *= -1;

    } else if ( demoTextY &lt; 0 ) {

        demoTextY = 0;

        demoTextStepY *= -1;

    }

    //OLEDへ出力指示(oledInvert==false は draw()と同じ)

    //負荷サンプルです。oledInvert==true のときに、表示が遅くなるのがわかると思います。

    oledDisplay.invert(oledInvert);

}

}

Ping Pong game and QR Code demos will be included in Part II.

Conclusion

I think we have created an OLED drawing library that can be used quite easily. There are some restrictions, and maybe… there may still be bugs, but I would appreciate it if you could point out anything you notice.

Once the display library is in place, it may be easier to create things like:

  • Real-time display of edge-extracted pictures of live view with OpenCV
  • Information display for shooting mode and various settings
  • Histogram display from live view data
  • Graphical level display
  • Real-time display of waveform of sound obtained from the microphone
  • Game that uses the network (such as an egg that goes out to another person’s THETA?)
  • Keyboard connected to THETA, so a terminal can execute ADB commands
  • Debugging information (logcat) of the plug-in sent to OLED
  • And more!

We would appreciate it if you could try creating a new plug-in with your own ideas. It seems that you can make a lot of retro game-like things, breakout-like games, ultra-narrow Tetris, etc. I would be very grateful if you could publish them to the THETA plug-in store!

About the RICOH THETA Plug-in Partner Program

If you are interested in THETA plug-in development, please register for the partner program!

Please be aware that the THETA with its serial number registered with the program will no longer be eligible for standard end-user support.

For detailed information regarding the partner program please see here.

The registration form is here.