Patchou's Cabana

The personal blog of Patchou

Eorzea’s Guide released for BlackBerry

After months of working on it during my free time, my new pet project is finally released, approved and available on BlackBerry App World! This new app has been designed exclusively for Final Fantasy 14 gamers. Use it to get help on more than a thousand official synthesis recipes available in game or to keep in touch with Eorzea’s news and world information while away from your computer.

More information about the features offered by Eorzea’s Guide can be found here on this site. If you own a BlackBerry and play Final Fantasy XIV, just search for “Eorzea” in your app store and give it a try. It’s entirely free :).

Resizing transparent bitmaps with the BlackBerry JDE

This post was originally made on BlackBerry’s Java Development forum. See the original post here. I updated the code since then, the latest version can be found below.

Here’s the little story behind this code: during the development of Eorzea’s Guide, I tried to use Bitmap.scaleInto() to resize transparent bitmaps in my application. Although this function is a nice addition to JDE 5, it tends to produce bad-looking results on transparent bitmaps such as PNG24 files. Forum posts I found on the web for this problem talk about using Bitmap.createAlpha() which does restore transparency but still produces artifacts in the final bitmap such as white edges and wicked pixel colors.

To solve this without the use of an external library, I created the following function. It still uses scaleInto() but in a different manner. I added some comments in the function and created a screenshot showing before and after results. I’m posting the result here in hope it will help other people searching to achieve the same thing. The code was tested in JDE 5 and JDE 6 and the sample pictures were created using different combinations of filter types and aspect ratios.

package com.patchou.ui;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.Color;
import net.rim.device.api.ui.Graphics;
/**
 *
 * @author    Patchou
 * @version   1.01
 *
 */
public class GPATools
{
    /**
     * Resizes a bitmap with an alpha channel (transparency) without the artifacts introduced
     *   by <code>scaleInto()</code>.
     *
     * @param bmpSrc        Source Bitmap
     * @param nWidth        New Width
     * @param nHeight       New Height
     * @param nFilterType   Filter quality to use. Can be <code>Bitmap.FILTER_LANCZOS</code>,
     *                           <code>Bitmap.FILTER_BILINEAR</code> or
     *                           <code>Bitmap.FILTER_BOX</code>.
     * @param nAspectRatio  Specifies how the picture is resized. Can be
     *                           <code>Bitmap.SCALE_TO_FIT</code>,
     *                           <code>Bitmap.SCALE_TO_FILL</code> or
     *                           <code>Bitmap.SCALE_STRETCH</code>.
     * @return              The resized Bitmap in a new object.
     */
    public static Bitmap ResizeTransparentBitmap(Bitmap bmpSrc, int nWidth, int nHeight, int nFilterType, int nAspectRatio)
    {
        if(bmpsrc== null)
            return null;

        //Get the original dimensions of the bitmap
        int nOriginWidth = bmpSrc.getWidth();
        int nOriginHeight = bmpSrc.getHeight();
        if(nWidth == nOriginWidth && nHeight == nOriginHeight)
            return bmpSrc;

        //Prepare a drawing bitmap and graphic object
        Bitmap bmpOrigin = new Bitmap(nOriginWidth, nOriginHeight);
        Graphics graph = Graphics.create(bmpOrigin);

        //Create a line of transparent pixels for later use
        int[] aEmptyLine = new int[nWidth];
        for(int x = 0; x < nWidth; x++)
            aEmptyLine[x] = 0x00000000;
        //Create two scaled bitmaps
        Bitmap[] bmpScaled = new Bitmap[2];
        for(int i = 0; i < 2; i++)
        {
            //Draw the bitmap on a white background first, then on a black background
            graph.setColor((i == 0) ? Color.WHITE : Color.BLACK);
            graph.fillRect(0, 0, nOriginWidth, nOriginHeight);
            graph.drawBitmap(0, 0, nOriginWidth, nOriginHeight, bmpSrc, 0, 0);

            //Create a new bitmap with the desired size
            bmpScaled[i] = new Bitmap(nWidth, nHeight);
            if(nAspectRatio == Bitmap.SCALE_TO_FIT)
            {
                //Set the alpha channel of all pixels to 0 to ensure transparency is
                //applied around the picture, if needed by the transformation
                for(int y = 0; y < nHeight; y++)
                    bmpScaled[i].setARGB(aEmptyLine, 0, nWidth, 0, y, nWidth, 1);
            }

            //Scale the bitmap
            bmpOrigin.scaleInto(bmpScaled[i], nFilterType, nAspectRatio);
        }

        //Prepare objects for final iteration
        Bitmap bmpFinal = bmpScaled[0];
        int[][] aPixelLine = new int[2][nWidth];

        //Iterate every line of the two scaled bitmaps
        for(int y = 0; y < nHeight; y++)
        {
            bmpScaled[0].getARGB(aPixelLine[0], 0, nWidth, 0, y, nWidth, 1);
            bmpScaled[1].getARGB(aPixelLine[1], 0, nWidth, 0, y, nWidth, 1);

            //Check every pixel one by one
            for(int x = 0; x < nWidth; x++)
            {
                //If the pixel was untouched (alpha channel still at 0), keep it transparent
                if(((aPixelLine[0][x] >> 24) & 0xff) == 0)
                    aPixelLine[0][x] = 0x00000000;
                else
                {
                    //Compute the alpha value based on the difference of intensity
                    //in the red channel
                    int nAlpha = ((aPixelLine[1][x] >> 16) & 0xff) -
                                    ((aPixelLine[0][x] >> 16) & 0xff) + 255;
                    if(nAlpha == 0)
                        aPixelLine[0][x] = 0x00000000; //Completely transparent
                    else if(nAlpha >= 255)
                        aPixelLine[0][x] |= 0xff000000; //Completely opaque
                    else
                    {
                        //Compute the value of the each channel one by one
                        int nRed = ((aPixelLine[0][x] >> 16 ) & 0xff);
                        int nGreen = ((aPixelLine[0][x] >> 8 ) & 0xff);
                        int nBlue = (aPixelLine[0][x] & 0xff);

                        nRed = (int)(255 + (255.0 * ((double)(nRed-255)/(double)nAlpha)));
                        nGreen = (int)(255 + (255.0 * ((double)(nGreen-255)/(double)nAlpha)));
                        nBlue = (int)(255 + (255.0 * ((double)(nBlue-255)/(double)nAlpha)));

                        if(nRed < 0) nRed = 0;
                        if(nGreen < 0) nGreen = 0;
                        if(nBlue < 0) nBlue = 0;
                        aPixelLine[0][x] = nBlue | (nGreen<<8) | (nRed<<16) | (nAlpha<<24);
                    }
                }
            }

            //Change the pixels of this line to their final value
            bmpFinal.setARGB(aPixelLine[0], 0, nWidth, 0, y, nWidth, 1);
        }
        return bmpFinal;
    }
} 

