mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-10-04 11:26:44 -04:00
Merge branch 'master' of https://github.com/haraldk/TwelveMonkeys
Conflicts: sandbox/sandbox-common/src/main/java/com/twelvemonkeys/io/enc/DeflateEncoder.java sandbox/sandbox-common/src/main/java/com/twelvemonkeys/io/enc/InflateDecoder.java servlet/src/main/java/com/twelvemonkeys/servlet/GenericFilter.java servlet/src/main/java/com/twelvemonkeys/servlet/GenericServlet.java servlet/src/main/java/com/twelvemonkeys/servlet/HttpServlet.java servlet/src/main/java/com/twelvemonkeys/servlet/ServletResponseStreamDelegate.java servlet/src/main/java/com/twelvemonkeys/servlet/cache/CacheResponseWrapper.java servlet/src/main/java/com/twelvemonkeys/servlet/cache/HTTPCache.java servlet/src/main/java/com/twelvemonkeys/servlet/cache/SerlvetCacheResponseWrapper.java servlet/src/main/java/com/twelvemonkeys/servlet/cache/WritableCachedResponseImpl.java servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageServletResponseImpl.java
This commit is contained in:
@@ -79,6 +79,12 @@
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.sandbox</groupId>
|
||||
<artifactId>sandbox-common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
@@ -120,7 +126,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.2</version>
|
||||
<version>2.4</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestEntries>
|
||||
|
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.image;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.BufferedImageOp;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* AbstractFilter
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: AbstractFilter.java,v 1.0 18.06.12 16:55 haraldk Exp$
|
||||
*/
|
||||
public abstract class AbstractFilter implements BufferedImageOp {
|
||||
public abstract BufferedImage filter(BufferedImage src, BufferedImage dest);
|
||||
|
||||
public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM) {
|
||||
throw new UnsupportedOperationException("Method createCompatibleDestImage not implemented"); // TODO: Implement
|
||||
}
|
||||
|
||||
public Rectangle2D getBounds2D(BufferedImage src) {
|
||||
return new Rectangle2D.Double(0, 0, src.getWidth(), src.getHeight());
|
||||
}
|
||||
|
||||
public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
|
||||
if (dstPt == null) {
|
||||
dstPt = new Point2D.Double();
|
||||
}
|
||||
|
||||
dstPt.setLocation(srcPt);
|
||||
|
||||
return dstPt;
|
||||
}
|
||||
|
||||
public RenderingHints getRenderingHints() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected static void exercise(final String[] args, final BufferedImageOp filter, final Color background) throws IOException {
|
||||
boolean original = false;
|
||||
|
||||
for (String arg : args) {
|
||||
if (arg.startsWith("-")) {
|
||||
if (arg.equals("-o") || arg.equals("--original")) {
|
||||
original = true;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
final File file = new File(arg);
|
||||
BufferedImage image = ImageIO.read(file);
|
||||
|
||||
if (image.getWidth() > 640) {
|
||||
image = new ResampleOp(640, Math.round(image.getHeight() * (640f / image.getWidth())), null).filter(image, null);
|
||||
}
|
||||
|
||||
if (!original) {
|
||||
filter.filter(image, image);
|
||||
}
|
||||
|
||||
final Color bg = original ? Color.BLACK : background;
|
||||
final BufferedImage img = image;
|
||||
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
JFrame frame = new JFrame(filter.getClass().getSimpleName().replace("Filter", "") + "Test: " + file.getName());
|
||||
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
||||
frame.addWindowListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosed(final WindowEvent e) {
|
||||
Window[] windows = Window.getWindows();
|
||||
if (windows == null || windows.length == 0) {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
});
|
||||
frame.getRootPane().getActionMap().put("window-close", new AbstractAction() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Window window = SwingUtilities.getWindowAncestor((Component) e.getSource());
|
||||
window.setVisible(false);
|
||||
window.dispose();
|
||||
}
|
||||
});
|
||||
frame.getRootPane().getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_W, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), "window-close");
|
||||
|
||||
JLabel label = new JLabel(new BufferedImageIcon(img));
|
||||
if (bg != null) {
|
||||
label.setOpaque(true);
|
||||
label.setBackground(bg);
|
||||
}
|
||||
label.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
||||
JScrollPane scrollPane = new JScrollPane(label);
|
||||
scrollPane.setBorder(BorderFactory.createEmptyBorder());
|
||||
frame.add(scrollPane);
|
||||
|
||||
frame.pack();
|
||||
frame.setLocationByPlatform(true);
|
||||
frame.setVisible(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.image;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorConvertOp;
|
||||
import java.awt.image.RescaleOp;
|
||||
import java.io.IOException;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* InstaCRTFilter
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: InstaCRTFilter.java,v 1.0 15.06.12 13:24 haraldk Exp$
|
||||
*/
|
||||
public class InstaCRTFilter extends AbstractFilter {
|
||||
|
||||
// NOTE: This is a PoC, and not good code...
|
||||
public BufferedImage filter(BufferedImage src, BufferedImage dest) {
|
||||
if (dest == null) {
|
||||
dest = createCompatibleDestImage(src, null);
|
||||
}
|
||||
|
||||
// Make grayscale
|
||||
BufferedImage image = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), getRenderingHints()).filter(src, null);
|
||||
|
||||
// Make image faded/too bright
|
||||
image = new RescaleOp(1.2f, 120f, getRenderingHints()).filter(image, image);
|
||||
|
||||
// Blur
|
||||
image = ImageUtil.blur(image, 2.5f);
|
||||
|
||||
Graphics2D g = dest.createGraphics();
|
||||
try {
|
||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
|
||||
g.drawImage(image, 0, 0, null);
|
||||
|
||||
// Rotate it slightly for a more analogue feeling
|
||||
double angle = .0055;
|
||||
g.rotate(angle);
|
||||
|
||||
// Apply fake green-ish h-sync line at random position
|
||||
Random random = new Random();
|
||||
int lineStart = random.nextInt(image.getHeight() - 80);
|
||||
int lineHeight = random.nextInt(10) + 20;
|
||||
|
||||
g.setComposite(AlphaComposite.SrcOver.derive(.3f));
|
||||
g.setPaint(new LinearGradientPaint(
|
||||
0, lineStart, 0, lineStart + lineHeight,
|
||||
new float[] {0, .3f, .9f, 1},
|
||||
new Color[] {new Color(0, true), new Color(0x90AF66), new Color(0x99606F33, true), new Color(0, true)}
|
||||
));
|
||||
g.fillRect(0, lineStart, image.getWidth(), lineHeight);
|
||||
|
||||
// Apply fake large dot-pitch (black lines w/transparency)
|
||||
g.setComposite(AlphaComposite.SrcOver.derive(.55f));
|
||||
g.setColor(Color.BLACK);
|
||||
|
||||
for (int y = 0; y < image.getHeight(); y += 3) {
|
||||
g.setStroke(new BasicStroke(random.nextFloat() / 3 + .8f));
|
||||
g.drawLine(0, y, image.getWidth(), y);
|
||||
}
|
||||
|
||||
// Vignette/border
|
||||
g.setComposite(AlphaComposite.SrcOver.derive(.75f));
|
||||
int focus = Math.min(image.getWidth() / 8, image.getHeight() / 8);
|
||||
g.setPaint(new RadialGradientPaint(
|
||||
new Point(image.getWidth() / 2, image.getHeight() / 2),
|
||||
Math.max(image.getWidth(), image.getHeight()) / 1.6f,
|
||||
new Point(focus, focus),
|
||||
new float[] {0, .3f, .9f, 1f},
|
||||
new Color[] {new Color(0x99FFFFFF, true), new Color(0x00FFFFFF, true), new Color(0x0, true), Color.BLACK},
|
||||
MultipleGradientPaint.CycleMethod.NO_CYCLE
|
||||
));
|
||||
g.fillRect(-2, -2, image.getWidth() + 4, image.getHeight() + 4);
|
||||
|
||||
g.rotate(-angle);
|
||||
|
||||
g.setComposite(AlphaComposite.SrcOver.derive(.35f));
|
||||
g.setPaint(new RadialGradientPaint(
|
||||
new Point(image.getWidth() / 2, image.getHeight() / 2),
|
||||
Math.max(image.getWidth(), image.getHeight()) / 1.65f,
|
||||
new Point(image.getWidth() / 2, image.getHeight() / 2),
|
||||
new float[] {0, .85f, 1f},
|
||||
new Color[] {new Color(0x0, true), new Color(0x0, true), Color.BLACK},
|
||||
MultipleGradientPaint.CycleMethod.NO_CYCLE
|
||||
));
|
||||
g.fillRect(0, 0, image.getWidth(), image.getHeight());
|
||||
|
||||
// Highlight
|
||||
g.setComposite(AlphaComposite.SrcOver.derive(.55f));
|
||||
g.setPaint(new RadialGradientPaint(
|
||||
new Point(image.getWidth(), image.getHeight()),
|
||||
Math.max(image.getWidth(), image.getHeight()) * 1.1f,
|
||||
new Point(image.getWidth() / 2, image.getHeight() / 2),
|
||||
new float[] {0, .75f, 1f},
|
||||
new Color[] {new Color(0x00FFFFFF, true), new Color(0x00FFFFFF, true), Color.WHITE},
|
||||
MultipleGradientPaint.CycleMethod.NO_CYCLE
|
||||
));
|
||||
g.fillRect(0, 0, image.getWidth(), image.getHeight());
|
||||
}
|
||||
finally {
|
||||
g.dispose();
|
||||
}
|
||||
|
||||
// Round corners
|
||||
BufferedImage foo = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D graphics = foo.createGraphics();
|
||||
try {
|
||||
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
graphics.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
|
||||
graphics.setColor(Color.WHITE);
|
||||
double angle = -0.04;
|
||||
g.rotate(angle);
|
||||
graphics.fillRoundRect(1, 1, image.getWidth() - 2, image.getHeight() - 2, 20, 20);
|
||||
}
|
||||
finally {
|
||||
graphics.dispose();
|
||||
}
|
||||
|
||||
foo = ImageUtil.blur(foo, 4.5f);
|
||||
|
||||
// Compose image into rounded corners
|
||||
graphics = foo.createGraphics();
|
||||
try {
|
||||
graphics.setComposite(AlphaComposite.SrcIn);
|
||||
graphics.drawImage(dest, 0, 0, null);
|
||||
}
|
||||
finally {
|
||||
graphics.dispose();
|
||||
}
|
||||
|
||||
// Draw it all back to dest
|
||||
g = dest.createGraphics();
|
||||
try {
|
||||
g.setComposite(AlphaComposite.SrcOver);
|
||||
g.setColor(Color.BLACK);
|
||||
g.fillRect(0, 0, image.getWidth(), image.getHeight());
|
||||
g.drawImage(foo, 0, 0, null);
|
||||
}
|
||||
finally {
|
||||
g.dispose();
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
exercise(args, new InstaCRTFilter(), Color.BLACK);
|
||||
}
|
||||
}
|
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.image;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.RescaleOp;
|
||||
import java.io.IOException;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* InstaLomoFilter
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: InstaLomoFilter.java,v 1.0 15.06.12 13:24 haraldk Exp$
|
||||
*/
|
||||
public class InstaLomoFilter extends AbstractFilter {
|
||||
final private Random random = new Random();
|
||||
|
||||
// NOTE: This is a PoC, and not good code...
|
||||
public BufferedImage filter(BufferedImage src, BufferedImage dest) {
|
||||
if (dest == null) {
|
||||
dest = createCompatibleDestImage(src, null);
|
||||
}
|
||||
|
||||
// Make image faded/washed out/red-ish
|
||||
// DARK WARM
|
||||
float[] scales = new float[] { 2.2f, 2.0f, 1.55f};
|
||||
float[] offsets = new float[] {-20.0f, -90.0f, -110.0f};
|
||||
|
||||
// BRIGHT NATURAL
|
||||
// float[] scales = new float[] { 1.1f, .9f, .7f};
|
||||
// float[] offsets = new float[] {20, 30, 80};
|
||||
|
||||
// Faded, old-style
|
||||
// float[] scales = new float[] { 1.1f, .7f, .3f};
|
||||
// float[] offsets = new float[] {20, 30, 80};
|
||||
|
||||
// float[] scales = new float[] { 1.2f, .4f, .4f};
|
||||
// float[] offsets = new float[] {0, 120, 120};
|
||||
|
||||
// BRIGHT WARM
|
||||
// float[] scales = new float[] {1.1f, .8f, 1.6f};
|
||||
// float[] offsets = new float[] {60, 70, -80};
|
||||
BufferedImage image = new RescaleOp(scales, offsets, getRenderingHints()).filter(src, null);
|
||||
|
||||
// Blur
|
||||
image = ImageUtil.blur(image, 2.5f);
|
||||
|
||||
Graphics2D g = dest.createGraphics();
|
||||
try {
|
||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
|
||||
g.drawImage(image, 0, 0, null);
|
||||
|
||||
// Rotate it slightly for a more analogue feeling
|
||||
double angle = .0055;
|
||||
g.rotate(angle);
|
||||
|
||||
// Scratches
|
||||
g.setComposite(AlphaComposite.SrcOver.derive(.025f));
|
||||
for (int i = 0; i < 100; i++) {
|
||||
g.setColor(random.nextBoolean() ? Color.WHITE : Color.BLACK);
|
||||
g.setStroke(new BasicStroke(random.nextFloat() * 2f));
|
||||
int x = random.nextInt(image.getWidth());
|
||||
|
||||
int off = random.nextInt(100);
|
||||
for (int j = random.nextInt(3); j > 0; j--) {
|
||||
g.drawLine(x + j, 0, x + off - 50 + j, image.getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
// Vignette/border
|
||||
g.setComposite(AlphaComposite.SrcOver.derive(.75f));
|
||||
int focus = Math.min(image.getWidth() / 8, image.getHeight() / 8);
|
||||
g.setPaint(new RadialGradientPaint(
|
||||
new Point(image.getWidth() / 2, image.getHeight() / 2),
|
||||
Math.max(image.getWidth(), image.getHeight()) / 1.6f,
|
||||
new Point(focus, focus),
|
||||
new float[] {0, .3f, .9f, 1f},
|
||||
new Color[] {new Color(0x99FFFFFF, true), new Color(0x00FFFFFF, true), new Color(0x0, true), Color.BLACK},
|
||||
MultipleGradientPaint.CycleMethod.NO_CYCLE
|
||||
));
|
||||
g.fillRect(-2, -2, image.getWidth() + 4, image.getHeight() + 4);
|
||||
|
||||
g.rotate(-angle);
|
||||
|
||||
g.setComposite(AlphaComposite.SrcOver.derive(.35f));
|
||||
g.setPaint(new RadialGradientPaint(
|
||||
new Point(image.getWidth() / 2, image.getHeight() / 2),
|
||||
Math.max(image.getWidth(), image.getHeight()) / 1.65f,
|
||||
new Point(image.getWidth() / 2, image.getHeight() / 2),
|
||||
new float[] {0, .85f, 1f},
|
||||
new Color[] {new Color(0x0, true), new Color(0x0, true), Color.BLACK},
|
||||
MultipleGradientPaint.CycleMethod.NO_CYCLE
|
||||
));
|
||||
g.fillRect(0, 0, image.getWidth(), image.getHeight());
|
||||
|
||||
// Highlight
|
||||
g.setComposite(AlphaComposite.SrcOver.derive(.35f));
|
||||
g.setPaint(new RadialGradientPaint(
|
||||
new Point(image.getWidth(), image.getHeight()),
|
||||
Math.max(image.getWidth(), image.getHeight()) * 1.1f,
|
||||
new Point(image.getWidth() / 2, image.getHeight() / 2),
|
||||
new float[] {0, .75f, 1f},
|
||||
new Color[] {new Color(0x00FFFFFF, true), new Color(0x00FFFFFF, true), Color.PINK},
|
||||
MultipleGradientPaint.CycleMethod.NO_CYCLE
|
||||
));
|
||||
g.fillRect(0, 0, image.getWidth(), image.getHeight());
|
||||
}
|
||||
finally {
|
||||
g.dispose();
|
||||
}
|
||||
|
||||
// Noise
|
||||
NoiseFilter noise = new NoiseFilter();
|
||||
noise.setAmount(10);
|
||||
noise.setDensity(2);
|
||||
dest = noise.filter(dest, dest);
|
||||
|
||||
// Round corners
|
||||
BufferedImage foo = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D graphics = foo.createGraphics();
|
||||
try {
|
||||
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
graphics.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
|
||||
graphics.setColor(Color.WHITE);
|
||||
double angle = (random.nextDouble() * .01) - .005;
|
||||
graphics.rotate(angle);
|
||||
graphics.fillRoundRect(4, 4, image.getWidth() - 8, image.getHeight() - 8, 20, 20);
|
||||
}
|
||||
finally {
|
||||
graphics.dispose();
|
||||
}
|
||||
|
||||
noise.setAmount(20);
|
||||
noise.setDensity(1);
|
||||
noise.setMonochrome(true);
|
||||
foo = noise.filter(foo, foo);
|
||||
|
||||
foo = ImageUtil.blur(foo, 4.5f);
|
||||
|
||||
// Compose image into rounded corners
|
||||
graphics = foo.createGraphics();
|
||||
try {
|
||||
graphics.setComposite(AlphaComposite.SrcIn);
|
||||
graphics.drawImage(dest, 0, 0, null);
|
||||
}
|
||||
finally {
|
||||
graphics.dispose();
|
||||
}
|
||||
|
||||
// Draw it all back to dest
|
||||
g = dest.createGraphics();
|
||||
try {
|
||||
if (dest.getTransparency() != Transparency.OPAQUE) {
|
||||
g.setComposite(AlphaComposite.Clear);
|
||||
}
|
||||
g.setColor(Color.WHITE);
|
||||
g.fillRect(0, 0, image.getWidth(), image.getHeight());
|
||||
g.setComposite(AlphaComposite.SrcOver);
|
||||
g.drawImage(foo, 0, 0, null);
|
||||
}
|
||||
finally {
|
||||
g.dispose();
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
exercise(args, new InstaLomoFilter(), Color.WHITE);
|
||||
}
|
||||
}
|
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.image;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.image.*;
|
||||
import java.io.IOException;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* InstaLomoFilter
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: InstaLomoFilter.java,v 1.0 15.06.12 13:24 haraldk Exp$
|
||||
*/
|
||||
public class InstaSepiaFilter extends AbstractFilter {
|
||||
final private Random random = new Random();
|
||||
|
||||
// NOTE: This is a PoC, and not good code...
|
||||
@Override
|
||||
public BufferedImage filter(BufferedImage src, BufferedImage dest) {
|
||||
if (dest == null) {
|
||||
dest = createCompatibleDestImage(src, null);
|
||||
}
|
||||
|
||||
BufferedImage image = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), getRenderingHints()).filter(src, dest);
|
||||
|
||||
Graphics2D g2d = dest.createGraphics();
|
||||
try {
|
||||
g2d.drawImage(image, 0, 0, null);
|
||||
}
|
||||
finally {
|
||||
g2d.dispose();
|
||||
}
|
||||
|
||||
// Blur
|
||||
image = ImageUtil.blur(image, 2.5f);
|
||||
|
||||
Graphics2D g = dest.createGraphics();
|
||||
try {
|
||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
|
||||
g.drawImage(image, 0, 0, null);
|
||||
|
||||
// Rotate it slightly for a more analogue feeling
|
||||
double angle = -.0055;
|
||||
g.rotate(angle);
|
||||
|
||||
// Vignette/border
|
||||
g.setComposite(AlphaComposite.SrcOver.derive(.35f));
|
||||
g.setPaint(new RadialGradientPaint(
|
||||
new Point(image.getWidth() / 2, image.getHeight() / 2),
|
||||
Math.max(image.getWidth(), image.getHeight()) / 1.65f,
|
||||
new Point(image.getWidth() / 2, image.getHeight() / 2),
|
||||
new float[] {0, .85f, 1f},
|
||||
new Color[] {new Color(0x0, true), new Color(0x0, true), Color.BLACK},
|
||||
MultipleGradientPaint.CycleMethod.NO_CYCLE
|
||||
));
|
||||
g.fillRect(0, 0, image.getWidth(), image.getHeight());
|
||||
|
||||
}
|
||||
finally {
|
||||
g.dispose();
|
||||
}
|
||||
|
||||
// Round corners
|
||||
BufferedImage foo = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D graphics = foo.createGraphics();
|
||||
try {
|
||||
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
graphics.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
|
||||
graphics.setColor(Color.WHITE);
|
||||
double angle = (random.nextDouble() * .01) - .005;
|
||||
graphics.rotate(angle);
|
||||
graphics.fillRoundRect(4, 4, image.getWidth() - 8, image.getHeight() - 8, 20, 20);
|
||||
}
|
||||
finally {
|
||||
graphics.dispose();
|
||||
}
|
||||
|
||||
// Noise
|
||||
NoiseFilter noise = new NoiseFilter();
|
||||
noise.setAmount(20);
|
||||
noise.setDensity(1);
|
||||
noise.setMonochrome(true);
|
||||
foo = noise.filter(foo, foo);
|
||||
|
||||
foo = ImageUtil.blur(foo, 4.5f);
|
||||
|
||||
// Compose image into rounded corners
|
||||
graphics = foo.createGraphics();
|
||||
try {
|
||||
graphics.setComposite(AlphaComposite.SrcIn);
|
||||
graphics.drawImage(dest, 0, 0, null);
|
||||
}
|
||||
finally {
|
||||
graphics.dispose();
|
||||
}
|
||||
|
||||
float[] scales = new float[] {1, 1, 1, 1};
|
||||
float[] offsets = new float[] {80, 40, 0, 0};
|
||||
foo = new RescaleOp(scales, offsets, getRenderingHints()).filter(foo, foo);
|
||||
|
||||
// Draw it all back to dest
|
||||
g = dest.createGraphics();
|
||||
try {
|
||||
g.setComposite(AlphaComposite.SrcOver);
|
||||
g.setColor(Color.WHITE);
|
||||
g.fillRect(0, 0, image.getWidth(), image.getHeight());
|
||||
g.drawImage(foo, 0, 0, null);
|
||||
}
|
||||
finally {
|
||||
g.dispose();
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
exercise(args, new InstaSepiaFilter(), null);
|
||||
}
|
||||
}
|
@@ -61,6 +61,7 @@ import java.util.concurrent.*;
|
||||
public class MappedBufferImage {
|
||||
private static int threads = Runtime.getRuntime().availableProcessors();
|
||||
private static ExecutorService executorService = Executors.newFixedThreadPool(threads * 4);
|
||||
private static ExecutorService executorService2 = Executors.newFixedThreadPool(2);
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
int argIndex = 0;
|
||||
@@ -553,15 +554,15 @@ public class MappedBufferImage {
|
||||
}
|
||||
}
|
||||
|
||||
public void drawTo(Graphics2D g) {
|
||||
public boolean drawTo(Graphics2D g) {
|
||||
BufferedImage img = data.get();
|
||||
|
||||
if (img != null) {
|
||||
g.drawImage(img, x, y, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
// g.setPaint(Color.GREEN);
|
||||
// g.drawString(String.format("[%d, %d]", x, y), x + 20, y + 20);
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
@@ -622,6 +623,7 @@ public class MappedBufferImage {
|
||||
}
|
||||
|
||||
// TODO: Consider a fixed size (mem) LRUCache instead
|
||||
// TODO: Better yet, re-use tiles
|
||||
Map<Point, Tile> tiles = createTileCache();
|
||||
|
||||
private void repaintImage(final Rectangle rect, final Graphics2D g2) {
|
||||
@@ -634,6 +636,15 @@ public class MappedBufferImage {
|
||||
// Paint tiles of the image, to preserve memory
|
||||
final int tileSize = 200;
|
||||
|
||||
// Calculate relative to image(0,0), rather than rect(x, y)
|
||||
int xOff = rect.x % tileSize;
|
||||
int yOff = rect.y % tileSize;
|
||||
|
||||
rect.x -= xOff;
|
||||
rect.y -= yOff;
|
||||
rect.width += xOff;
|
||||
rect.height += yOff;
|
||||
|
||||
int tilesW = 1 + rect.width / tileSize;
|
||||
int tilesH = 1 + rect.height / tileSize;
|
||||
|
||||
@@ -658,10 +669,10 @@ public class MappedBufferImage {
|
||||
// TODO: Could we use ImageProducer/ImageConsumer/ImageObserver interface??
|
||||
|
||||
// Destination (display) coordinates
|
||||
int dstX = (int) Math.round(x * zoom);
|
||||
int dstY = (int) Math.round(y * zoom);
|
||||
int dstW = (int) Math.round(w * zoom);
|
||||
int dstH = (int) Math.round(h * zoom);
|
||||
int dstX = (int) Math.floor(x * zoom);
|
||||
int dstY = (int) Math.floor(y * zoom);
|
||||
int dstW = (int) Math.ceil(w * zoom);
|
||||
int dstH = (int) Math.ceil(h * zoom);
|
||||
|
||||
if (dstW == 0 || dstH == 0) {
|
||||
continue;
|
||||
@@ -678,8 +689,8 @@ public class MappedBufferImage {
|
||||
// final int tileSrcH = Math.min(tileSize, image.getHeight() - tileSrcY);
|
||||
|
||||
// Destination (display) coordinates
|
||||
int tileDstX = (int) Math.round(tileSrcX * zoom);
|
||||
int tileDstY = (int) Math.round(tileSrcY * zoom);
|
||||
int tileDstX = (int) Math.floor(tileSrcX * zoom);
|
||||
int tileDstY = (int) Math.floor(tileSrcY * zoom);
|
||||
// final int tileDstW = (int) Math.round(tileSrcW * zoom);
|
||||
// final int tileDstH = (int) Math.round(tileSrcH * zoom);
|
||||
|
||||
@@ -699,9 +710,7 @@ public class MappedBufferImage {
|
||||
Tile tile = tiles.get(point);
|
||||
|
||||
if (tile != null) {
|
||||
Reference<BufferedImage> img = tile.data;
|
||||
if (img != null) {
|
||||
tile.drawTo(g2);
|
||||
if (tile.drawTo(g2)) {
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
@@ -713,9 +722,8 @@ public class MappedBufferImage {
|
||||
|
||||
// Dispatch to off-thread worker
|
||||
final Map<Point, Tile> localTiles = tiles;
|
||||
executorService.submit(new Runnable() {
|
||||
executorService2.submit(new Runnable() {
|
||||
public void run() {
|
||||
// TODO: Fix rounding issues... Problem is that sometimes the srcW/srcH is 1 pixel off filling the tile...
|
||||
int tileSrcX = (int) Math.round(point.x / zoom);
|
||||
int tileSrcY = (int) Math.round(point.y / zoom);
|
||||
int tileSrcW = Math.min(tileSize, image.getWidth() - tileSrcX);
|
||||
@@ -735,8 +743,14 @@ public class MappedBufferImage {
|
||||
}
|
||||
|
||||
// Test against current view rect, to avoid computing tiles that will be thrown away immediately
|
||||
// TODO: EDT safe?
|
||||
if (!getVisibleRect().intersects(new Rectangle(point.x, point.y, tileDstW, tileDstH))) {
|
||||
final Rectangle visibleRect = new Rectangle();
|
||||
SwingUtilities.invokeAndWait(new Runnable() {
|
||||
public void run() {
|
||||
visibleRect.setBounds(getVisibleRect());
|
||||
}
|
||||
});
|
||||
|
||||
if (!visibleRect.intersects(new Rectangle(point.x, point.y, tileDstW, tileDstH))) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -30,11 +30,12 @@ package com.twelvemonkeys.image;
|
||||
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.DataBuffer;
|
||||
import java.awt.image.SampleModel;
|
||||
import java.awt.image.*;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
|
||||
/**
|
||||
* A factory for creating {@link BufferedImage}s backed by memory mapped files.
|
||||
@@ -50,6 +51,9 @@ public final class MappedImageFactory {
|
||||
// TODO: Create a way to do ColorConvertOp (or other color space conversion) on these images.
|
||||
// - Current implementation of CCOp delegates to internal sun.awt classes that assumes java.awt.DataBufferByte for type byte buffers :-/
|
||||
|
||||
private static final boolean DEBUG = "true".equalsIgnoreCase(System.getProperty("com.twelvemonkeys.image.mapped.debug"));
|
||||
static final RasterFactory RASTER_FACTORY = createRasterFactory();
|
||||
|
||||
private MappedImageFactory() {}
|
||||
|
||||
public static BufferedImage createCompatibleMappedImage(int width, int height, int type) throws IOException {
|
||||
@@ -58,7 +62,8 @@ public final class MappedImageFactory {
|
||||
}
|
||||
|
||||
public static BufferedImage createCompatibleMappedImage(int width, int height, GraphicsConfiguration configuration, int transparency) throws IOException {
|
||||
// TODO: Should we also use the sample model?
|
||||
// BufferedImage temp = configuration.createCompatibleImage(1, 1, transparency);
|
||||
// return createCompatibleMappedImage(width, height, temp.getSampleModel().createCompatibleSampleModel(width, height), temp.getColorModel());
|
||||
return createCompatibleMappedImage(width, height, configuration.getColorModel(transparency));
|
||||
}
|
||||
|
||||
@@ -73,6 +78,88 @@ public final class MappedImageFactory {
|
||||
static BufferedImage createCompatibleMappedImage(int width, int height, SampleModel sm, ColorModel cm) throws IOException {
|
||||
DataBuffer buffer = MappedFileBuffer.create(sm.getTransferType(), width * height * sm.getNumDataElements(), 1);
|
||||
|
||||
return new BufferedImage(cm, new GenericWritableRaster(sm, buffer, new Point()), cm.isAlphaPremultiplied(), null);
|
||||
return new BufferedImage(cm, RASTER_FACTORY.createRaster(sm, buffer, new Point()), cm.isAlphaPremultiplied(), null);
|
||||
}
|
||||
|
||||
private static RasterFactory createRasterFactory() {
|
||||
try {
|
||||
// Try to instantiate, will throw LinkageError if it fails
|
||||
return new SunRasterFactory();
|
||||
}
|
||||
catch (LinkageError e) {
|
||||
if (DEBUG) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.err.println("Could not instantiate SunWritableRaster, falling back to GenericWritableRaster.");
|
||||
}
|
||||
|
||||
// Fall back
|
||||
return new GenericRasterFactory();
|
||||
}
|
||||
|
||||
static interface RasterFactory {
|
||||
WritableRaster createRaster(SampleModel model, DataBuffer buffer, Point origin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic implementation that should work for any JRE, and creates a custom subclass of {@link WritableRaster}.
|
||||
*/
|
||||
static final class GenericRasterFactory implements RasterFactory {
|
||||
public WritableRaster createRaster(final SampleModel model, final DataBuffer buffer, final Point origin) {
|
||||
return new GenericWritableRaster(model, buffer, origin);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sun/Oracle JRE-specific implementation that creates {@code sun.awt.image.SunWritableRaster}.
|
||||
* Callers must catch {@link LinkageError}.
|
||||
*/
|
||||
static final class SunRasterFactory implements RasterFactory {
|
||||
final private Constructor<WritableRaster> factoryMethod = getFactoryMethod();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Constructor<WritableRaster> getFactoryMethod() {
|
||||
try {
|
||||
Class<?> cls = Class.forName("sun.awt.image.SunWritableRaster");
|
||||
|
||||
if (Modifier.isAbstract(cls.getModifiers())) {
|
||||
throw new IncompatibleClassChangeError("sun.awt.image.SunWritableRaster has become abstract and can't be instantiated");
|
||||
}
|
||||
|
||||
return (Constructor<WritableRaster>) cls.getConstructor(SampleModel.class, DataBuffer.class, Point.class);
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
throw new NoClassDefFoundError(e.getMessage());
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
throw new NoSuchMethodError(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public WritableRaster createRaster(final SampleModel model, final DataBuffer buffer, final Point origin) {
|
||||
try {
|
||||
return factoryMethod.newInstance(model, buffer, origin);
|
||||
}
|
||||
catch (InstantiationException e) {
|
||||
throw new Error("Could not create SunWritableRaster: ", e); // Should never happen, as we test for abstract class
|
||||
}
|
||||
catch (IllegalAccessException e) {
|
||||
throw new Error("Could not create SunWritableRaster: ", e); // Should never happen, only public constructors are reflected
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
// Unwrap to allow normal exception flow
|
||||
Throwable cause = e.getCause();
|
||||
|
||||
if (cause instanceof RuntimeException) {
|
||||
throw (RuntimeException) cause;
|
||||
}
|
||||
else if (cause instanceof Error) {
|
||||
throw (Error) cause;
|
||||
}
|
||||
|
||||
throw new UndeclaredThrowableException(cause);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/*
|
||||
Copyright 2006 Jerry Huxtable
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.twelvemonkeys.image;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.WritableRaster;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* NoiseFilter
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: NoiseFilter.java,v 1.0 15.06.12 22:59 haraldk Exp$
|
||||
*/
|
||||
public class NoiseFilter extends AbstractFilter {
|
||||
|
||||
/**
|
||||
* Gaussian distribution for the noise.
|
||||
*/
|
||||
public final static int GAUSSIAN = 0;
|
||||
|
||||
/**
|
||||
* Uniform distribution for the noise.
|
||||
*/
|
||||
public final static int UNIFORM = 1;
|
||||
|
||||
private int amount = 25;
|
||||
private int distribution = UNIFORM;
|
||||
private boolean monochrome = false;
|
||||
private float density = 1;
|
||||
private Random randomNumbers = new Random();
|
||||
|
||||
public NoiseFilter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the amount of effect.
|
||||
*
|
||||
* @param amount the amount
|
||||
* @min-value 0
|
||||
* @max-value 1
|
||||
* @see #getAmount
|
||||
*/
|
||||
public void setAmount(int amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the amount of noise.
|
||||
*
|
||||
* @return the amount
|
||||
* @see #setAmount
|
||||
*/
|
||||
public int getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the distribution of the noise.
|
||||
*
|
||||
* @param distribution the distribution
|
||||
* @see #getDistribution
|
||||
*/
|
||||
public void setDistribution(int distribution) {
|
||||
this.distribution = distribution;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the distribution of the noise.
|
||||
*
|
||||
* @return the distribution
|
||||
* @see #setDistribution
|
||||
*/
|
||||
public int getDistribution() {
|
||||
return distribution;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to use monochrome noise.
|
||||
*
|
||||
* @param monochrome true for monochrome noise
|
||||
* @see #getMonochrome
|
||||
*/
|
||||
public void setMonochrome(boolean monochrome) {
|
||||
this.monochrome = monochrome;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether to use monochrome noise.
|
||||
*
|
||||
* @return true for monochrome noise
|
||||
* @see #setMonochrome
|
||||
*/
|
||||
public boolean getMonochrome() {
|
||||
return monochrome;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the density of the noise.
|
||||
*
|
||||
* @param density the density
|
||||
* @see #getDensity
|
||||
*/
|
||||
public void setDensity(float density) {
|
||||
this.density = density;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the density of the noise.
|
||||
*
|
||||
* @return the density
|
||||
* @see #setDensity
|
||||
*/
|
||||
public float getDensity() {
|
||||
return density;
|
||||
}
|
||||
|
||||
private int random() {
|
||||
return (int) (((distribution == GAUSSIAN ? randomNumbers.nextGaussian() : 2 * randomNumbers.nextFloat() - 1)) * amount);
|
||||
}
|
||||
|
||||
private static int clamp(int x) {
|
||||
if (x < 0) {
|
||||
return 0;
|
||||
}
|
||||
else if (x > 0xff) {
|
||||
return 0xff;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
public int filterRGB(int x, int y, int rgb) {
|
||||
if (randomNumbers.nextFloat() <= density) {
|
||||
int a = rgb & 0xff000000;
|
||||
int r = (rgb >> 16) & 0xff;
|
||||
int g = (rgb >> 8) & 0xff;
|
||||
int b = rgb & 0xff;
|
||||
|
||||
if (monochrome) {
|
||||
int n = random();
|
||||
r = clamp(r + n);
|
||||
g = clamp(g + n);
|
||||
b = clamp(b + n);
|
||||
}
|
||||
else {
|
||||
r = clamp(r + random());
|
||||
g = clamp(g + random());
|
||||
b = clamp(b + random());
|
||||
}
|
||||
return a | (r << 16) | (g << 8) | b;
|
||||
}
|
||||
return rgb;
|
||||
}
|
||||
|
||||
public BufferedImage filter(BufferedImage src, BufferedImage dst) {
|
||||
int width = src.getWidth();
|
||||
int height = src.getHeight();
|
||||
int type = src.getType();
|
||||
WritableRaster srcRaster = src.getRaster();
|
||||
|
||||
if (dst == null) {
|
||||
dst = createCompatibleDestImage(src, null);
|
||||
}
|
||||
WritableRaster dstRaster = dst.getRaster();
|
||||
|
||||
int[] inPixels = new int[width];
|
||||
for (int y = 0; y < height; y++) {
|
||||
// We try to avoid calling getRGB on images as it causes them to become unmanaged, causing horrible performance problems.
|
||||
if (type == BufferedImage.TYPE_INT_ARGB) {
|
||||
srcRaster.getDataElements(0, y, width, 1, inPixels);
|
||||
for (int x = 0; x < width; x++) {
|
||||
inPixels[x] = filterRGB(x, y, inPixels[x]);
|
||||
}
|
||||
dstRaster.setDataElements(0, y, width, 1, inPixels);
|
||||
}
|
||||
else {
|
||||
src.getRGB(0, y, width, 1, inPixels, 0, width);
|
||||
for (int x = 0; x < width; x++) {
|
||||
inPixels[x] = filterRGB(x, y, inPixels[x]);
|
||||
}
|
||||
dst.setRGB(0, y, width, 1, inPixels, 0, width);
|
||||
}
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
}
|
@@ -0,0 +1,87 @@
|
||||
package com.twelvemonkeys.io;
|
||||
|
||||
import com.twelvemonkeys.lang.Validate;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
|
||||
/**
|
||||
* An {@code InputStream} that reads bytes from a {@code String}.
|
||||
*
|
||||
* This class properly converts characters into bytes using a {@code Charset},
|
||||
* unlike the deprecated {@link java.io.StringBufferInputStream}.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: StringInputStream.java,v 1.0 03.09.13 10:19 haraldk Exp$
|
||||
*/
|
||||
public final class StringInputStream extends InputStream {
|
||||
|
||||
private final CharBuffer chars;
|
||||
private final CharsetEncoder encoder;
|
||||
private final ByteBuffer buffer;
|
||||
|
||||
public StringInputStream(final String string, final Charset charset) {
|
||||
this(Validate.notNull(string, "string"), 0, string.length(), charset);
|
||||
}
|
||||
|
||||
public StringInputStream(final String string, int offset, int length, final Charset charset) {
|
||||
chars = CharBuffer.wrap(Validate.notNull(string, "string"), offset, offset + length);
|
||||
encoder = Validate.notNull(charset, "charset").newEncoder();
|
||||
buffer = ByteBuffer.allocate(256);
|
||||
buffer.flip();
|
||||
}
|
||||
|
||||
private boolean fillBuffer() {
|
||||
buffer.clear();
|
||||
encoder.encode(chars, buffer, chars.hasRemaining()); // TODO: Do we have to care about the result?
|
||||
buffer.flip();
|
||||
|
||||
return buffer.hasRemaining();
|
||||
}
|
||||
|
||||
private boolean ensureBuffer() {
|
||||
return buffer.hasRemaining() || (chars.hasRemaining() && fillBuffer());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (!ensureBuffer()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return buffer.get() & 0xff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
if (!ensureBuffer()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int count = Math.min(buffer.remaining(), len);
|
||||
buffer.get(b, off, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long len) throws IOException {
|
||||
if (!ensureBuffer()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int count = (int) Math.min(buffer.remaining(), len);
|
||||
int position = buffer.position();
|
||||
buffer.position(position + count);
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
return buffer.remaining();
|
||||
}
|
||||
}
|
@@ -30,6 +30,7 @@ package com.twelvemonkeys.io.enc;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.zip.Deflater;
|
||||
|
||||
/**
|
||||
@@ -50,7 +51,6 @@ final class DeflateEncoder implements Encoder {
|
||||
private final byte[] buffer = new byte[1024];
|
||||
|
||||
public DeflateEncoder() {
|
||||
// this(new Deflater());
|
||||
this(new Deflater(Deflater.DEFAULT_COMPRESSION, true)); // TODO: Should we use "no wrap"?
|
||||
}
|
||||
|
||||
@@ -62,12 +62,12 @@ final class DeflateEncoder implements Encoder {
|
||||
deflater = pDeflater;
|
||||
}
|
||||
|
||||
public void encode(final OutputStream pStream, final byte[] pBuffer, final int pOffset, final int pLength)
|
||||
public void encode(final OutputStream stream, ByteBuffer buffer)
|
||||
throws IOException
|
||||
{
|
||||
System.out.println("DeflateEncoder.encode");
|
||||
deflater.setInput(pBuffer, pOffset, pLength);
|
||||
flushInputToStream(pStream);
|
||||
deflater.setInput(buffer.array(), buffer.arrayOffset() + buffer.position(), buffer.remaining());
|
||||
flushInputToStream(stream);
|
||||
}
|
||||
|
||||
private void flushInputToStream(final OutputStream pStream) throws IOException {
|
||||
|
@@ -31,6 +31,7 @@ package com.twelvemonkeys.io.enc;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.zip.DataFormatException;
|
||||
import java.util.zip.Inflater;
|
||||
|
||||
@@ -75,17 +76,17 @@ final class InflateDecoder implements Decoder {
|
||||
buffer = new byte[1024];
|
||||
}
|
||||
|
||||
public int decode(final InputStream pStream, final byte[] pBuffer) throws IOException {
|
||||
public int decode(final InputStream stream, final ByteBuffer buffer) throws IOException {
|
||||
try {
|
||||
int decoded;
|
||||
|
||||
while ((decoded = inflater.inflate(pBuffer, 0, pBuffer.length)) == 0) {
|
||||
while ((decoded = inflater.inflate(buffer.array(), buffer.arrayOffset(), buffer.capacity())) == 0) {
|
||||
if (inflater.finished() || inflater.needsDictionary()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (inflater.needsInput()) {
|
||||
fill(pStream);
|
||||
fill(stream);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.net;
|
||||
|
||||
import java.net.*;
|
||||
|
||||
/**
|
||||
* Interface for filtering Authenticator requests, used by the
|
||||
* SimpleAuthenticator.
|
||||
*
|
||||
* @see SimpleAuthenticator
|
||||
* @see java.net.Authenticator
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version 1.0
|
||||
*/
|
||||
public interface AuthenticatorFilter {
|
||||
public boolean accept(InetAddress pAddress, int pPort, String pProtocol, String pPrompt, String pScheme);
|
||||
}
|
143
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/net/BASE64.java
Executable file
143
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/net/BASE64.java
Executable file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.net;
|
||||
|
||||
import com.twelvemonkeys.io.*;
|
||||
import com.twelvemonkeys.io.enc.Base64Decoder;
|
||||
import com.twelvemonkeys.io.enc.DecoderStream;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
|
||||
/**
|
||||
* This class does BASE64 encoding (and decoding).
|
||||
*
|
||||
* @author unascribed
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/util/BASE64.java#1 $
|
||||
* @deprecated Use {@link com.twelvemonkeys.io.enc.Base64Encoder}/{@link Base64Decoder} instead
|
||||
*/
|
||||
class BASE64 {
|
||||
/**
|
||||
* This array maps the characters to their 6 bit values
|
||||
*/
|
||||
private final static char[] PEM_ARRAY = {
|
||||
//0 1 2 3 4 5 6 7
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 0
|
||||
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 1
|
||||
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 2
|
||||
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', // 3
|
||||
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', // 4
|
||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', // 5
|
||||
'w', 'x', 'y', 'z', '0', '1', '2', '3', // 6
|
||||
'4', '5', '6', '7', '8', '9', '+', '/' // 7
|
||||
};
|
||||
|
||||
/**
|
||||
* Encodes the input data using the standard base64 encoding scheme.
|
||||
*
|
||||
* @param pData the bytes to encode to base64
|
||||
* @return a string with base64 encoded data
|
||||
*/
|
||||
public static String encode(byte[] pData) {
|
||||
int offset = 0;
|
||||
int len;
|
||||
StringBuilder buf = new StringBuilder();
|
||||
|
||||
while ((pData.length - offset) > 0) {
|
||||
byte a, b, c;
|
||||
if ((pData.length - offset) > 2) {
|
||||
len = 3;
|
||||
}
|
||||
else {
|
||||
len = pData.length - offset;
|
||||
}
|
||||
|
||||
switch (len) {
|
||||
case 1:
|
||||
a = pData[offset];
|
||||
b = 0;
|
||||
buf.append(PEM_ARRAY[(a >>> 2) & 0x3F]);
|
||||
buf.append(PEM_ARRAY[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]);
|
||||
buf.append('=');
|
||||
buf.append('=');
|
||||
offset++;
|
||||
break;
|
||||
case 2:
|
||||
a = pData[offset];
|
||||
b = pData[offset + 1];
|
||||
c = 0;
|
||||
buf.append(PEM_ARRAY[(a >>> 2) & 0x3F]);
|
||||
buf.append(PEM_ARRAY[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]);
|
||||
buf.append(PEM_ARRAY[((b << 2) & 0x3c) + ((c >>> 6) & 0x3)]);
|
||||
buf.append('=');
|
||||
offset += offset + 2; // ???
|
||||
break;
|
||||
default:
|
||||
a = pData[offset];
|
||||
b = pData[offset + 1];
|
||||
c = pData[offset + 2];
|
||||
buf.append(PEM_ARRAY[(a >>> 2) & 0x3F]);
|
||||
buf.append(PEM_ARRAY[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]);
|
||||
buf.append(PEM_ARRAY[((b << 2) & 0x3c) + ((c >>> 6) & 0x3)]);
|
||||
buf.append(PEM_ARRAY[c & 0x3F]);
|
||||
offset = offset + 3;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public static byte[] decode(String pData) throws IOException {
|
||||
InputStream in = new DecoderStream(new ByteArrayInputStream(pData.getBytes()), new Base64Decoder());
|
||||
ByteArrayOutputStream bytes = new FastByteArrayOutputStream(pData.length() * 3);
|
||||
FileUtil.copy(in, bytes);
|
||||
|
||||
return bytes.toByteArray();
|
||||
}
|
||||
|
||||
//private final static sun.misc.BASE64Decoder DECODER = new sun.misc.BASE64Decoder();
|
||||
|
||||
public static void main(String[] pArgs) throws IOException {
|
||||
if (pArgs.length == 1) {
|
||||
System.out.println(encode(pArgs[0].getBytes()));
|
||||
}
|
||||
else
|
||||
if (pArgs.length == 2 && ("-d".equals(pArgs[0]) || "--decode".equals(pArgs[0])))
|
||||
{
|
||||
System.out.println(new String(decode(pArgs[1])));
|
||||
}
|
||||
else {
|
||||
System.err.println("BASE64 [ -d | --decode ] arg");
|
||||
System.err.println("Encodes or decodes a given string");
|
||||
System.exit(5);
|
||||
}
|
||||
}
|
||||
}
|
1101
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/net/HttpURLConnection.java
Executable file
1101
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/net/HttpURLConnection.java
Executable file
File diff suppressed because it is too large
Load Diff
1258
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/net/NetUtil.java
Executable file
1258
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/net/NetUtil.java
Executable file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.net;
|
||||
|
||||
import java.net.*;
|
||||
|
||||
/**
|
||||
* Interface fro PasswordAuthenticators used by SimpleAuthenticator.
|
||||
*
|
||||
* @see SimpleAuthenticator
|
||||
* @see java.net.Authenticator
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
*
|
||||
* @version 1.0
|
||||
*/
|
||||
public interface PasswordAuthenticator {
|
||||
public PasswordAuthentication requestPasswordAuthentication(InetAddress addr, int port, String protocol, String prompt, String scheme);
|
||||
}
|
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.net;
|
||||
|
||||
import com.twelvemonkeys.lang.Validate;
|
||||
|
||||
import java.net.Authenticator;
|
||||
import java.net.InetAddress;
|
||||
import java.net.PasswordAuthentication;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A simple Authenticator implementation.
|
||||
* Singleton class, obtain reference through the static
|
||||
* {@code getInstance} method.
|
||||
* <p/>
|
||||
* <EM>After swearing, sweating, pulling my hair, banging my head repeatedly
|
||||
* into the walls and reading the java.net.Authenticator API documentation
|
||||
* once more, an idea came to my mind. This is the result. I hope you find it
|
||||
* useful. -- Harald K.</EM>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version 1.0
|
||||
* @see java.net.Authenticator
|
||||
*/
|
||||
public class SimpleAuthenticator extends Authenticator {
|
||||
/** The reference to the single instance of this class. */
|
||||
private static SimpleAuthenticator sInstance = null;
|
||||
/** Keeps track of the state of this class. */
|
||||
private static boolean sInitialized = false;
|
||||
|
||||
// These are used for the identification hack.
|
||||
private final static String MAGIC = "magic";
|
||||
private final static int FOURTYTWO = 42;
|
||||
|
||||
/** Basic authentication scheme. */
|
||||
public final static String BASIC = "Basic";
|
||||
|
||||
/** The hastable that keeps track of the PasswordAuthentications. */
|
||||
protected Map<AuthKey, PasswordAuthentication> passwordAuthentications = null;
|
||||
|
||||
/** The hastable that keeps track of the Authenticators. */
|
||||
protected Map<PasswordAuthenticator, AuthenticatorFilter> authenticators = null;
|
||||
|
||||
/** Creates a SimpleAuthenticator. */
|
||||
private SimpleAuthenticator() {
|
||||
passwordAuthentications = new HashMap<AuthKey, PasswordAuthentication>();
|
||||
authenticators = new HashMap<PasswordAuthenticator, AuthenticatorFilter>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SimpleAuthenticator instance and registers it through the
|
||||
* Authenticator.setDefault(). If there is no current instance
|
||||
* of the SimpleAuthenticator in the VM, one is created. This method will
|
||||
* try to figure out if the setDefault() succeeded (a hack), and will
|
||||
* return null if it was not able to register the instance as default.
|
||||
*
|
||||
* @return The single instance of this class, or null, if another
|
||||
* Authenticator is allready registered as default.
|
||||
*/
|
||||
public static synchronized SimpleAuthenticator getInstance() {
|
||||
if (!sInitialized) {
|
||||
// Create an instance
|
||||
sInstance = new SimpleAuthenticator();
|
||||
|
||||
// Try to set default (this may quietly fail...)
|
||||
Authenticator.setDefault(sInstance);
|
||||
|
||||
// A hack to figure out if we really did set the authenticator
|
||||
PasswordAuthentication pa = Authenticator.requestPasswordAuthentication(null, FOURTYTWO, null, null, MAGIC);
|
||||
|
||||
// If this test returns false, we didn't succeed, so we set the
|
||||
// instance back to null.
|
||||
if (pa == null || !MAGIC.equals(pa.getUserName()) || !("" + FOURTYTWO).equals(new String(pa.getPassword()))) {
|
||||
sInstance = null;
|
||||
}
|
||||
|
||||
// Done
|
||||
sInitialized = true;
|
||||
}
|
||||
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the PasswordAuthentication for the request. Called when password
|
||||
* authorization is needed.
|
||||
*
|
||||
* @return The PasswordAuthentication collected from the user, or null if
|
||||
* none is provided.
|
||||
*/
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
// Don't worry, this is just a hack to figure out if we were able
|
||||
// to set this Authenticator through the setDefault method.
|
||||
if (!sInitialized && MAGIC.equals(getRequestingScheme()) && getRequestingPort() == FOURTYTWO) {
|
||||
return new PasswordAuthentication(MAGIC, ("" + FOURTYTWO).toCharArray());
|
||||
}
|
||||
/*
|
||||
System.err.println("getPasswordAuthentication");
|
||||
System.err.println(getRequestingSite());
|
||||
System.err.println(getRequestingPort());
|
||||
System.err.println(getRequestingProtocol());
|
||||
System.err.println(getRequestingPrompt());
|
||||
System.err.println(getRequestingScheme());
|
||||
*/
|
||||
|
||||
// TODO:
|
||||
// Look for a more specific PasswordAuthenticatior before using
|
||||
// Default:
|
||||
//
|
||||
// if (...)
|
||||
// return pa.requestPasswordAuthentication(getRequestingSite(),
|
||||
// getRequestingPort(),
|
||||
// getRequestingProtocol(),
|
||||
// getRequestingPrompt(),
|
||||
// getRequestingScheme());
|
||||
|
||||
return passwordAuthentications.get(new AuthKey(getRequestingSite(),
|
||||
getRequestingPort(),
|
||||
getRequestingProtocol(),
|
||||
getRequestingPrompt(),
|
||||
getRequestingScheme()));
|
||||
}
|
||||
|
||||
/** Registers a PasswordAuthentication with a given URL address. */
|
||||
public PasswordAuthentication registerPasswordAuthentication(URL pURL, PasswordAuthentication pPA) {
|
||||
return registerPasswordAuthentication(NetUtil.createInetAddressFromURL(pURL),
|
||||
pURL.getPort(),
|
||||
pURL.getProtocol(),
|
||||
null, // Prompt/Realm
|
||||
BASIC,
|
||||
pPA);
|
||||
}
|
||||
|
||||
/** Registers a PasswordAuthentication with a given net address. */
|
||||
public PasswordAuthentication registerPasswordAuthentication(InetAddress pAddress, int pPort, String pProtocol, String pPrompt, String pScheme, PasswordAuthentication pPA) {
|
||||
/*
|
||||
System.err.println("registerPasswordAuthentication");
|
||||
System.err.println(pAddress);
|
||||
System.err.println(pPort);
|
||||
System.err.println(pProtocol);
|
||||
System.err.println(pPrompt);
|
||||
System.err.println(pScheme);
|
||||
*/
|
||||
|
||||
return passwordAuthentications.put(new AuthKey(pAddress, pPort, pProtocol, pPrompt, pScheme), pPA);
|
||||
}
|
||||
|
||||
/** Unregisters a PasswordAuthentication with a given URL address. */
|
||||
public PasswordAuthentication unregisterPasswordAuthentication(URL pURL) {
|
||||
return unregisterPasswordAuthentication(NetUtil.createInetAddressFromURL(pURL), pURL.getPort(), pURL.getProtocol(), null, BASIC);
|
||||
}
|
||||
|
||||
/** Unregisters a PasswordAuthentication with a given net address. */
|
||||
public PasswordAuthentication unregisterPasswordAuthentication(InetAddress pAddress, int pPort, String pProtocol, String pPrompt, String pScheme) {
|
||||
return passwordAuthentications.remove(new AuthKey(pAddress, pPort, pProtocol, pPrompt, pScheme));
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Registers a PasswordAuthenticator that can answer authentication
|
||||
* requests.
|
||||
*
|
||||
* @see PasswordAuthenticator
|
||||
*/
|
||||
public void registerPasswordAuthenticator(PasswordAuthenticator pPA, AuthenticatorFilter pFilter) {
|
||||
authenticators.put(pPA, pFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Unregisters a PasswordAuthenticator that can answer authentication
|
||||
* requests.
|
||||
*
|
||||
* @see PasswordAuthenticator
|
||||
*/
|
||||
public void unregisterPasswordAuthenticator(PasswordAuthenticator pPA) {
|
||||
authenticators.remove(pPA);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility class, used for caching the PasswordAuthentication objects.
|
||||
* Everything but address may be null
|
||||
*/
|
||||
class AuthKey {
|
||||
// TODO: Move this class to sandbox?
|
||||
|
||||
InetAddress address = null;
|
||||
int port = -1;
|
||||
String protocol = null;
|
||||
String prompt = null;
|
||||
String scheme = null;
|
||||
|
||||
AuthKey(InetAddress pAddress, int pPort, String pProtocol, String pPrompt, String pScheme) {
|
||||
Validate.notNull(pAddress, "address");
|
||||
|
||||
address = pAddress;
|
||||
port = pPort;
|
||||
protocol = pProtocol;
|
||||
prompt = pPrompt;
|
||||
scheme = pScheme;
|
||||
|
||||
// System.out.println("Created: " + this);
|
||||
}
|
||||
|
||||
/** Creates a string representation of this object. */
|
||||
|
||||
public String toString() {
|
||||
return "AuthKey[" + address + ":" + port + "/" + protocol + " \"" + prompt + "\" (" + scheme + ")]";
|
||||
}
|
||||
|
||||
public boolean equals(Object pObj) {
|
||||
return (pObj instanceof AuthKey && equals((AuthKey) pObj));
|
||||
}
|
||||
|
||||
// Ahem.. Breaks the rule from Object.equals(Object):
|
||||
// It is transitive: for any reference values x, y, and z, if x.equals(y)
|
||||
// returns true and y.equals(z) returns true, then x.equals(z)
|
||||
// should return true.
|
||||
|
||||
public boolean equals(AuthKey pKey) {
|
||||
// Maybe allow nulls, and still be equal?
|
||||
return (address.equals(pKey.address)
|
||||
&& (port == -1
|
||||
|| pKey.port == -1
|
||||
|| port == pKey.port)
|
||||
&& (protocol == null
|
||||
|| pKey.protocol == null
|
||||
|| protocol.equals(pKey.protocol))
|
||||
&& (prompt == null
|
||||
|| pKey.prompt == null
|
||||
|| prompt.equals(pKey.prompt))
|
||||
&& (scheme == null
|
||||
|| pKey.scheme == null
|
||||
|| scheme.equalsIgnoreCase(pKey.scheme)));
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
// There won't be too many pr address, will it? ;-)
|
||||
return address.hashCode();
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,126 @@
|
||||
package com.twelvemonkeys.io;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* StringInputStreamTest
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: StringInputStreamTest.java,v 1.0 03.09.13 10:40 haraldk Exp$
|
||||
*/
|
||||
public class StringInputStreamTest {
|
||||
|
||||
static final Charset UTF8 = Charset.forName("UTF-8");
|
||||
static final String LONG_STRING = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse id est lobortis, elementum nisi id, mollis urna. Morbi lorem nulla, vehicula ut ultricies ut, blandit sit amet metus. Praesent ut urna et arcu commodo tempus. Aenean dapibus commodo ligula, non vehicula leo dictum a. Aenean at leo ut eros hendrerit pellentesque. Phasellus sagittis arcu non faucibus faucibus. Sed volutpat vulputate metus sed consequat. Aenean auctor sapien sit amet erat dictum laoreet. Nullam libero felis, rutrum scelerisque elit eu, porta mollis nisi. Vestibulum vel ultricies turpis, vel dignissim arcu.\n" +
|
||||
"Ut convallis erat et dapibus feugiat. Pellentesque eu dictum ligula, et interdum nibh. Sed rutrum justo a leo faucibus eleifend. Proin est justo, porttitor vel nulla egestas, faucibus scelerisque lacus. Vivamus sit amet gravida nibh. Praesent odio diam, ornare vitae mi nec, pretium ultrices tellus. Pellentesque vitae felis consequat mauris lacinia condimentum in ut nibh. In odio quam, laoreet luctus velit vel, suscipit mollis leo. Etiam justo nulla, posuere et massa non, pretium vehicula diam. Sed porta molestie mauris quis condimentum. Sed quis gravida ipsum, eget porttitor felis. Vivamus volutpat velit vitae dolor convallis, nec malesuada est porttitor. Proin sed purus vel leo pretium suscipit. Morbi ut nibh quis tortor vehicula porttitor non sit amet lorem. Proin tempor vel sem sit amet accumsan.\n" +
|
||||
"Cras vulputate orci a lorem luctus, vel egestas leo porttitor. Duis venenatis odio et mauris molestie rutrum. Mauris gravida volutpat odio at consequat. Mauris eros purus, bibendum in vulputate vitae, laoreet quis libero. Quisque lacinia, neque sed semper fringilla, elit dolor sagittis est, nec tincidunt ipsum risus ut sem. Maecenas consectetur aliquam augue. Etiam neque mi, euismod eget metus quis, molestie lacinia odio. Sed eget sollicitudin metus. Phasellus facilisis augue et sem facilisis, consequat mollis augue ultricies.\n" +
|
||||
"Vivamus in porta massa. Sed eget lorem non lectus viverra pretium. Curabitur convallis posuere est vestibulum vulputate. Maecenas placerat risus ut dui hendrerit, sed suscipit magna tincidunt. Etiam ut mattis dolor, quis dictum velit. Donec ut dui sit amet libero convallis euismod. Phasellus dapibus dolor in nibh volutpat, eu scelerisque neque tempus. Maecenas a rhoncus velit. Etiam sollicitudin, leo non euismod vehicula, lectus risus aliquet metus, quis cursus purus orci non turpis. Nulla vel enim tortor. Quisque nec mi vulputate, convallis orci vel, suscipit nibh. Sed sed tellus id elit commodo laoreet ut euismod ligula. Mauris suscipit commodo interdum. Phasellus scelerisque arcu nec nibh porta, et semper massa rutrum. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.\n" +
|
||||
"Praesent cursus, sapien ut venenatis malesuada, turpis nulla venenatis velit, nec tristique leo turpis auctor purus. Curabitur non porta urna. Sed vitae felis massa. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Phasellus scelerisque id dolor nec fermentum. Etiam suscipit tincidunt odio, sed molestie elit fringilla in. Phasellus nec euismod lacus. Suspendisse bibendum vulputate viverra. Fusce mollis pharetra imperdiet. Phasellus tortor eros, rhoncus volutpat diam in, scelerisque viverra felis. Ut ornare urna commodo, pretium mauris eget, eleifend ipsum.";
|
||||
static final String SHORT_STRING = "Java";
|
||||
|
||||
@Test
|
||||
public void testReadShortString() throws IOException {
|
||||
StringInputStream stream = new StringInputStream(SHORT_STRING, UTF8);
|
||||
|
||||
byte[] value = SHORT_STRING.getBytes(UTF8);
|
||||
for (int i = 0; i < value.length; i++) {
|
||||
int read = stream.read();
|
||||
assertEquals(String.format("Wrong value at offset %s: '%s' != '%s'", i, String.valueOf((char) value[i]), String.valueOf((char) (byte) read)), value[i] &0xff, read);
|
||||
}
|
||||
|
||||
assertEquals(-1, stream.read());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadSubString() throws IOException {
|
||||
StringInputStream stream = new StringInputStream("foo bar xyzzy", 4, 3, UTF8);
|
||||
|
||||
byte[] value = "bar".getBytes(UTF8);
|
||||
for (int i = 0; i < value.length; i++) {
|
||||
int read = stream.read();
|
||||
assertEquals(String.format("Wrong value at offset %s: '%s' != '%s'", i, String.valueOf((char) value[i]), String.valueOf((char) (byte) read)), value[i] &0xff, read);
|
||||
}
|
||||
|
||||
assertEquals(-1, stream.read());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadNonAsciiString() throws IOException {
|
||||
String string = "\u00c6\u00d8\u00c5\u00e6\u00f8\u00e5\u00e1\u00e9\u00c0\u00c8\u00fc\u00dc\u00df";
|
||||
StringInputStream stream = new StringInputStream(string, UTF8);
|
||||
|
||||
byte[] value = string.getBytes(UTF8);
|
||||
for (int i = 0; i < value.length; i++) {
|
||||
int read = stream.read();
|
||||
assertEquals(String.format("Wrong value at offset %s: '%s' != '%s'", i, String.valueOf((char) value[i]), String.valueOf((char) (byte) read)), value[i] &0xff, read);
|
||||
}
|
||||
|
||||
assertEquals(-1, stream.read());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadLongString() throws IOException {
|
||||
StringInputStream stream = new StringInputStream(LONG_STRING, UTF8);
|
||||
|
||||
byte[] value = LONG_STRING.getBytes(UTF8);
|
||||
for (int i = 0; i < value.length; i++) {
|
||||
int read = stream.read();
|
||||
assertEquals(String.format("Wrong value at offset %s: '%s' != '%s'", i, String.valueOf((char) value[i]), String.valueOf((char) (byte) read)), value[i] &0xff, read);
|
||||
}
|
||||
|
||||
assertEquals(-1, stream.read());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadArrayLongString() throws IOException {
|
||||
StringInputStream stream = new StringInputStream(LONG_STRING, UTF8);
|
||||
|
||||
byte[] value = LONG_STRING.getBytes(UTF8);
|
||||
byte[] buffer = new byte[17];
|
||||
int count;
|
||||
for (int i = 0; i < value.length; i += count) {
|
||||
count = stream.read(buffer);
|
||||
assertArrayEquals(String.format("Wrong value at offset %s", i), Arrays.copyOfRange(value, i, i + count), Arrays.copyOfRange(buffer, 0, count));
|
||||
}
|
||||
|
||||
assertEquals(-1, stream.read());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadArraySkipLongString() throws IOException {
|
||||
StringInputStream stream = new StringInputStream(LONG_STRING, UTF8);
|
||||
|
||||
byte[] value = LONG_STRING.getBytes(UTF8);
|
||||
byte[] buffer = new byte[17];
|
||||
int count;
|
||||
for (int i = 0; i < value.length; i += count) {
|
||||
if (i % 2 == 0) {
|
||||
count = (int) stream.skip(buffer.length);
|
||||
}
|
||||
else {
|
||||
count = stream.read(buffer);
|
||||
assertArrayEquals(String.format("Wrong value at offset %s", i), Arrays.copyOfRange(value, i, i + count), Arrays.copyOfRange(buffer, 0, count));
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(-1, stream.read());
|
||||
}
|
||||
|
||||
/*@Test
|
||||
public */void testPerformance() throws IOException {
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
StringInputStream stream = new StringInputStream(LONG_STRING, UTF8);
|
||||
while(stream.read() != -1) {
|
||||
stream.available();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -40,7 +40,7 @@
|
||||
<packaging>jar</packaging>
|
||||
<name>TwelveMonkeys :: Sandbox :: ImageIO</name>
|
||||
<description>
|
||||
The TwelveMonkeys ImageIO Sandbox. Experimental stuff. Old retired stuff.
|
||||
The TwelveMonkeys ImageIO Sandbox. New experimental stuff. Old retired stuff.
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
@@ -62,6 +62,12 @@
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.sandbox</groupId>
|
||||
<artifactId>sandbox-common</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common-io</artifactId>
|
||||
|
@@ -0,0 +1,65 @@
|
||||
package com.twelvemonkeys.imageio.stream;
|
||||
|
||||
import com.twelvemonkeys.io.StringInputStream;
|
||||
import com.twelvemonkeys.io.enc.Base64Decoder;
|
||||
import com.twelvemonkeys.io.enc.DecoderStream;
|
||||
|
||||
import javax.imageio.spi.ImageInputStreamSpi;
|
||||
import javax.imageio.stream.FileCacheImageInputStream;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import javax.imageio.stream.MemoryCacheImageInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Base64DataURLImageInputStreamSpi
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: Base64DataURLImageInputStreamSpi.java,v 1.0 03.09.13 09:35 haraldk Exp$
|
||||
*/
|
||||
public class Base64DataURLImageInputStreamSpi extends ImageInputStreamSpi {
|
||||
// This is generally a bad idea, because:
|
||||
// - It is bound to String.class, and not all strings are base64 encoded data URLs.
|
||||
// - It's better to just create a decoder stream from the base64 stream, and use what's already in ImageIO....
|
||||
|
||||
public Base64DataURLImageInputStreamSpi() {
|
||||
super("TwelveMonkeys", "0.1-BETA", String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageInputStream createInputStreamInstance(final Object input, final boolean useCache, final File cacheDir) throws IOException {
|
||||
String string = (String) input;
|
||||
|
||||
InputStream stream = createStreamFromBase64(string);
|
||||
|
||||
return useCache && cacheDir != null ? new FileCacheImageInputStream(stream, cacheDir) : new MemoryCacheImageInputStream(stream);
|
||||
}
|
||||
|
||||
private InputStream createStreamFromBase64(String string) {
|
||||
if (!string.startsWith("data:")) {
|
||||
throw new IllegalArgumentException(String.format("Not a data URL: %s", string));
|
||||
}
|
||||
|
||||
int index = string.indexOf(';');
|
||||
if (index < 0 || !string.regionMatches(index + 1, "base64,", 0, "base64,".length())) {
|
||||
throw new IllegalArgumentException(String.format("Not base64 encoded: %s", string));
|
||||
}
|
||||
|
||||
int offset = index + "base64,".length() + 1;
|
||||
return new DecoderStream(new StringInputStream(string.substring(offset), Charset.forName("UTF-8")), new Base64Decoder());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUseCacheFile() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription(Locale locale) {
|
||||
return "Service provider that instantiates a FileCacheImageInputStream or MemoryCacheImageInputStream from a Base64 encoded data string";
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user