I'm currently trying to create an image classification Android app using a TensorFlow Lite model. When I open the Android App and try to perform classification, I keep getting this error message
java.lang.IllegalArgumentException: Label number 3 mismatch the shape on axis 1
Here's the content inside my label file
0 A
1 B
2 C
And here's the code of my Classifier class:
package com.ukzn.signchat;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.media.Image;
import android.util.Log;
import androidx.camera.core.ImageProxy;
import org.tensorflow.lite.DataType;
import org.tensorflow.lite.Interpreter;
import org.tensorflow.lite.support.common.FileUtil;
import org.tensorflow.lite.support.common.TensorProcessor;
import org.tensorflow.lite.support.common.ops.NormalizeOp;
import org.tensorflow.lite.support.image.ImageProcessor;
import org.tensorflow.lite.support.image.TensorImage;
import org.tensorflow.lite.support.image.ops.ResizeOp;
import org.tensorflow.lite.support.image.ops.ResizeWithCropOrPadOp;
import org.tensorflow.lite.support.image.ops.Rot90Op;
import org.tensorflow.lite.support.label.TensorLabel;
import org.tensorflow.lite.support.tensorbuffer.TensorBuffer;
import java.io.IOException;
import java.nio.MappedByteBuffer;
import java.util.List;
import java.util.Map;
public class Classifier {
private Context context;
Interpreter tflite;
final String ASSOCIATED_AXIS_LABELS = "labels.txt";
List<String> associatedAxisLabels = null;
public Classifier(Context context) {
this.context = context;
// load labels to a List<String>
try {
associatedAxisLabels = FileUtil.loadLabels(context, ASSOCIATED_AXIS_LABELS);
} catch (IOException e) {
Log.e("tfliteSupport", "Error reading label file", e);
}
// load model to interpreter
try {
MappedByteBuffer tfliteModel = FileUtil.loadMappedFile(context, "model.tflite");
tflite = new Interpreter(tfliteModel);
} catch (IOException e) {
Log.e("tfliteSupport", "Error reading model", e);
}
}
public String classify(ImageProxy image) {
#SuppressLint("UnsafeExperimentalUsageError")
Image img = image.getImage();
Bitmap bitmap = Utils.toBitmap(img);
int rotation = Utils.getImageRotation(image);
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int size = height > width ? width : height;
ImageProcessor imageProcessor = new ImageProcessor.Builder()
.add(new ResizeWithCropOrPadOp(size, size))
.add(new ResizeOp(224, 224, ResizeOp.ResizeMethod.BILINEAR)) // changed from 128x128
.add(new Rot90Op(rotation))
.build();
TensorImage tensorImage = new TensorImage(DataType.UINT8);
tensorImage.load(bitmap);
tensorImage = imageProcessor.process(tensorImage);
TensorBuffer probabilityBuffer = TensorBuffer.createFixedSize(new int[]{1, 224, 224, 3}, DataType.UINT8);
if (null != tflite) {
tflite.run(tensorImage.getBuffer(), probabilityBuffer.getBuffer());
}
TensorProcessor probabilityProcessor = new TensorProcessor.Builder().add(new NormalizeOp(0, 255)).build();
String result = "";
if (null != associatedAxisLabels) {
// Map of labels and their corresponding probability
TensorLabel labels = new TensorLabel(associatedAxisLabels, probabilityProcessor.process(probabilityBuffer));
// Create a map to access the result based on label
Map<String, Float> floatMap = labels.getMapWithFloatValue();
result = Utils.writeResults(floatMap);
}
return result;
}
}
The classifier is probably based on the MobileNet label format, which requires that labels start from 1. Since you have 0, 1, 2 & it ignores the 0, it doesn't find the 3.
Related
Using an AR glass' API to get its camera frames to do object detection
I tried converting the frames ( Byte Buffer ) to a bitmap and feeding it into my object detection pipeline. I realised there was no detection going on and debugged to find my bitmap is being read as null. Is it possible to input the bytebuffer straight to the interpreter and do object detection? if not my byte is valid and tested just converting to bitmap returns a toast messafe that is invalid and null.
package com.example.jjsdkcameratest;
import androidx.appcompat.app.AppCompatActivity;
import java.io.IOException;
import java.nio.ByteBuffer;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Bundle;
import android.os.FileUtils;
import android.util.Log;
import android.view.SurfaceView;
import android.widget.Button;
import com.example.jjsdkcameratest.ml.SsdMobilenetV11Metadata1;
import com.jorjin.jjsdk.camera.CameraManager;
import com.jorjin.jjsdk.camera.FrameListener;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.widget.ImageView;
import android.widget.Toast;
import org.tensorflow.lite.DataType;
import org.tensorflow.lite.support.common.FileUtil;
import org.tensorflow.lite.support.image.ImageProcessor;
import org.tensorflow.lite.support.image.TensorImage;
import org.tensorflow.lite.support.image.ops.ResizeOp;
import org.tensorflow.lite.support.image.ImageProcessor;
import org.tensorflow.lite.support.image.TensorImage;
import org.tensorflow.lite.support.tensorbuffer.TensorBuffer;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.List;
public class MainActivity extends Activity {
private CameraManager cameraManager;
private SurfaceView cameraSurface;
private Context context;
private ImageView imageView;
private SsdMobilenetV11Metadata1 model;
private ImageProcessor imageProcessor;
private Paint paint;
private List<String> labels;
private List<Integer> colors = Arrays.asList(Color.BLUE, Color.GREEN, Color.CYAN, Color.GRAY, Color.BLACK, Color.DKGRAY, Color.MAGENTA, Color.YELLOW, Color.RED);
private FrameListener frameListener = (buffer, width, height, format) -> {
// Access the data buffer of the previewing frame here
byte[] bytes = buffer.array();
if (bytes == null || bytes.length == 0) {
Log.e("MainActivity", "Frame data is invalid or empty");
Toast.makeText(context, "Error: Frame data not valid", Toast.LENGTH_SHORT).show();
return;
}
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
if (bitmap == null) {
Log.e("MainActivity", "Failed to decode frame data into a bitmap");
Toast.makeText(context, "Error: Failed to decode frame data into a bitmap", Toast.LENGTH_SHORT).show();
}
// Creates inputs for reference.
try {
TensorImage image = TensorImage.fromBitmap(bitmap);
image = imageProcessor.process(image);
// Runs model inference and gets result.
SsdMobilenetV11Metadata1.Outputs outputs = model.process(image);
float[] locations = outputs.getLocationsAsTensorBuffer().getFloatArray();
float[] classes = outputs.getClassesAsTensorBuffer().getFloatArray();
float[] scores = outputs.getScoresAsTensorBuffer().getFloatArray();
float[] numberOfDetections = outputs.getNumberOfDetectionsAsTensorBuffer().getFloatArray();
Bitmap mutable = bitmap.copy(Bitmap.Config.ARGB_8888, true);
Canvas canvas = new Canvas(mutable);
int h = mutable.getHeight();
int w = mutable.getWidth();
paint.setTextSize(h/15f);
paint.setStrokeWidth(h/85f);
int x = 0;
for (int index = 0; index < scores.length; index++) {
float fl = scores[index];
x = index;
x *= 4;
if (fl > 0.5) {
paint.setColor(colors.get(index));
paint.setStyle(Paint.Style.STROKE);
canvas.drawRect(new RectF(locations[x+1]*w, locations[x]*h, locations[x+3]*w, locations[x+2]*h), paint);
paint.setStyle(Paint.Style.FILL);
canvas.drawText(labels.get((int) classes[index]) + " " + Float.toString(fl), locations[x+1]*w, locations[x]*h, paint);
}
}
if (imageView != null) {
imageView.setImageBitmap(bitmap);
}
} catch (NullPointerException npe) {
Log.e("MainActivity", "Null pointer exception occurred", npe);
Toast.makeText(this, "Null pointer exception occurred", Toast.LENGTH_SHORT);
}
};
public ImageView getImageView() {
if (imageView == null) {
imageView = findViewById(R.id.image_view);
}
return imageView;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
labels = FileUtil.loadLabels(this, "labels.txt");
} catch (IOException e) {
e.printStackTrace();
}
context = this;
getImageView();
cameraSurface = findViewById(R.id.surface_camera);
cameraManager = new CameraManager(context);
cameraManager.addSurfaceHolder(cameraSurface.getHolder());
cameraManager.setCameraFrameListener(frameListener);
cameraManager.setResolutionIndex(0);
cameraManager.startCamera(CameraManager.COLOR_FORMAT_RGBA);
imageProcessor = new ImageProcessor.Builder().add(new ResizeOp(300, 300, ResizeOp.ResizeMethod.BILINEAR)).build();
try {
SsdMobilenetV11Metadata1 model = SsdMobilenetV11Metadata1.newInstance(this);
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
protected void onDestroy() {
super.onDestroy();
// Releases model resources if no longer used.
model.close();
cameraManager.stopCamera();
}
}
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Insets;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import org.apache.batik.dom.GenericDOMImplementation;
import org.apache.batik.svggen.SVGGeneratorContext;
import org.apache.batik.svggen.SVGGraphics2D;
import org.scilab.forge.jlatexmath.TeXConstants;
import org.scilab.forge.jlatexmath.TeXFormula;
import org.scilab.forge.jlatexmath.TeXFormula.TeXIconBuilder;
import org.scilab.forge.jlatexmath.TeXIcon;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
public class jlatexmath {
private final static String SVG_NS = "http://www.w3.org/2000/svg";
private final static String SVG_ROOT = "svg";
private final static float FONT_SIZE = 20;
private String renderLatex(String source) {
DOMImplementation DOMImpl = GenericDOMImplementation.getDOMImplementation();
Document document = DOMImpl.createDocument(SVG_NS, SVG_ROOT, null);
SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(document);
SVGGraphics2D g = new SVGGraphics2D(ctx, true);
TeXFormula formula = new TeXFormula(source);
TeXFormula.TeXIconBuilder builder = formula.new TeXIconBuilder();
builder.setStyle(TeXConstants.STYLE_DISPLAY);
builder.setSize(FONT_SIZE);
TeXIcon icon = builder.build();
icon.setInsets(new Insets(0, 0, 0, 0));
g.setSVGCanvasSize(new Dimension(icon.getIconWidth(), icon.getIconHeight()));
g.setColor(new Color(0, 0, 0, 0));
g.fillRect(0, 0, icon.getIconWidth(), icon.getIconHeight());
icon.paintIcon(null, g, 0, 0);
StringWriter out = new StringWriter();
try {
g.stream(out, true);
out.flush();
out.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
return out.toString();
}
public static void main(String[] args) throws IOException {
String latex = "(a+b)^{2}=a^{2}+2ab+b^{2}";
jlatexmath j = new jlatexmath();
String svgString = j.renderLatex(latex);
Files.write(Paths.get("D:/latex.svg"), svgString.getBytes());
System.out.println(svgString);
}
}
I am using jlatexmath-1.0.7 for generating latex images that works fine. but i need svg out so i use apache batik for the same and above code is generating ~17KB file. Some online tool like codecogs.com generating svg of ~7KB for same latex input. how can i remove un-necessary information from svg in java so it can generate less size image.
Have you tried passing false in the constructor SVGGraphics2D(ctx, true)?
It uses text rather than graphics and so the resulting file size is also smaller.
I tried to train the classifier with the sample from internet (from yale), but I keep getting wrong prediction (in fact it only output category "1") when I input one of the training picture as test sample. Could anyone give me some hint? I attached my code below.
(I think the problem might be the training samples as they are already grayscaled. I grayscaled them again because the error bad argument, size(1,30000), (10000,66).... thing shows up If I don't do so.)
import org.opencv.face.FaceRecognizer;
import org.opencv.core.Mat;
import org.opencv.core.MatOfInt;
import org.opencv.core.*;
import org.opencv.face.Face;
import org.opencv.imgcodecs.Imgcodecs;
import java.io.File;
import java.io.FilenameFilter;
import java.util.List;
import java.util.ArrayList;
import org.opencv.imgproc.Imgproc;
public class FaceRecognization {
public static void main(String[] args) {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
String trainingDir = "C:\\Users\\songli\\Desktop\\yale\\train";
String testImgPath = "C:\\Users\\songli\\Desktop\\yale\\5-6.bmp";
Mat testImg = Imgcodecs.imread(testImgPath);
Mat gray = new Mat();
File root = new File(trainingDir);
FilenameFilter bmpFilter = new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(".bmp");
}
};
File[] imageFiles = root.listFiles(bmpFilter);
List<Mat> list = new ArrayList<Mat>(imageFiles.length);
int[] labels = new int[imageFiles.length];
int counter = 0;
int label;
Mat grayImg = new Mat();
Mat grayTestImg = new Mat();
Mat img = new Mat();
for (File image : imageFiles) {
img = Imgcodecs.imread(image.getAbsolutePath());
// System.out.print(img.elemSize());
label = Integer.parseInt(image.getName().split("\\-")[0]);
grayImg.create(img.width(), img.height(), 1);
Imgproc.cvtColor(img, grayImg, Imgproc.COLOR_BGR2GRAY);
list.add(grayImg);
labels[counter] = label;
counter++;
}
// System.out.print(labels[11]);
MatOfInt labels1 = new MatOfInt();
labels1.fromArray(labels);
FaceRecognizer fr = Face.createEigenFaceRecognizer();
fr.train(list, labels1);
grayTestImg.create(testImg.width(), testImg.height(), 1);
Imgproc.cvtColor(testImg, grayTestImg, Imgproc.COLOR_BGR2GRAY);
int predictedlabel = fr.predict_label(grayTestImg);
// Imgcodecs.imwrite("C:\\Users\\songli\\Desktop\\testImg.jpg",
// testImg);
// int[] predLabel = new int[1];
// double[] confidence = new double[1];
// int result = -1;
// fr.predict(testImgGrey,predLabel,confidence);
// result = predLabel[0];
System.out.println("Predicted label: " + predictedlabel);
}
}
Alright guys I know the place I went wrong.
Imgproc.cvtColor(img, grayImg, Imgproc.COLOR_BGR2GRAY); ->
Imgproc.cvtColor(img,img,Imgproc.COLOR_BGR2GRAY);
Done!
A stupid mistake. Sorry guys.
I am trying to run a code in java and when I run this code, it throws the following error:
OpenCV Error: Assertion failed (!empty()) in cv::CascadeClassifier::detectMultiScale, file C:\builds\master_PackSlaveAddon-win64-vc12-static\opencv\modules\objdetect\src\cascadedetect.cpp, line 1634
Exception in thread "main" CvException [org.opencv.core.CvException: cv::Exception: C:\builds\master_PackSlaveAddon-win64-vc12-static\opencv\modules\objdetect\src\cascadedetect.cpp:1634: error: (-215) !empty() in function cv::CascadeClassifier::detectMultiScale
]
at org.opencv.objdetect.CascadeClassifier.detectMultiScale_1(Native Method)
at org.opencv.objdetect.CascadeClassifier.detectMultiScale(CascadeClassifier.java:103)
at FaceDetector.main(FaceDetector.java:30)
My source code is the following:
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.objdetect.CascadeClassifier;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
public class FaceDetector {
public static void main(String[] args) {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
System.out.println("\nRunning FaceDetector");
CascadeClassifier faceDetector = new CascadeClassifier(FaceDetector.class.getResource("haarcascade_frontalface_alt.xml").getPath());
//CascadeClassifier cascade1 = new CascadeClassifier("C:/OpenCV/opencv/sources/data/haarcascades/haarcascade_frontalface_alt.xml");
//CascadeClassifier cascade1 = new CascadeClassifier("C:/OpenCV/opencv/sources/data/lbpcascade/lbpcascade_frontalface.xml");
//CascadeClassifier cascade1=new CascadeClassifier();
//cascade1.load("C:/opencv2.4.9/sources/data/haarcascades/haarcascade_frontalface_alt.xml");
faceDetector.load("C:/opencv2.4.9/sources/data/haarcascades/haarcascade_frontalface_alt.xml");
System.out.println("step1");
Mat image = Imgcodecs.imread(FaceDetector.class.getResource("anuj.jpg").getPath());
System.out.println("step2");
MatOfRect faceDetections = new MatOfRect();
System.out.println("step3");
faceDetector.detectMultiScale(image, faceDetections);
System.out.println("step4");
try {
System.out.println(String.format("Detected %s faces", faceDetections.toArray().length));
} catch (Exception e) {
// TODO Auto-generated catch block
System.err.println("ERROR IS HERE");
//e.printStackTrace();
}
for (Rect rect : faceDetections.toArray()) {
Imgproc.rectangle(image, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height),
new Scalar(0, 255, 0));
}
String filename = "ouput.png";
System.out.println(String.format("Writing %s", filename));
Imgcodecs.imwrite(filename, image);
}
}
Please tell me what is my mistake. I am not able to solve this. I also tried many variations in the code but it does not work.
It seems that the classifier is not being loaded properly from file.
Please ensure that faceDetector.load() returns true, otherwise the file is not being read.
This was posted 5 months ago, but for the sake of people who are still going to be faced with this challenge after trying all proposed solutions, there is another possibility which I found out after facing same challenge. If there are spaces in the URL returned by getPath(), the spaces are returned as "%20".
For example:
/C:/Users/Ayomide.Johnson/Documents/NetBeansProjects/OpenCV%20Test%20Project/build/classes/haarcascade_frontalface_alt.xml
You need to change the "%20" back to spaces.
My tweek was:
FaceDetector.class.getResource("x.JPG").getPath().substring(1).replace("%20", " ") and it worked!
Note: The substring(1) is to remove the initial "/" in the path. If you do not need that call, you can remove it.
I was also struggling with the same problem. Indicating the directory of the haarcascade_frontalface_alt.xml file worked fine for me. You may try it too.
package faceDetection;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
public class FaceDetection
{
public static void main(String[] args)
{
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
CascadeClassifier faceDetector = new CascadeClassifier();
faceDetector.load("D:\\OpenCv\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml");
System.out.println ( "Working" );
// Input image
Mat image = Imgcodecs.imread("E:\\input.jpg");
// Detecting faces
MatOfRect faceDetections = new MatOfRect();
faceDetector.detectMultiScale(image, faceDetections);
// Creating a rectangular box showing faces detected
for (Rect rect : faceDetections.toArray())
{
Imgproc.rectangle(image, new Point(rect.x, rect.y),
new Point(rect.x + rect.width, rect.y + rect.height),
new Scalar(0, 255, 0));
}
// Saving the output image
String filename = "Ouput.jpg";
Imgcodecs.imwrite("E:\\"+filename, image);
}
}
"C:\\opencv2.4.9\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml"
Use double slash when you give path in windows.
Adding convert-buffered-image to mat type variable fixes the problem.
package facedetect;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Rect;
import org.opencv.objdetect.CascadeClassifier;
public class FaceDetector {
// https://blog.openshift.com/day-12-opencv-face-detection-for-java-developers/
// make user library and add it to project
public static void main(String[] args) throws IOException {
BufferedImage image = ImageIO.read(new File("/hayanchoi/scene1.png"));
detectFace(image);
}
private static Mat convertBufImg2Mat(BufferedImage image) {
DataBufferByte s;
byte[] data = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
Mat mat = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8UC3);
mat.put(0, 0, data);
return mat;
}
private static int detectFace(BufferedImage image) {
System.out.println("step0: Running FaceDetector");
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
CascadeClassifier faceDetector = new CascadeClassifier(
FaceDetector.class.getResource("haarcascade_frontalface_alt.xml").getPath());
if (!faceDetector.load("E:/hayanchoi/FaceDetectionTest/bin/facedetect/haarcascade_frontalface_alt.xml")) {
return -1;
}
System.out.println("step1: convert bufferedimage to mat type");
Mat matImage = convertBufImg2Mat(image);
System.out.print("step2: detect face- ");
MatOfRect faceDetections = new MatOfRect();
faceDetector.detectMultiScale(matImage, faceDetections);
System.out.println(String.format(" %s faces", faceDetections.toArray().length));
System.out.println("step3: write faces");
String filename = "/0_research/" + "ouput.png";
for (Rect rect : faceDetections.toArray()) {
writeFrame(filename, matImage, rect);
}
return faceDetections.toArray().length;
}
private static BufferedImage cropImage(BufferedImage src, Rect rect) {
BufferedImage dest = src.getSubimage(rect.x, rect.y, rect.width, rect.height);
return dest;
}
public static void writeFrame(String filename, Mat mat, Rect rect) {
byte[] data = new byte[mat.rows() * mat.cols() * (int) (mat.elemSize())];
mat.get(0, 0, data);
if (mat.channels() == 3) {
for (int i = 0; i < data.length; i += 3) {
byte temp = data[i];
data[i] = data[i + 2];
data[i + 2] = temp;
}
}
BufferedImage image = new BufferedImage(mat.cols(), mat.rows(), BufferedImage.TYPE_3BYTE_BGR);
image.getRaster().setDataElements(0, 0, mat.cols(), mat.rows(), data);
BufferedImage frame = cropImage(image, rect);
try {
ImageIO.write(frame, "png", new File(filename + ".png"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
Java didn't work with getResoure("...").getPath()
So change all lines have that function to absolute path , example :"C:/Users/USER/workspace/SmallTest/bin/face.jpg"
I just have resolved it.
Sorry for bad English
First of all in this case you should check if CascadeClassifier has properly loaded the specified XML resource.
There are 2 ways of doing this: either check if the load() method returns true. Another way (e.g. if you didn't use this method just specifying the necessary resource in the constructor) is to use empty() method to ensure classifier has been loaded properly.
I have been experimenting with a small program to set the desktop image to the current "Astronomy Picture of the Day". I have been using the JNA suggestion to set the wallpaper from a similar question (). However, my code is not working. I am not sure what's wrong - I have little experience with JNA. Here is the code. Please ignore the completely misleading class names - I started with another project to get me going. The part that is not working is the final setting of the wallpaper - no errors get thrown it just doesn't do anything. The image saves fine.
Edit - I have decided to make a batch file that sets the registry keys and run that. The batch file works sometimes then refuses to work other times. So far it's a partial success! The program is now:
Edit 2- I imported the wallpaper code from Can I change my Windows desktop wallpaper programmatically in Java/Groovy? and once I remembered to close the output file (doh!) it worked fine.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.CropImageFilter;
import java.awt.image.FilteredImageSource;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.text.BadLocationException;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTML.Tag;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.HTMLEditorKit.ParserCallback;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.CharacterData;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.io.File;
import java.util.Iterator;
import javax.imageio.*;
import javax.imageio.stream.*;
public class RSSReader {
private class HTMLParse extends HTMLEditorKit
{
/**
* Call to obtain a HTMLEditorKit.Parser object.
*
* #return A new HTMLEditorKit.Parser object.
*/
public HTMLEditorKit.Parser getParser()
{
return super.getParser();
}
}
private class HREFCallback extends ParserCallback
{
private String base;
public HREFCallback(String base)
{
this.base = base;
}
#Override
public void handleStartTag(Tag t,
MutableAttributeSet a,
int pos)
{
if (t == HTML.Tag.A)
{
String href = (String)(a.getAttribute(HTML.Attribute.HREF));
if (href.endsWith("jpg") && href.startsWith("image"))
{
URL u_img;
try
{
u_img = new URL(base + href);
System.out.println(u_img.toString());
Image img = ImageIO.read(u_img);
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
double aspectScreen = dim.getWidth() / dim.getHeight();
double aspectImage = img.getWidth(null) / img.getHeight(null);
System.out.println(Double.toString(aspectScreen)
+ " " + Double.toString(aspectImage));
if (aspectScreen / aspectImage > 1.1 || aspectScreen / aspectImage < 0.9)
{
int x = 0;
int y = 0;
int w = (int)img.getWidth(null);
int h = (int)img.getHeight(null);
if (aspectScreen > aspectImage)
{
// Image needs to be letterboxed
double newHeight = img.getWidth(null) / aspectScreen;
y = (int)((img.getHeight(null) - newHeight) / 2);
h = (int)newHeight;
}
else
{
double newWidth = img.getHeight(null) / aspectScreen;
x = (int)(img.getWidth(null) - newWidth / 2);
w = (int)newWidth;
}
img = Toolkit.getDefaultToolkit().createImage((new FilteredImageSource(img.getSource(),
new CropImageFilter(x,y,w,h))));
}
Image scaled = img.getScaledInstance(dim.width, dim.height, Image.SCALE_DEFAULT);
String l_appdata = System.getenv("APPDATA");
System.out.println(l_appdata);
if (!l_appdata.equals(""))
{
try {
BufferedImage bufImage =
new BufferedImage(scaled.getWidth(null), scaled.getHeight(null),BufferedImage.TYPE_INT_RGB);
Graphics2D bufImageGraphics = bufImage.createGraphics();
bufImageGraphics.drawImage(scaled, 0, 0, null);
String dirname = l_appdata + "\\" + "APOD Wallpaper";
(new File(dirname)).mkdir();
String fname = dirname + "\\" + "apod_wallpaper1.jpg";
File outputfile = new File(fname);
Iterator iter = ImageIO.getImageWritersByFormatName("jpeg");
ImageWriter writer = (ImageWriter)iter.next();
// instantiate an ImageWriteParam object with default compression options
ImageWriteParam iwp = writer.getDefaultWriteParam();
iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
iwp.setCompressionQuality(1); // an integer between 0 and 1
// 1 specifies minimum compression and maximum quality
File file = new File(fname);
FileImageOutputStream output = new FileImageOutputStream(file);
writer.setOutput(output);
IIOImage image = new IIOImage(bufImage, null, null);
writer.write(null, image, iwp);
writer.dispose();
String scriptName = dirname + "\\" + "setwallpaper.bat";
File s = new File(scriptName);
BufferedWriter wr = new BufferedWriter(new FileWriter(s));
wr.write(":: Configure Wallpaper");
wr.newLine();
wr.write("REG ADD \"HKCU\\Control Panel\\Desktop\" /V Wallpaper /T REG_SZ /F /D \"" + fname + "\"");
wr.newLine();
wr.write("REG ADD \"HKCU\\Control Panel\\Desktop\" /V WallpaperStyle /T REG_SZ /F /D 0");
wr.newLine();
wr.write("REG ADD \"HKCU\\Control Panel\\Desktop\" /V TileWallpaper /T REG_SZ /F /D 2");
wr.newLine();
wr.write(":: Make the changes effective immediately");
wr.newLine();
wr.write("%SystemRoot%\\System32\\RUNDLL32.EXE user32.dll, UpdatePerUserSystemParameters");
wr.newLine();
wr.close();
String cmd = "cmd /C start /D\"" + dirname + "\" setwallpaper.bat ";
System.out.println(cmd);
Process p = Runtime.getRuntime().exec(cmd);
try
{
p.waitFor();
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Done");
} catch (IOException e) {
e.printStackTrace();
}
}
}
catch (MalformedURLException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
private static RSSReader instance = null;
private RSSReader() {
}
public static RSSReader getInstance() {
if(instance == null) {
instance = new RSSReader();
}
return instance;
}
public void writeNews() {
try {
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
String base = "http://apod.nasa.gov/apod/";
URL u = new URL(base + "astropix.html"); // your feed url
BufferedReader in = new BufferedReader(new InputStreamReader(u
.openStream()));
HTMLEditorKit.Parser parse = new HTMLParse().getParser();
parse.parse(in,new HREFCallback(base),true);
}
catch (Exception ex)
{
//do nothing
}
}
public static void main(String[] args) {
RSSReader reader = RSSReader.getInstance();
reader.writeNews();
}
}
You can take a look and see how JAWC does it.
FTS:
Jawc stands for Just Another Wallpaper Changer or, if you prefer, JAva Wallpaper Changer.
It is a Plugin-Based Wallpaper Changer and can change your desktop background picture from a > lot of different sources like your PC's folders, or Flickr, or VladStudio, just depending on > which plugins you enable.
Jawc is written using Java and it has been tested to work on Windows, Linux and Mac Os X systems.
Further to Rodrigo's answer, see these classes in particular: http://jawc-wallpaperc.svn.sourceforge.net/viewvc/jawc-wallpaperc/trunk/Jawc/src/it/jwallpaper/platform/impl/