Here’s an example of how to call the function:

Bitmap bmp = Bitmap.getBitmapResource("picture.png");
Bitmap bmpResized = GPATools.ResizeTransparentBitmap(bmp, 30, 60,
    Bitmap.FILTER_LANCZOS, Bitmap.SCALE_TO_FIT);

Here’s the result:

Eorzea’s Guide for Adventurers


The first full featured app for a Final Fantasy game is now available on Blackberry!

Eorzea’s Guide is an app for Final Fantasy XIV players and adventurers. Like so many other apps available nowadays, this program does not intend to blow your brain out. Instead, Eorzea’s Guide intends to make itself useful while you’re playing, and while you’re away from your computer. The application has both online and offline features: for example, you can use it as a recipe book when playing the game and read the latest Final Fantasy news when you’re in the subway.

Eorzea’s Guide is entirely free to use and redistribute, made by a Final Fantasy fan, for Final Fantasy fans. After all, it’s not everyday you get the chance to contribute in one of the things you like the most. The idea to create this program came to me in September 2010, when I received my copy of FF14. I was already searching for a reason to start developing on mobiles and this game gave me the perfect excuse when I realized I had no way to access my recipes while in-game. It took more time than I had expected to complete the first public version of the app (I had another job to do after all…) but I’ve finally managed to put the finishing touches on it and send it to the BlackBerry store.

Eorzea’s Guide is compatible with any BlackBerry device running OS versions 5, 6 and 7  (Curve, Bold, Style, Pearl, Torch, Tour, Storm, …). Both touch-screen and non-touch-screen devices are supported and the application adapts its layout to landscape and portrait orientations (when you tilt your BlackBerry). No other phone is supported at the moment but I am planning to work on an Android version depending on the feedback I get. Current languages supported are English, French, and German with work in progress for Japanese (translator needed!).

This app consist in 3 main sections: News, Synthesis and World Status.

News Section

