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