CS 330 Lecture 21 – Languages Working Together
Agenda
- what ?s
- calling C++ from Java
- strings
- arrays
TODO
- Start the Timbre homework.
Code
Main.java
public class Main {
public static void main(String[] args) {
Logger.log("brad mittens");
}
}
Logger.java
public class Logger {
static {
System.loadLibrary("logger");
}
public static native void log(String message);
}
native.cpp
#include <asl.h>
#include "native.h"
JNIEXPORT void JNICALL Java_Logger_log(JNIEnv *env, jclass, jstring jstr) {
const char *cstr = env->GetStringUTFChars(jstr, NULL);
asl_log_message(ASL_LEVEL_NOTICE, cstr);
env->ReleaseStringUTFChars(jstr, cstr);
}
makefile
Note to copy and pasters: makefile rules need to be indented with real tabs, not spaces.
Main.class: Main.java Logger.java
javac Main.java
native.h: Main.class
javah -o $@ -force Logger
liblogger.dylib: native.cpp native.h
g++ -shared -I /Library/Java/JavaVirtualMachines/jdk1.8.0_05.jdk/Contents/Home/include -o liblogger.dylib native.cpp
clean:
rm -rf *.dylib *.class native.h
Main.java
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Main {
public static void main(String[] args) throws IOException {
JFrame frame = new JFrame("Thresh");
final BufferedImage leftImage = ImageIO.read(new File(args[0]));
JLabel leftLabel = new JLabel(new ImageIcon(leftImage));
frame.add(leftLabel, BorderLayout.WEST);
final BufferedImage rightImage = new BufferedImage(leftImage.getWidth(), leftImage.getHeight(), leftImage.getType());
final JLabel rightLabel = new JLabel(new ImageIcon(rightImage));
frame.add(rightLabel, BorderLayout.EAST);
JButton processButton = new JButton("Process");
frame.add(processButton, BorderLayout.NORTH);
processButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int[] pixels = leftImage.getRGB(0, 0, leftImage.getWidth(), leftImage.getHeight(), null, 0, leftImage.getWidth());
Imogene.process(pixels, leftImage.getWidth(), leftImage.getHeight());
rightImage.setRGB(0, 0, rightImage.getWidth(), rightImage.getHeight(), pixels, 0, rightImage.getWidth());
rightLabel.setIcon(new ImageIcon(rightImage));
}
});
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
Imogene.java
public final class Imogene {
static {
System.loadLibrary("imogene");
}
public native static void process(int[] pixels, int width, int height);
}
native.cpp
#include <jni.h>
#include <iostream>
#include "native.h"
JNIEXPORT void JNICALL Java_Imogene_process(JNIEnv *env, jclass, jintArray pixels, jint width, jint height) {
int *raster = env->GetIntArrayElements(pixels, NULL);
int *thresholded = new int[width * height];
for (int r = 0; r < height; ++r) {
for (int c = 0; c < width; ++c) {
int argb = raster[c + r * width];
int red = (argb >> 16) & 0xff;
int green = (argb >> 8) & 0xff;
int blue = (argb >> 0) & 0xff;
int gray = (int) (0.2989 * red + 0.5870 * green + 0.1140 * blue);
int intensity = gray < 254 ? 1 : 0;
/* if (gray < 254) { */
/* raster[c + r * width] = 0xFFFFFF; */
/* } else { */
/* raster[c + r * width] = 0; */
/* } */
thresholded[c + r * width] = intensity;
}
}
// Erode
int *dilated = new int[width * height];
for (int r = 1; r < height - 1; ++r) {
for (int c = 1; c < width - 1; ++c) {
if (thresholded[(c - 1) + (r - 1) * width] &&
thresholded[(c - 1) + (r - 0) * width] &&
thresholded[(c - 1) + (r + 1) * width] &&
thresholded[(c - 0) + (r - 1) * width] &&
thresholded[(c - 0) + (r - 0) * width] &&
thresholded[(c - 0) + (r + 1) * width] &&
thresholded[(c + 1) + (r - 1) * width] &&
thresholded[(c + 1) + (r - 0) * width] &&
thresholded[(c + 1) + (r + 1) * width]) {
dilated[c + r * width] = 1;
} else {
dilated[c + r * width] = 0;
}
}
}
// Dilate
for (int r = 1; r < height - 1; ++r) {
for (int c = 1; c < width - 1; ++c) {
if (dilated[(c - 1) + (r - 1) * width] ||
dilated[(c - 1) + (r - 0) * width] ||
dilated[(c - 1) + (r + 1) * width] ||
dilated[(c - 0) + (r - 1) * width] ||
dilated[(c - 0) + (r - 0) * width] ||
dilated[(c - 0) + (r + 1) * width] ||
dilated[(c + 1) + (r - 1) * width] ||
dilated[(c + 1) + (r - 0) * width] ||
dilated[(c + 1) + (r + 1) * width]) {
raster[c + r * width] = 0xffffff;
} else {
raster[c + r * width] = 0;
}
}
}
delete[] thresholded;
delete[] dilated;
env->ReleaseIntArrayElements(pixels, raster, 0);
}
native.cpp.ours
#include "native.h"
JNIEXPORT void JNICALL Java_Imogene_process(JNIEnv *env, jclass, jintArray jpixels, jint width, jint height) {
int *raster = env->GetIntArrayElements(jpixels, NULL);
for (int r = 0; r < height; ++r) {
for (int c = 0; c < width; ++c) {
int argb = raster[r * width + c];
int red = (argb >> 16) & 0xFF;
int green = (argb >> 8) & 0xFF;
int blue = (argb >> 0) & 0xFF;
int grayscale = 0.2989 * red + 0.587 * green + 0.114 * blue;
int bw = grayscale > 128 ? 255 : 0;
raster[r * width + c] = bw | (bw << 8) | (bw << 16);
}
}
env->ReleaseIntArrayElements(jpixels, raster, 0);
}
makefile
Note to copy and pasters: makefile rules need to be indented with real tabs, not spaces.
.PHONY: run
Main.class: Main.java Imogene.java
@echo Newer than Main.class: $?
javac Main.java
native.h: Main.class
@echo Newer than native.h: $?
javah -o $@ -force Imogene
libimogene.dylib: native.cpp native.h
@echo Newer than so: $?
g++ -shared -I/Library/Java/JavaVirtualMachines/jdk1.8.0_05.jdk/Contents/Home/include -o libimogene.dylib native.cpp
run: Main.class libimogene.dylib
java -cp . -Djava.library.path=. Main ~/Desktop/coins5.gif
clean:
rm -rf *.class native.h libimogene.dylib
Haiku
on stratification
The bottom is dark
Because the top gets the light
And it will stay there
The bottom is dark
Because the top gets the light
And it will stay there