The News section requires a data connection and displays the latest information posted by Square Enix on The Lodestone web site. News from all 6 available categories are displayed: Topics, Important Notices, Server Maintenance, General, Updates, and Status Changes. If you’re not interested in seeing all of those, you can filter the list to include only your chosen categories and/or only news articles which title contains a specific word.


Every article is processed server side and a custom look, derived from the original style displayed on The Lodestone, is used for better viewing on a mobile phone.

Every picture is compressed and resized when needed for optimal speed, visibility, and bandwidth management.

The actual content of each news post is downloaded only once, when first accessed, and stored in a temporary directory on your phone for faster future access.

Synthesis Section

The Synthesis section does not require any external connection and only uses local resources available on your phone. This is why the initial download of the Eorzea’s Guide application is larger than many other apps: more than a thousand different pictures are stored in its resources for all the recipe materials displayed in this section. Final Fantasy XIV recipes can be displayed by craft, or all at once if preferred. One interesting feature of Eorzea’s Guide is the different ways you can search for specific recipes and materials matching your needs.


More than 2,100 official recipes are currently available, with more added regularly with each update.

Filter recipes by name or by specifying material you have in your possession to easily find synthesis you can do.

Each recipe comes packed with every possible detail, from classification to required skills, facilities and training.

Materials are all linked to each other. You can go from Canvas Chest Guard, to Iron Buckle to Iron Square to Iron Nugget in no time to complete the synthesis you’re really interested in.

Similar recipes are grouped together to improve navigation. Each variant can be displayed in the recipe’s details.

World Status Section

Information regarding Eorzea and its servers can also be found in the app.


The current time, date and year in the world are displayed in real time.

The proper moon calendar is shown along with the date.

The status of each individual game server is displayed, with speed of response (ping).

Get it now, it’s free!

Software development is a passion of mine. Eorzea’s Guide is my current pet project and it is available entirely free of charge on BlackBerry, in every country and on all carriers. Just search for “Eorzea” in your app store and give it a try :-). Feedback and comments are always welcomed.

Blackberry, iPhone and Android

Just saw this on Crackberry:

Users of smartphones

Resizing transparent bitmaps with the BlackBerry JDE

Here’s a post I made yesterday on the BlackBerry’s Java Development forum. See the original post here. I updated the code since then, the latest version can be found below.

I recently tried to use Bitmap.scaleInto() to resize transparent bitmaps in my application. Although this function is a nice addition to JDE 5, it tends to produce bad-looking results on transparent bitmaps such as PNG24 files. Forum posts I found on the web for this problem talk about using Bitmap.createAlpha() which does restore transparency but still produces artifacts in the final bitmap such as white edges and wicked pixel colors.

To solve this without the use of an external library, I created the following function. It still uses scaleInto() but in a different manner. I added some comments in the function and created a screenshot showing before and after results (don’t mind the pictures, they’re part of the project I’m currently working on). I’m posting the result here in hope it will help other people searching to achieve the same thing. The code was tested in JDE 5 and JDE 6 and the sample pictures were created using different combinations of filter types and aspect ratios.

package com.patchou.ui;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.Color;
import net.rim.device.api.ui.Graphics;
/**
 *
 * @author    Patchou
 * @version   1.01
 *
 */
