Applying page margins in EPUB with CSS

Apr 23rd, 2011 | Filed under EBooks, EPUB

Recently, pretty much all ebook readers adopted the @page CSS rule (including Adobe Digital Editions), making the proprietary Adobe Page Templates obsolete when trying to set margins.

Therefore, if you want to set a margin of 1.5em, all you need to do is use the following CSS rule:

@page {
    margin: 1.5em;
}

Calling C code from Java using JNA

Apr 22nd, 2011 | Filed under C, Java

I recently wrote an article about calling C code from Java using JNI. Another way to call C code from Java is to use Java Native Access, which makes things significantly easier.

First off, we’ll need to write the C library. Create a ctest.c file containing a simple helloFromC function:

/* ctest.c */
 
#include <stdio.h>
 
void helloFromC() {
    printf("Hello from C!\n");
}

Notice that this version is much simpler than the JNI version, and also not intrusive at all. Using JNA you can run code from any library without any of the additional boilerplate associated with JNI.

Now that we have the C source, let’s create a library:

gcc -o libctest.so -shared ctest.c

This is the standard way of creating a library, not specific to Java in any way. For details about creating the library on Mac or Windows, see the previously mentioned article.

Let’s now write the Java code in a HelloWorld.java file:

/* HelloWorld.java */
 
import com.sun.jna.Library;
import com.sun.jna.Native;
 
public class HelloWorld {
    public interface CTest extends Library {
        public void helloFromC();
    }
    static public void main(String argv[]) {
        CTest ctest = (CTest) Native.loadLibrary("ctest", CTest.class);
        ctest.helloFromC();
    }
}

After downloading the JNA package from the official Subversion repository an placing it in the same directory, we can now compile the Java application:

javac -classpath jna.jar HelloWorld.java

This should produce a HelloWorld.class file containing our compiled class. We can run it with:

java -classpath jna.jar:. HelloWorld

If everything works correctly, you should see:

Hello from C!

Importing photos from iPhone on Mac OS X

Apr 20th, 2011 | Filed under iPhone, Mac

To copy your photos from iPhone without synchronizing with iTunes:

  1. Open “Preview” (you can find it in the Applications folder)
  2. Choose File > Import from iPhone
  3. Choose the folder in the “Import To” dropdown
  4. Click “Import All” (or select the ones you wish to import and click “Import”)

Calling C code from Java using JNI

Apr 17th, 2011 | Filed under C, Java

In this tutorial we’ll be creating a Java application calling code from a native library. We’ll have a Java application called HelloWorld which will call the function helloFromC from a shared library named “ctest“, using Java Native Interface.

First off, we’ll create a file named HelloWorld.java to contain the HelloWorld class.

/* HelloWorld.java */
 
public class HelloWorld {
    native void helloFromC(); /* (1) */
    static {
        System.loadLibrary("ctest"); /* (2) */
    }
    static public void main(String argv[]) {
        HelloWorld helloWorld = new HelloWorld();
        helloWorld.helloFromC(); /* (3) */
    }
}
  1. Make the virtual machine aware of a function defined externally, named “helloFromC”
  2. Load an external library called “ctest” (which will need to define this function)
  3. Call the function we talked about

Even though we didn’t write any library yet, we can still compile the Java application, because this is a dependency that will be resolved at runtime. So, let’s compile the application:

javac HelloWorld.java

This will generate a HelloWorld.class file containing the application. Running the application will now result in an error, as we expect, because the library is not created yet:

java HelloWorld
Exception in thread "main" java.lang.UnsatisfiedLinkError: no ctest in java.library.path
    at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1754)
    at java.lang.Runtime.loadLibrary0(Runtime.java:823)
    at java.lang.System.loadLibrary(System.java:1045)
    at HelloWorld.(HelloWorld.java:6)

Alright, let’s now start writing the “ctest” library in C. To do that, we must first generate a header file from the .class file we created earlier. This header file will contain the definition of the function as it must be present in the C file.

javah HelloWorld

This command will generate a HelloWorld.h file in the same directory, containing the following code:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloWorld */
 
#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     HelloWorld
 * Method:    helloFromC
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_HelloWorld_helloFromC
  (JNIEnv *, jobject);
 
#ifdef __cplusplus
}
#endif
#endif

We’ll leave this file exactly as is, as the comment suggests, but we need to copy the function definition. Copy the definition and put it in a new file, named ctest.c:

/* ctest.c */
 
JNIEXPORT void JNICALL Java_HelloWorld_helloFromC
  (JNIEnv * env, jobject jobj)
{
}

Note that we gave names to the parameters. Now let’s implement the function. Aside from our own includes, we also need to include jni.h for this to work. So, modify the ctest.c file to contain something like:

/* ctest.c */
 
#include <jni.h>
#include <stdio.h>
 
JNIEXPORT void JNICALL Java_HelloWorld_helloFromC
  (JNIEnv * env, jobject jobj)
{
    printf("Hello from C!\n");
}

Now that we have the file, let’s compile it and create a native library. This part is system dependent, but the only things that change really are the extension of the generated library file and the path to the jni.h include.

gcc -o libctest.so -shared -I/path/to/jdk/headers ctest.c -lc

Replace “so” with “dylib” if you’re on a Mac, or “dll” if you’re on Windows (remove the “lib” from the file name as well if you’re on Windows). Also, replace “/path/to/jdk/headers” with the full path to the directory containing the file jni.h. If you don’t know where that is, you can use the locate jni.h command on UNIX-like systems.

Once you successfully run the above command, you will see a libctest.so file in the current directory (or libctest.dylib or libctest.dll). If you remember from the Java code you wrote earlier, the virtual machine will expect a library named “ctest” to reside in the current directory (point 2). By that, it means that a file with the name libctest.so should be here, which you just created.

To see this in action, run the application:

java HelloWorld

If everything works correctly, you should see:

Hello from C!