Hello, this is ohayota. Have you ever wanted to make a presentation slide with Processing (?) The other day, I made a slide for the stage at [Ryukyu University and Future University Joint LT] [1] with ** Processing and presented it with Processing. ** ** So, in this article, I'll write about how I made the slides. [1]:https://connpass.com/event/133298/
--Processing (Java) grammar understanding --Understanding object-oriented (classes, etc.) grammar
The slide I'm trying to make here looks like the image below.
We will implement it according to these two images. (The basic explanation of Processing is omitted. If you do not understand, please refer to [Official Reference] [2] etc.) [2]:https://processing.org/reference/
Even if you say to make slides, it is troublesome to write rect (...)
and text (...)
one by one in setup ()
and draw ()
.
Especially if you want to make dozens of slides, it's a hassle (at least I don't like it).
Therefore, we prepared multiple classes and implemented them in ** object-oriented **.
The structure of the class was roughly decided as follows.
-** Slide ** (class representing one slide) -** TopBar ** (class representing the area at the top of the screen) -** TextField ** (a class that represents an area that displays text and images) -** Text ** (class representing the text to be displayed) -** CroppedImage ** (class that displays a circular image) -** Image ** (class that displays a rectangular image) -** BottomBar ** (class representing the area at the bottom of the screen) -** CroppedImage ** (class that displays a circular image)
One set of ** TopBar ** & ** TextField ** & ** BottomBar ** is required for each slide.
We will implement it for each class. First of all, from the preparation.
Before mounting, prepare the screen size, color, images and fonts to be used.
//Font to use
PFont yuGothic90;
PFont yuGothic70;
PFont yuGothic50;
PFont yuGothic30;
PFont yuGothic15;
PFont helvetica;
//Image to use
PImage dummy600;
// createSlides()Put all the slides in
ArrayList<Slide> slides = new ArrayList<Slide>();
String slideName = "Slide name";
int slideNum = 0; //Display target slide number
boolean isKeyTyped = false;
final color backColor = color(240);
final color mainColor = color(0, 0, 70);
final color subColor1 = color(100);
final color subColor2 = color(200);
void setup() {
fullScreen();
noStroke();
noCursor();
imageMode(CENTER);
frameRate(15);
yuGothic90 = createFont("YuGo-Bold", 90, true);
yuGothic70 = createFont("YuGo-Bold", 70, true);
yuGothic50 = createFont("YuGo-Bold", 50, true);
yuGothic30 = createFont("YuGo-Bold", 30, true);
yuGothic15 = createFont("YuGo-Bold", 15, true);
helvetica = createFont("Helvetica-Bold", 50, true);
dummy600 = loadImage("dummy600.png ");
createSlides();
}
void createSlides() {
//Write slide addition process
}
Prepare the materials to be used. Use fillScreen ()
to display it in full screen.
Use createSlides ()
once the Slide class is complete.
Prepare a dummy image of 600px * 600px for the program handled below.
Create a directory called "data" in the same directory and save it as dummy600.png
.
Now that we are ready, we will implement each class. From this point onward, the layout will be determined relatively ** using the vertical and horizontal sizes of the screen. ** **
What you need is as follows.
--Navy blue background --Title --Subtitle --Slide number
Implement so that these can be displayed.
TopBar.pde
class TopBar {
float barHeight;
String title;
String subTitle;
int number;
TopBar(float barHeight, String title, String subTitle, int number) {
this.barHeight = barHeight;
this.title = title;
this.subTitle = subTitle;
this.number = number;
}
void drawBase() {
noStroke();
fill(mainColor);
rect(0, 0, width, barHeight);
}
void drawTitle() {
fill(backColor);
textFont(yuGothic70);
textSize(height/17.5);
textAlign(LEFT, CENTER);
text(title, width/33.6, barHeight/2);
}
void drawSubTitle() {
fill(backColor);
textFont(yuGothic30);
textSize(height/35);
textAlign(RIGHT, CENTER);
text(subTitle, width*10.2/11.2, barHeight/2);
}
void drawNumber() {
fill(backColor);
textFont(helvetica);
textSize(height/21);
textAlign(RIGHT, CENTER);
text(number, width*32.6/33.6, barHeight/2);
}
void draw() {
drawBase();
drawTitle();
drawSubTitle();
drawNumber();
}
}
As shown in the above example, it is a class that displays a single rectangular image.
Image.pde
class Image {
PImage image;
float sizeX;
float sizeY;
float x;
float y;
color back;
boolean isReflect; //Do you need to flip it upside down?
Image(PImage image, float sizeX, float sizeY, float x, float y, color back, boolean isReflect) {
this.image = image;
this.sizeX = sizeX;
this.sizeY = sizeY;
this.x = x;
this.y = y;
this.back = back;
this.isReflect = isReflect;
}
void drawImage() {
pushMatrix();
translate(x, y);
if (isReflect) rotate(radians(180));
image(image, 0, 0, sizeX, sizeY);
popMatrix();
}
void drawFrame() {
noFill();
strokeWeight(sizeY/100+2);
stroke(mainColor);
rect(x-sizeX/2, y-sizeY/2, sizeX, sizeY);
}
void draw() {
drawImage();
drawFrame();
}
}
In the implementation of this class, the method used in [Displaying a round image with Processing] [3] is used. As shown in the above example, this class displays a single image cut out in a circle. [3]:https://qiita.com/ohayota/items/e00e29b2a86a8143f258
CroppedImage.pde
class CroppedImage {
PImage image;
float size;
float x;
float y;
color back;
boolean isReflect; //Do you need to flip it upside down?
CroppedImage(PImage image, float size, float x, float y, color back, boolean isReflect) {
this.image = image;
this.size = size;
this.x = x;
this.y = y;
this.back = back;
this.isReflect = isReflect;
}
void drawBaseImage() {
pushMatrix();
translate(x, y);
if (isReflect) rotate(radians(180));
image(image, 0, 0, size, size);
popMatrix();
}
//Cut out a circle inside a square
void drawCroppedShape() {
pushMatrix();
translate(x, y);
fill(back);
noStroke();
beginShape();
//The outer frame of the figure
vertex(-(size/2+1), -(size/2+1));
vertex(size/2+1, -(size/2+1));
vertex(size/2+1, size/2+1);
vertex(-(size/2+1), size/2+1);
//Drawing a shape to cut out
beginContour();
for (int i = 360; 0 < i; i--) {
vertex(size/2 * cos(radians(i)), size/2 * sin(radians(i)));
}
endContour();
endShape(CLOSE);
popMatrix();
}
void drawFrame() {
//Draw the frame of the cropped image
noFill();
strokeWeight(size/100+2);
stroke(mainColor);
ellipse(x, y, size, size);
}
//To be precise, instead of cropping the image itself, draw the cropped figure on top of the image.
void draw() {
drawBaseImage();
drawCroppedShape();
drawFrame();
}
}
What you need is as follows.
--Dark gray background --Slide name --Presenter icon and name
Implement so that these can be displayed.
BottomBar.pde
class BottomBar {
float barHeight;
String title;
CroppedImage image;
BottomBar(float barHeight, String title) {
this.barHeight = barHeight;
this.title = title;
image = new CroppedImage(dummy600, barHeight*2/3, width*7.5/8.4, height-barHeight/2, subColor1, false);
}
void drawBase() {
noStroke();
fill(subColor1);
rect(0, height-barHeight, width, barHeight);
}
void drawTitle() {
fill(subColor2);
textFont(yuGothic30);
textSize(height/35);
textAlign(LEFT, CENTER);
text(title, width/33.6, height-barHeight/2);
}
void drawUserInfo() {
textSize(height/42);
text("User name", image.x + image.size/2 + width/168, image.y - barHeight/8);
textFont(yuGothic15);
textSize(height/70);
text("User ID, etc.", image.x + image.size/2 + width/168, image.y + barHeight/6);
image.draw();
}
void draw() {
drawBase();
drawTitle();
drawUserInfo();
}
}
A class that represents an area for displaying text and images. Set the level from 1 to 3 for bullets. A circle marker is displayed on the second level, and a line marker is displayed on the third level.
TextField.pde
class TextField {
float topBarHeight;
float bottomBarHeight;
float x;
float y;
float fieldWidth;
float fieldHeight;
ArrayList<CroppedImage> cImages;
ArrayList<Image> images;
ArrayList<Text> texts;
TextField(float topBarHeight, float bottomBarHeight, float marginX, float marginY) {
this.topBarHeight = topBarHeight;
this.bottomBarHeight = bottomBarHeight;
this.x = marginX;
this.y = topBarHeight + marginY;
fieldWidth = width - marginX*2;
fieldHeight = height - (y+bottomBarHeight+marginY);
cImages = new ArrayList<CroppedImage>();
images = new ArrayList<Image>();
texts = new ArrayList<Text>();
}
void drawImages() {
for (CroppedImage img: cImages) img.draw();
for (Image img: images) img.draw();
}
void drawTexts() {
if (!texts.isEmpty()) {
int textX = 0;
int textY = 0;
int beforeLevel = texts.get(0).level;
for (int i = 0; i < texts.size(); i++) {
Text t = texts.get(i);
switch (t.level) {
case 0:
textX = 0;
textY += height/17.5;
break;
case 1:
textX = 0;
t.draw(textX, textY);
textY += height/15;
break;
case 2:
if (beforeLevel == 3) {
textX -= width/28;
} else if (beforeLevel != 2) {
textX += width/28;
}
t.draw(textX, textY);
textY += height/17.5;
break;
case 3:
if (beforeLevel != 3) textX += width/28;
t.draw(textX, textY);
textY += height/21;
break;
default:
}
beforeLevel = t.level;
}
}
}
void draw() {
pushMatrix();
//Since the position in the TextField is set, the origin is at the upper left of the TextField.(0, 0)To
translate(x, y);
drawTexts();
drawImages();
popMatrix();
}
}
Text class used in TextField class. It has information such as text content, level, font, marker, and color.
Text.pde
class Text {
String text;
int level;
Text(String text, int level) {
this.text = text;
this.level = level;
}
//A circle is displayed on the left side of the text for the second level, and a line is displayed as a marker for the third level.
void drawMarker(float x, float y) {
switch (level) {
case 2:
fill(mainColor);
noStroke();
ellipse(x-width/48, y+height/52.5, height/42, height/42);
break;
case 3:
stroke(mainColor);
strokeCap(SQUARE);
strokeWeight(height/262.5);
line(x-width/33.6, y+height/70, x-width/60, y+height/70);
break;
default:
return;
}
}
void drawText(float x, float y) {
switch (level) {
case 1:
fill(mainColor);
textFont(yuGothic50);
textSize(height/21);
break;
case 2:
fill(subColor1);
textFont(yuGothic50);
textSize(height/26.25);
break;
case 3:
fill(subColor1);
textFont(yuGothic30);
textSize(height/35);
break;
default:
return;
}
textAlign(LEFT, TOP);
text(text, x, y);
}
void draw(float x, float y) {
drawMarker(x, y);
drawText(x, y);
}
}
A class that represents one slide.
Slide.pde
class Slide {
TopBar topBar;
BottomBar bottomBar;
TextField textField;
int number; //Slide number
boolean isCover;
String title;
String subTitle;
Slide(boolean isCover, int number, String title, String subTitle) {
topBar = new TopBar(height/8, title, subTitle, number);
bottomBar = new BottomBar(height/12, slideName);
textField = new TextField(topBar.barHeight, bottomBar.barHeight, width/21, height/17.5);
this.isCover = isCover;
this.number = number;
this.title = title;
this.subTitle = subTitle;
}
void drawTitle() {
fill(mainColor);
textFont(yuGothic90);
textSize(height/11.7);
textAlign(CENTER, TOP);
text(title, width/2, height*4.5/13);
}
void drawSubTitle() {
fill(subColor1);
textFont(yuGothic50);
textSize(height/21);
textAlign(CENTER, TOP);
text(subTitle, width/2, height*8.5/13);
}
void draw() {
background(backColor);
if (isCover) {
drawTitle();
drawSubTitle();
} else {
topBar.draw();
bottomBar.draw();
textField.draw();
}
}
}
Now that we have implemented all the classes that make up a slide, we will create each page of the slide (an instance of the Slide class).
At the stage of preparation, there was a function called createSlides ()
.
Add a slide in this function. (This time it is dummy data)
void createSlides() {
//Cover
slides.add(new Slide(true, 0, "title", "サブtitle"));
//1st slide
Slide s1 = new Slide(false, 1, "title", "サブtitle");
s1.textField.texts.add(new Text("1st level", 1));
s1.textField.texts.add(new Text("Second level", 2));
s1.textField.texts.add(new Text("3rd level", 3));
s1.textField.texts.add(new Text("Second level", 2));
s1.textField.texts.add(new Text("3rd level", 3));
s1.textField.texts.add(new Text("", 0)); //Blank line
s1.textField.texts.add(new Text("1st level", 1));
s1.textField.texts.add(new Text("Second level", 2));
s1.textField.texts.add(new Text("Second level", 2));
s1.textField.texts.add(new Text("3rd level", 3));
s1.textField.texts.add(new Text("3rd level", 3));
s1.textField.cImages.add(new CroppedImage(dummy600, s1.textField.fieldWidth/3,
s1.textField.x + s1.textField.fieldWidth*7/10,
s1.textField.fieldHeight/2, backColor, false));
slides.add(s1);
//2nd slide
Slide s2 = new Slide(false, 2, "title", "サブtitle");
s2.textField.texts.add(new Text("1st level", 1));
s2.textField.texts.add(new Text("Second level", 2));
s2.textField.texts.add(new Text("3rd level", 3));
s2.textField.texts.add(new Text("Second level", 2));
s2.textField.texts.add(new Text("3rd level", 3));
s2.textField.texts.add(new Text("", 0)); //Blank line
s2.textField.texts.add(new Text("1st level", 1));
s2.textField.texts.add(new Text("Second level", 2));
s2.textField.texts.add(new Text("Second level", 2));
s2.textField.texts.add(new Text("3rd level", 3));
s2.textField.texts.add(new Text("3rd level", 3));
s2.textField.images.add(new Image(dummy600, s2.textField.fieldWidth/3, s2.textField.fieldWidth/3,
s2.textField.x + s2.textField.fieldWidth*7/10,
s2.textField.fieldHeight/2, backColor, false));
slides.add(s2);
//3rd slide...
}
Create an instance of the slide and add an instance of text (** Text ) or image ( Image ** or ** Cropped Image **) to the textField
inside that instance.
After adding the textField, add an instance of the slide to ʻArrayList
Now that the slide has been added, call draw ()
on the slide with draw ()
.
void draw() {
background(backColor);
slides.get(slideNum).draw();
}
The cover slide is now displayed.
In order to use it for presentations, you need a function that can switch slides. You can switch between them with the left and right arrows on the keyboard.
keyEvent.pde
void keyPressed() {
if (!isKeyTyped) {
switch (keyCode) {
case LEFT:
if (0 < slideNum) {
loop();
slideNum--;
}
break;
case RIGHT:
if (slideNum < slides.size()-1) {
loop();
slideNum++;
}
break;
default:
}
isKeyTyped = true;
}
}
void keyReleased() {
isKeyTyped = false;
}
If you are looping when a key is pressed, you may switch between multiple slides with just one press.
Therefore, add noLoop ()
to the draw ()
function.
void draw() {
background(backColor);
slides.get(slideNum).draw();
noLoop(); //Avoid looping except when a specific key is pressed
}
When the arrow key is pressed once, it will switch one by one. This completes the implementation.
The slides implemented this time were my own slide master, but you can create original slides by customizing the colors and layout in the program. Please try it.
Recommended Posts