public class GPATools
{
    /**
     * Resizes a bitmap with an alpha channel (transparency) without the artifacts introduced
     *   by <code>scaleInto()</code>.
     *
     * @param bmpSrc        Source Bitmap
     * @param nWidth        New Width
     * @param nHeight       New Height
     * @param nFilterType   Filter quality to use. Can be <code>Bitmap.FILTER_LANCZOS</code>,
     *                           <code>Bitmap.FILTER_BILINEAR</code> or
     *                           <code>Bitmap.FILTER_BOX</code>.
     * @param nAspectRatio  Specifies how the picture is resized. Can be
     *                           <code>Bitmap.SCALE_TO_FIT</code>,
     *                           <code>Bitmap.SCALE_TO_FILL</code> or
     *                           <code>Bitmap.SCALE_STRETCH</code>.
     * @return              The resized Bitmap in a new object.
     */
    public static Bitmap ResizeTransparentBitmap(Bitmap bmpSrc, int nWidth, int nHeight, int nFilterType, int nAspectRatio)
    {
        if(bmpsrc== null)
            return null;

        //Get the original dimensions of the bitmap
        int nOriginWidth = bmpSrc.getWidth();
        int nOriginHeight = bmpSrc.getHeight();
        if(nWidth == nOriginWidth && nHeight == nOriginHeight)
            return bmpSrc;

        //Prepare a drawing bitmap and graphic object
        Bitmap bmpOrigin = new Bitmap(nOriginWidth, nOriginHeight);
        Graphics graph = Graphics.create(bmpOrigin);

        //Create a line of transparent pixels for later use
        int[] aEmptyLine = new int[nWidth];
        for(int x = 0; x < nWidth; x++)
            aEmptyLine[x] = 0x00000000;
        //Create two scaled bitmaps
        Bitmap[] bmpScaled = new Bitmap[2];
        for(int i = 0; i < 2; i++)
        {
            //Draw the bitmap on a white background first, then on a black background
            graph.setColor((i == 0) ? Color.WHITE : Color.BLACK);
            graph.fillRect(0, 0, nOriginWidth, nOriginHeight);
            graph.drawBitmap(0, 0, nOriginWidth, nOriginHeight, bmpSrc, 0, 0);

            //Create a new bitmap with the desired size
            bmpScaled[i] = new Bitmap(nWidth, nHeight);
            if(nAspectRatio == Bitmap.SCALE_TO_FIT)
            {
                //Set the alpha channel of all pixels to 0 to ensure transparency is
                //applied around the picture, if needed by the transformation
                for(int y = 0; y < nHeight; y++)
                    bmpScaled[i].setARGB(aEmptyLine, 0, nWidth, 0, y, nWidth, 1);
            }

            //Scale the bitmap
            bmpOrigin.scaleInto(bmpScaled[i], nFilterType, nAspectRatio);
        }

        //Prepare objects for final iteration
        Bitmap bmpFinal = bmpScaled[0];
        int[][] aPixelLine = new int[2][nWidth];

        //Iterate every line of the two scaled bitmaps
        for(int y = 0; y < nHeight; y++)
        {
            bmpScaled[0].getARGB(aPixelLine[0], 0, nWidth, 0, y, nWidth, 1);
            bmpScaled[1].getARGB(aPixelLine[1], 0, nWidth, 0, y, nWidth, 1);

            //Check every pixel one by one
            for(int x = 0; x < nWidth; x++)
            {
                //If the pixel was untouched (alpha channel still at 0), keep it transparent
                if(((aPixelLine[0][x] >> 24) & 0xff) == 0)
                    aPixelLine[0][x] = 0x00000000;
                else
                {
                    //Compute the alpha value based on the difference of intensity
                    //in the red channel
                    int nAlpha = ((aPixelLine[1][x] >> 16) & 0xff) -
                                    ((aPixelLine[0][x] >> 16) & 0xff) + 255;
                    if(nAlpha == 0)
                        aPixelLine[0][x] = 0x00000000; //Completely transparent
                    else if(nAlpha >= 255)
                        aPixelLine[0][x] |= 0xff000000; //Completely opaque
                    else
                    {
                        //Compute the value of the each channel one by one
                        int nRed = ((aPixelLine[0][x] >> 16 ) & 0xff);
                        int nGreen = ((aPixelLine[0][x] >> 8 ) & 0xff);
                        int nBlue = (aPixelLine[0][x] & 0xff);

                        nRed = (int)(255 + (255.0 * ((double)(nRed-255)/(double)nAlpha)));
                        nGreen = (int)(255 + (255.0 * ((double)(nGreen-255)/(double)nAlpha)));
                        nBlue = (int)(255 + (255.0 * ((double)(nBlue-255)/(double)nAlpha)));

                        if(nRed < 0) nRed = 0;
                        if(nGreen < 0) nGreen = 0;
                        if(nBlue < 0) nBlue = 0;
                        aPixelLine[0][x] = nBlue | (nGreen<<8) | (nRed<<16) | (nAlpha<<24);
                    }
                }
            }

            //Change the pixels of this line to their final value
            bmpFinal.setARGB(aPixelLine[0], 0, nWidth, 0, y, nWidth, 1);
        }
        return bmpFinal;
    }
} 

Here’s an example of how to call the function:

Bitmap bmp = Bitmap.getBitmapResource("picture.png");
Bitmap bmpResized = GPATools.ResizeTransparentBitmap(bmp, 30, 60,
    Bitmap.FILTER_LANCZOS, Bitmap.SCALE_TO_FIT);

Here’s the result:

  • Archive

  • Categories

  • Blogroll