Categories
Java

Reading JPEGs with CMYK profile

Today I tried to read a JPEG with the ImageIO-Library, provided by the JRE. But instead of a wonderful image I only received the following exception:

1
2
3
4
5
6
7
8
java.lang.IllegalArgumentException: bandOffsets.length is wrong!
	at javax.imageio.ImageTypeSpecifier$Interleaved.< init >(ImageTypeSpecifier.java:382)
	at javax.imageio.ImageTypeSpecifier.createInterleaved(ImageTypeSpecifier.java:495)
	at com.sun.imageio.plugins.jpeg.JPEGImageReader.getImageTypes(JPEGImageReader.java:743)
	at com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(JPEGImageReader.java:935)
	at com.sun.imageio.plugins.jpeg.JPEGImageReader.read(JPEGImageReader.java:912)
	at javax.imageio.ImageIO.read(ImageIO.java:1400)
	at javax.imageio.ImageIO.read(ImageIO.java:1322)

With an EXIF-Reader (by the way a nice website) I tried to analyze the picture and saw the picture includes an embedded color profile “(unrecognized embedded color profile ‘SWOP (Coated), 20%’)”. A little bit more research showed the currently unresolved bugs in the JRE (especially ImageIO-Library; #4799903 and #5100094). So I’m not the only person, who had the problem. There are some code snippets and bug workarounds on the net trying to convert CMYK or YCCK to RGB. For my picture the CMYK-Solution doesn’t work, because the JRE means the embedded ICC profile doesn’t match the given raster (raster contains 3 bytes per pixel, but CMYK 4 bytes). But Werner Randelshofer wrote that it is important to use the given ICC, because of unexpectable color problems. So just to use a fix conversion method is not the wanted solution.

Then I tried first not to use the ImageIO library, but to give AWT-Toolkit a try. I was very surprised, that this function can correctly read the given image. So I didn’t need to handle the embedded ICC profiles directly. I modified my code to use this method, if ImageIO fails. The resulting code looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
    private BufferedImage readImage(InputStream picture) throws IOException {
        ByteArrayOutputStream buf = new ByteArrayOutputStream();
        byte[] b = new byte[10240];
        int l = 0;
        while ((l = picture.read(b)) >= 0) {
            buf.write(b, 0, l);
        }
        buf.close();
        byte[] picturedata = buf.toByteArray();
        buf = null;
        try {
            return ImageIO.read(new ByteArrayInputStream(picturedata));
        } catch (IllegalArgumentException e) {
                ImageInputStream input = ImageIO
                        .createImageInputStream(new ByteArrayInputStream(
                                picturedata));
                Iterator< ImageReader > readers = ImageIO.getImageReaders(input);
                ImageReader reader = null;
                while (readers.hasNext()) {
                    reader = (ImageReader) readers.next();
                    if (reader.canReadRaster())
                        break;
                }
 
                if (reader == null)
                    throw new IOException("no reader found");
                // Set the input.
                reader.setInput(input);
                int w = reader.getWidth(0);
                int h = reader.getHeight(0);
                BufferedImage image;
                image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
                Image intImage = Toolkit.getDefaultToolkit().createImage(
                        picturedata);
                new ImageIcon(intImage);
                Graphics2D g = image.createGraphics();
                g.drawImage(intImage, 0, 0, null);
                g.dispose();
                return image;
        }
    }

The Toolkit-Method also has no problems on servers without an X11 server.

Categories
Eclipse

Eclipse 3.4 (Gallileo) – NoClassDefFoundError

I recently updated my Eclipse from a beta of 3.4 to the latest Gallileo version using Yoxos OnDemand service.

After that I received always the following error, if I started a application or unit test case from eclipse:

1
Exception in thread "main" java.lang.NoClassDefFoundError: info/javahelp/TestClass

The solution for me was to reset the used JRE in the Build Path (Project Properties -> Java Build Path).

Project properties

Here I changed from a System JRE from the underlying operation system Mac OS X to the used JRE Eclipse in running in.

Edit Library

After that a normal start of the application or test case was possible.

Categories
Maven

Running classes via maven from console

If you use maven to compile and handle your applications, you may want to directly call it from console. Here you can use the Maven-Exec-Plugin. This plugin provides an easy method to execute Java-Classes. Of course you can configure the plugin as usual in you pom.xml, but you also can directly use it from the console.

To run a simple class you can use:

1
mvn exec:java -Dexec.mainClass=info.javahelp.examples.Example

The advantage is that java is correctly called with all used jar-dependencies and the resulting classpath.

To affect the used dependencies you can also define the used scope (default: compile). For example your application is in testing scope you can run it with:

1
mvn exec:java -Dexec.mainClass=info.javahelp.examples.tests.Example -Dexec.classpathScope=test
Categories
Networking

Really caching web content

Today I tried to optimize a web application to speed up the usage. One big and low hanging fruit is the correct caching of static files like images, css- or javascript-files. There are two parts you can save with caching. And only the correct usage will really save time and bandwidth.

1. Caching content with live time revalidation

Every request of a http client consist of two parts; the request and the response. In the request defines the browser, which resource is needed. The response of the server then is the requested resource. One caching-strategy is to slim the response. So you will save bandwidth and on slow connections also time. To achieve this you have to use the ETag and / or Last-Modified header of the HTTP protocol.

Response

If the browser then needs the requested resource again, it will send the If-None-Match and / or If-Modified-Since request header. Then the server can decide, if the resource has changed or not. If not, it will send the 304 response result. But what if we know on the first request, that the content is safe for the next x minutes / days? In this case we could also save the request. Imaging you have 100 pictures on one site and have a ping-time of 100 ms to a server. It would take in sequential mode 10 seconds to check these URLs.

2. Caching content with expiration dates

To give your content a time range, where it is valid, you have to define an expiration date using the Expires header. Additional you should enable caching itself for a time range using the Cache-Control header. The Cache-Control header can have several values, which can be combined. Typically would be:

“public,max-age=1800,must-revalidate”

The last option defines, that the client have to re-request the server for the resource after the time “max-age”, if the resource is needed again. Unfortunately the Safari browser have a bug which results in ignoring the Expires and Cache-Control header under some circumstances. As Steve Clay wrote on his blog, the problem belongs to the definition of must-revalidate. So currently using must-revalidate is no good idea until the bug is resolved.

To easily find the resources with missing Expires headers, you can use YSlow, a Firefox plugin provided by Yahoo.

YSlow

Categories
Javascript

Calculating with dates in JavaScript

JavaScript provides a class “Date” to work with dates. In this short article I want to give some tips with date calculation.

1. Working with seconds

The easiest way, if you need to calculate with seconds, minutes or hours, is to use the provided methods getTime() or setTime(). Here you will get or you can set the microseconds since 1.1.1970. So if you want to add one hour, just add 3.600.000 microseconds:

?View Code JAVASCRIPT
1
2
var date = new Date();
date.setTime(date.getTime()+3600000);

2. Working with days

If you work with days, the way with getTime()/setTime() is not preferred, because you have to honour the summer / winter time. So calculating with days, months or years should be done using the provided methods getDate() / setDate(), getMonth() / setMonth() or getFullYear() / setFullYear(). These methods are fault tolerant, so you can set the 35. day of a month and the date is correctly converted to the given day in the next month.

?View Code JAVASCRIPT
1
2
var date = new Date(2009,1,25); //date is 2009-02-25
date.setDate(date.getDate()+5); //would change date to 2009-03-02
Categories
Java

Drawing aliased lines with Java

Java provides a very flexible API for drawing images. This API also support aliased drawing of lines, text, etc. To activate it, you have to set the RenderingHints of the Graphics-Object (line 3). After that all operations results in aliased objects. To draw half pixels, you can use g.scale or g.translate with double-values.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
        BufferedImage image = new BufferedImage(200,200,BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = image.createGraphics();
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g.setColor(Color.white);
        g.fillRect(0, 0, 199, 199);
        g.setColor(Color.black);
        double step = 2.5;
        g.scale(step, 1);
        for (int i = 0; i &lt; (int)(200/step); i++) {
            if (i % 2 == 1) {
                g.fillRect(0, 0, 1, 199);
            }
            g.translate(1, 0);
        }
        ImageIO.write(image, "png", new File("test.png"));
Categories
SEAM Tomcat

Restrict access to inner Facelets with SEAM

Sometimes you could have some facelets, which are no entry-sites and which should never be called directly by the user. Typical types are template-files.
Seam provides here an easy function to restrict the access to such pages. You can define this restriction in the pages.xml or the associated *.page.xml.
For the pages.xml you have to add:

1
2
3
4
5
6
7
8
< ?xml version="1.0" encoding="UTF-8"?>
<pages xmlns="http://jboss.com/products/seam/pages" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
...
	<page view-id="/templates/template.xhtml">
		<restrict />
	</page>
...
</pages>

Because you also can use wildcards, it is also possible to restrict a whole directory:

1
2
3
4
5
6
7
8
< ?xml version="1.0" encoding="UTF-8"?>
<pages xmlns="http://jboss.com/products/seam/pages" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
...
	<page view-id="/templates/*">
		<restrict />
	</page>
...
</pages>

Seam will now throw an exception, if a user will access this page, but instead we want to send the typical HTTP-error 403. So we have to define some more rules in pages.xml:

1
2
3
4
5
6
7
8
9
10
11
< ?xml version="1.0" encoding="UTF-8"?>
<pages xmlns="http://jboss.com/products/seam/pages" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
...
	<exception class="org.jboss.seam.security.NotLoggedInException">
		<http -error error-code="403" />
	</exception>
	<exception class="org.jboss.seam.security.AuthorizationException">
		<http -error error-code="403" />
	</exception>
...
</pages>

Another way would be an own Servlet or Servlet-Filter, which would send the errorcode directly.

Categories
Javascript SEAM XHTML

The XHTML and document.write / innerHTML story

If you use XHTML as HTML-Standard, which is recommended, to build your sites and you use JavaScript, you could have problems with document.write. Especially third-party JavaScript extensions like GoogleMaps or CKEditor use document.write to easily inject own JavaScript code.

But this is denied by specification for XHTML-Documents delivered with content-type application/xhtml+xml instead of text/html. You will receive the DOM Exception #7 by calling document.write or while using innerHTML (Example in Safari: “Error: NO_MODIFICATION_ALLOWED_ERR: DOM Exception 7”; in Firefox: uncaught exception: [Exception… “Component returned failure code: 0x80004003 (NS_ERROR_INVALID_POINTER) [nsIDOMNSHTMLElement.innerHTML]”  nsresult: “0x80004003 (NS_ERROR_INVALID_POINTER)”  location: … ]). The solution is to deliver the Website with content-type “text/html” instead of “application/xhtml+xml”.
Errormessage Safari
In SEAM using Facelets (with JSF) as View, you can set the content-type in the f:view-Tag. This would look like:

1
2
3
4
5
...
<f :view contentType="text/html">
....
</f>
...
Categories
SEAM Tomcat

Defining a ServletFilter – the SEAM way

SEAM doesn’t only extends JSF and Facelets, but also gives you a possibility to define other resources or components via annotations. To define a simple Servlet Filter you only need to annotate a class with the @Filter-annotation. There is no need to extend the web.xml or other.

One simple Filter would be:

1
2
3
4
5
6
7
8
9
10
@Scope(ScopeType.APPLICATION)
@Name("myFilter")
@Install(precedence = Install.FRAMEWORK)
@BypassInterceptors
@Filter(within = { "org.jboss.seam.web.rewriteFilter" })
public class MyFilter extends AbstractFilter {
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        chain.doFilter(request, response);
    }
}

With the parameters within or around of the @Filter annotation, you can define when you filter will be called.

Categories
JQuery

test if html element is visible with JQuery

If you use JQuery you can use the effects for dynamically hide and show html-elements, like boxes and so. But how to test if such a element is currently visible or not? JQuery offers here some selectors, named :hidden and :visible, which can be used. If you combine it with the “is” method, you can easily check the state.

?View Code JAVASCRIPT
1
2
3
alert($("p").is(":visible"));
$("p").hide();
alert($("p").is(":visible"));

This code would output “true”, “false” for a normal p-tag.