diff --git a/.classpath b/.classpath index eebe9ca..98de9f8 100644 --- a/.classpath +++ b/.classpath @@ -3,5 +3,6 @@ + diff --git a/lib/sanselan-0.97-incubator.jar b/lib/sanselan-0.97-incubator.jar new file mode 100644 index 0000000..fff931f Binary files /dev/null and b/lib/sanselan-0.97-incubator.jar differ diff --git a/src/JpegReader.java b/src/JpegReader.java new file mode 100644 index 0000000..6e88d20 --- /dev/null +++ b/src/JpegReader.java @@ -0,0 +1,174 @@ +import java.awt.color.ColorSpace; +import java.awt.color.ICC_ColorSpace; +import java.awt.color.ICC_Profile; +import java.awt.image.BufferedImage; +import java.awt.image.ColorConvertOp; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; +import java.util.Iterator; + +import javax.imageio.IIOException; +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.stream.ImageInputStream; + +import org.apache.sanselan.ImageReadException; +import org.apache.sanselan.Sanselan; +import org.apache.sanselan.common.byteSources.ByteSource; +import org.apache.sanselan.common.byteSources.ByteSourceFile; +import org.apache.sanselan.formats.jpeg.JpegImageParser; +import org.apache.sanselan.formats.jpeg.segments.UnknownSegment; + +public class JpegReader { + + public static final int COLOR_TYPE_RGB = 1; + public static final int COLOR_TYPE_CMYK = 2; + public static final int COLOR_TYPE_YCCK = 3; + + private int colorType = COLOR_TYPE_RGB; + private boolean hasAdobeMarker = false; + + public BufferedImage readImage(File file) throws IOException, + ImageReadException { + colorType = COLOR_TYPE_RGB; + hasAdobeMarker = false; + + ImageInputStream stream = ImageIO.createImageInputStream(file); + Iterator iter = ImageIO.getImageReaders(stream); + while (iter.hasNext()) { + ImageReader reader = iter.next(); + reader.setInput(stream); + + BufferedImage image; + ICC_Profile profile = null; + try { + image = reader.read(0); + } catch (IIOException e) { + colorType = COLOR_TYPE_CMYK; + checkAdobeMarker(file); + profile = Sanselan.getICCProfile(file); + WritableRaster raster = (WritableRaster) reader.readRaster(0, + null); + if (colorType == COLOR_TYPE_YCCK) + convertYcckToCmyk(raster); + if (hasAdobeMarker) + convertInvertedColors(raster); + image = convertCmykToRgb(raster, profile); + } + + return image; + } + + return null; + } + + public void checkAdobeMarker(File file) throws IOException, + ImageReadException { + JpegImageParser parser = new JpegImageParser(); + ByteSource byteSource = new ByteSourceFile(file); + @SuppressWarnings("rawtypes") + ArrayList segments = parser.readSegments(byteSource, + new int[] { 0xffee }, true); + if (segments != null && segments.size() >= 1) { + UnknownSegment app14Segment = (UnknownSegment) segments.get(0); + byte[] data = app14Segment.bytes; + if (data.length >= 12 && data[0] == 'A' && data[1] == 'd' + && data[2] == 'o' && data[3] == 'b' && data[4] == 'e') { + hasAdobeMarker = true; + int transform = app14Segment.bytes[11] & 0xff; + if (transform == 2) + colorType = COLOR_TYPE_YCCK; + } + } + } + + public static void convertYcckToCmyk(WritableRaster raster) { + int height = raster.getHeight(); + int width = raster.getWidth(); + int stride = width * 4; + int[] pixelRow = new int[stride]; + for (int h = 0; h < height; h++) { + raster.getPixels(0, h, width, 1, pixelRow); + + for (int x = 0; x < stride; x += 4) { + int y = pixelRow[x]; + int cb = pixelRow[x + 1]; + int cr = pixelRow[x + 2]; + + int c = (int) (y + 1.402 * cr - 178.956); + int m = (int) (y - 0.34414 * cb - 0.71414 * cr + 135.95984); + y = (int) (y + 1.772 * cb - 226.316); + + if (c < 0) + c = 0; + else if (c > 255) + c = 255; + if (m < 0) + m = 0; + else if (m > 255) + m = 255; + if (y < 0) + y = 0; + else if (y > 255) + y = 255; + + pixelRow[x] = 255 - c; + pixelRow[x + 1] = 255 - m; + pixelRow[x + 2] = 255 - y; + } + + raster.setPixels(0, h, width, 1, pixelRow); + } + } + + public static void convertInvertedColors(WritableRaster raster) { + int height = raster.getHeight(); + int width = raster.getWidth(); + int stride = width * 4; + int[] pixelRow = new int[stride]; + for (int h = 0; h < height; h++) { + raster.getPixels(0, h, width, 1, pixelRow); + for (int x = 0; x < stride; x++) + pixelRow[x] = 255 - pixelRow[x]; + raster.setPixels(0, h, width, 1, pixelRow); + } + } + + public static BufferedImage convertCmykToRgb(Raster cmykRaster, + ICC_Profile cmykProfile) throws IOException { + if (cmykProfile == null) + cmykProfile = ICC_Profile.getInstance(JpegReader.class + .getResourceAsStream("/ISOcoated_v2_300_eci.icc")); + + if (cmykProfile.getProfileClass() != ICC_Profile.CLASS_DISPLAY) { + byte[] profileData = cmykProfile.getData(); + + if (profileData[ICC_Profile.icHdrRenderingIntent] == ICC_Profile.icPerceptual) { + intToBigEndian(ICC_Profile.icSigDisplayClass, profileData, + ICC_Profile.icHdrDeviceClass); // Header is first + + cmykProfile = ICC_Profile.getInstance(profileData); + } + } + + ICC_ColorSpace cmykCS = new ICC_ColorSpace(cmykProfile); + BufferedImage rgbImage = new BufferedImage(cmykRaster.getWidth(), + cmykRaster.getHeight(), BufferedImage.TYPE_INT_RGB); + WritableRaster rgbRaster = rgbImage.getRaster(); + ColorSpace rgbCS = rgbImage.getColorModel().getColorSpace(); + ColorConvertOp cmykToRgb = new ColorConvertOp(cmykCS, rgbCS, null); + cmykToRgb.filter(cmykRaster, rgbRaster); + return rgbImage; + } + + static void intToBigEndian(int value, byte[] array, int index) { + array[index] = (byte) (value >> 24); + array[index + 1] = (byte) (value >> 16); + array[index + 2] = (byte) (value >> 8); + array[index + 3] = (byte) (value); + } +} \ No newline at end of file diff --git a/src/Main.java b/src/Main.java index 634e4c1..a6e271a 100644 --- a/src/Main.java +++ b/src/Main.java @@ -18,6 +18,7 @@ import java.net.HttpURLConnection; import java.net.URL; import javax.imageio.ImageIO; +import javax.swing.ImageIcon; import javax.swing.JFrame; import com.google.gson.Gson; @@ -91,7 +92,7 @@ public class Main extends Canvas implements KeyListener, MouseMotionListener { for (Image image : response.data) { if (!(image.nsfw && filterNSFW) && !image.type.equals("image/gif")) { String url = "http://imgur.com/" + (image.id) + (parseExtension(image.type)); - currentimage = ImageIO.read(new URL(url)); + currentimage = convertImage(new ImageIcon(new URL(url)).getImage()); currentimage = getScaledImage(currentimage, getWidth(), getHeight()); repaint(); Thread.sleep(SLEEPTIME); @@ -104,6 +105,12 @@ public class Main extends Canvas implements KeyListener, MouseMotionListener { } } + private BufferedImage convertImage(java.awt.Image image){ + BufferedImage buffer = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB); + buffer.getGraphics().drawImage(image, 0, 0, null); + return buffer; + } + private String parseExtension(String type) { if (type.equals("image/jpeg")) { return ".jpg"; diff --git a/src/ScrollingMain.java b/src/ScrollingMain.java index 34bb79d..738803f 100644 --- a/src/ScrollingMain.java +++ b/src/ScrollingMain.java @@ -16,13 +16,16 @@ import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; +import java.util.ArrayList; import javax.imageio.ImageIO; +import javax.swing.ImageIcon; import javax.swing.JFrame; import com.google.gson.Gson; -public class ScrollingMain extends Canvas implements KeyListener, MouseMotionListener { +public class ScrollingMain extends Canvas implements KeyListener, + MouseMotionListener { public static void main(String[] args) { new ScrollingMain(); } @@ -43,41 +46,64 @@ public class ScrollingMain extends Canvas implements KeyListener, MouseMotionLis requestFocus(); // Transparent 16 x 16 pixel cursor image. - BufferedImage cursorImg = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB); + BufferedImage cursorImg = new BufferedImage(16, 16, + BufferedImage.TYPE_INT_ARGB); // Create a new blank cursor. - Cursor blankCursor = Toolkit.getDefaultToolkit().createCustomCursor(cursorImg, new Point(0, 0), "blank cursor"); + Cursor blankCursor = Toolkit.getDefaultToolkit().createCustomCursor( + cursorImg, new Point(0, 0), "blank cursor"); // Set the blank cursor to the JFrame. frame.getContentPane().setCursor(blankCursor); - int pages = Integer.parseInt(new Variable("imgurscreensaver", "pages", "10", false).getValue()); + final int pages = Integer.parseInt(new Variable("imgurscreensaver", + "pages", "10", false).getValue()); - loopPages(pages, new Variable("imgurscreensaver", "subreddit", "annakendrick", false).getValue()); + new Thread(new Runnable() { + public void run() { + loopPages(pages, new Variable("imgurscreensaver", "subreddit", + "annakendrick", false).getValue()); + } + }).start(); + while (true) { + try { + Thread.sleep(35); + } catch (Exception e) { + e.printStackTrace(); + } + repaint(); + } } + private double timeOff = 0; + private void loopPages(int pages, String subreddit) { while (true) - for (int i = 0; i < pages; i++) + for (int page = 0; page < pages; page++) try { - String path = "https://api.imgur.com/3/gallery/r/" + subreddit + "/time/" + i + ".json"; + String path = "https://api.imgur.com/3/gallery/r/" + + subreddit + "/time/" + page + ".json"; - HttpURLConnection connection = (HttpURLConnection) ((new URL(path)).openConnection()); + HttpURLConnection connection = (HttpURLConnection) ((new URL( + path)).openConnection()); System.out.println("Connecting..."); connection.setRequestMethod("GET"); // TODO Auto-generated catch block - connection.addRequestProperty("Authorization", "client-id 76535d44f1f94da"); + connection.addRequestProperty("Authorization", + "client-id 76535d44f1f94da"); connection.connect(); - System.out.println("Response recieved with code " + connection.getResponseCode()); + System.out.println("Response recieved with code " + + connection.getResponseCode()); if (connection.getResponseCode() == 200) { - InputStream responseStream = connection.getInputStream(); + InputStream responseStream = connection + .getInputStream(); StringBuilder builder = new StringBuilder(); int j = -1; while ((j = responseStream.read()) != -1) @@ -86,16 +112,31 @@ public class ScrollingMain extends Canvas implements KeyListener, MouseMotionLis System.out.println(builder.toString()); Gson gson = new Gson(); - ImageArray response = gson.fromJson(builder.toString(), ImageArray.class); + ImageArray response = gson.fromJson(builder.toString(), + ImageArray.class); - for (Image image : response.data) { - if (!(image.nsfw && filterNSFW) && !image.type.equals("image/gif")) { - String url = "http://imgur.com/" + (image.id) + (parseExtension(image.type)); - currentimage = ImageIO.read(new URL(url)); - currentimage = getScaledImage(currentimage, getWidth(), getHeight()); - repaint(); + for (int imageCounter = 0; imageCounter < response.data.length;) { + + Image image = response.data[imageCounter]; + + if(image.type.equals("image/gif")) imageCounter ++; + + else if (!(image.nsfw && filterNSFW) + && images.size() < 6) { + String url = "http://imgur.com/" + (image.id) + + (parseExtension(image.type)); + BufferedImage toAdd = convertImage(new ImageIcon( + new URL(url)).getImage()); + toAdd = getScaledImage(toAdd, getWidth(), + getHeight()); + synchronized (images) { + images.add(toAdd); + } + imageCounter++; + } else { Thread.sleep(SLEEPTIME); } + } } @@ -104,6 +145,13 @@ public class ScrollingMain extends Canvas implements KeyListener, MouseMotionLis } } + private BufferedImage convertImage(java.awt.Image image) { + BufferedImage buffer = new BufferedImage(image.getWidth(null), + image.getHeight(null), BufferedImage.TYPE_INT_ARGB); + buffer.getGraphics().drawImage(image, 0, 0, null); + return buffer; + } + private String parseExtension(String type) { if (type.equals("image/jpeg")) { return ".jpg"; @@ -116,9 +164,12 @@ public class ScrollingMain extends Canvas implements KeyListener, MouseMotionLis } } - private boolean filterNSFW = Boolean.parseBoolean(new Variable("imgurscreensaver", "filterNSFW", "true", false).getValue()); - private BufferedImage currentimage; - private static final long SLEEPTIME = Long.parseLong(new Variable("imgurscreensaver", "SLEEPTIME", "1300", false).getValue()); + private ArrayList images = new ArrayList(); + + private boolean filterNSFW = Boolean.parseBoolean(new Variable( + "imgurscreensaver", "filterNSFW", "true", false).getValue()); + + private static final long SLEEPTIME = 500; public void update(Graphics g) { java.awt.Image buffer = createImage(getWidth(), getHeight()); @@ -127,7 +178,8 @@ public class ScrollingMain extends Canvas implements KeyListener, MouseMotionLis g.drawImage(buffer, 0, 0, null); } - private BufferedImage getScaledImage(BufferedImage image, int width, int height) throws IOException { + private BufferedImage getScaledImage(BufferedImage image, int width, + int height) throws IOException { int imageWidth = image.getWidth(); int imageHeight = image.getHeight(); @@ -136,44 +188,41 @@ public class ScrollingMain extends Canvas implements KeyListener, MouseMotionLis double scaleX = (double) width / imageWidth; double aspect = (double) imageWidth / imageHeight; - double screenAspect = ((double)getWidth()/getHeight()); + double screenAspect = ((double) getWidth() / getHeight()); System.out.println("" + aspect + "\n" + screenAspect); // fill or fit bit - - if (aspect < screenAspect || aspect > 2) - if (scaleX > scaleY) - scaleX = scaleY; - else - scaleY = scaleX; - - //this is fill. fill if aspect is between screen aspect and 2 + + if (scaleX > scaleY) + scaleX = scaleY; else - if (scaleX < scaleY) - scaleX = scaleY; - else - scaleY = scaleX; + scaleY = scaleX; // give us the transform object thing - AffineTransform scaleTransform = AffineTransform.getScaleInstance(scaleX, scaleY); + AffineTransform scaleTransform = AffineTransform.getScaleInstance( + scaleX, scaleY); // then make the scaling algorithm thing. - AffineTransformOp bilinearScaleOp = new AffineTransformOp(scaleTransform, AffineTransformOp.TYPE_BILINEAR); + AffineTransformOp bilinearScaleOp = new AffineTransformOp( + scaleTransform, AffineTransformOp.TYPE_BILINEAR); // out new image that we need to crop onto the buffer with the right // dimensions. - BufferedImage newImage = bilinearScaleOp.filter(image, new BufferedImage((int) (imageWidth * scaleX), (int) (imageHeight * scaleY), image.getType())); + BufferedImage newImage = bilinearScaleOp.filter(image, + new BufferedImage((int) (imageWidth * scaleX), + (int) (imageHeight * scaleY), image.getType())); // Image newImage = image.getScaledInstance((int) (imageWidth * scaleX), // (int) (imageWidth * scaleY), Image.SCALE_SMOOTH); // make the buffer - BufferedImage buffer = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + BufferedImage buffer = new BufferedImage((int) (imageWidth * scaleX), + (int) (imageHeight * scaleY), BufferedImage.TYPE_INT_ARGB); Graphics g = buffer.getGraphics(); int newImageWidth = newImage.getWidth(null); int newImageHeight = newImage.getHeight(null); // do math, shove it on. - g.drawImage(newImage, (width - newImageWidth) / 2, (height - newImageHeight) / 2, null); + g.drawImage(newImage, 0, 0, null); // return dat return buffer; @@ -188,12 +237,24 @@ public class ScrollingMain extends Canvas implements KeyListener, MouseMotionLis try { // BufferedImage image = (BufferedImage) ImageIO.read(new // URL(currentURL)); + if (images.size() > 0) { + g.setColor(Color.BLACK); + g.fillRect(0, 0, getWidth(), getHeight()); - g.setColor(Color.BLACK); - g.fillRect(0, 0, getWidth(), getHeight()); - - g.drawImage(currentimage, 0, 0, null); - + int xPos = (int) (0 - timeOff); + synchronized (images) { + for (BufferedImage image : images) { + g.drawImage(image, xPos, 0, null); + xPos += image.getWidth(); + } + timeOff += 5d; + int firstWidth = images.get(0).getWidth(); + if (timeOff > firstWidth) { + timeOff -= firstWidth; + images.remove(0); + } + } + } } catch (Exception e) { e.printStackTrace(); }