Tuesday, September 2, 2014

Android Image Cropping - Changing Template Instructions

A year ago I posted on my blog about my image cropping algorithm that developers can use freely for their own applications. During this time I have received many requests on changing template to their own custom templates, which many of them faced identical issues when modifying code to adapt to their custom templates. Therefore, in this post I will provide a step-by-step process on how to make the necessary changes when you plan to add your own custom templates.




Setting Up Project with your Templates

For this image crop algorithm to successfully work, you must provide templates with the background transparent and the lines clearly outlining your template. Make sure this template is saved as PNG, otherwise you won't have the transparent background that is required.
Once you have your templates in PNG files, you now need to place them into the correct project folders.
Looking at the screenshot above, I've placed my templates under res/drawable-nodpi. If you created your templates meant for any screen resolutions, then you can just place it under res/drawable-nodpi. Otherwise if you made different template sizes for different screen densities, then place them in their respective drawable folders.

Making the Proper Code Changes

The next process is to write code that will crop the images that you need.
Looking at the code snippet I have posted above.  The only code that you will need to modify are the arguments for invoking the static method ImageProcess.cropImage(). In the last two arguments, you must provide it with the width and height of your template. Passing in the incorrect argument can produce an error within the application.

That is pretty much it for making the proper modifications to add your own templates. If you have any questions and/or facing issues, feel free to comment below or create a Github issue.

Cheers!!

Link to my Github project: android-cropping-example.
Link to previous blog post: Android Image Cropping Example

Tuesday, April 22, 2014

Randomizer Refresh

Awhile back (like last year), I've released an app called Randomizer and then released the app source code open source on Github. Randomizer was my very first app released on the Google Play Store and was initially created using HTML5, CSS, JavaScript, JQuery, JQuery Mobile, and then packaged together with PhoneGap.

In short, Randomizer is an simple application to help people, who cannot decide on something from a list of choices. With this app users would input their list of choices, and then Randomizer would randomly select a selection from that list. Other features include randomizing the order of the given selection list, and selecting a number of a specified range of numbers.

In my initial post, I have described some of the issues regarding the user experience and the performance issues related to the application. At the time I thought this application never would have many downloads and it has been put aside for quite some time for improvements. Just two months ago, when I revisited this application, I've looked into the amount of downloads for this application and it turned out to be quite a decent number, at least 4000+ downloads. I was quite surprised with this number and thought why not improve it by overhauling the application. While the app download downloads statistics, I couldn't help but to also notice the comments left behind by the users. I noticed there were actually quite a bit of people looking for these types of applications, but the known issue regarding the user experience of Randomizer was the major let down for people wanting to use this app. Not only that, users were also helpful by providing some suggestions that should be implemented to make Randomizer better than before.

Being experienced with Android development than ever before, I started to go about overhauling the application by mimicking the exact UI layout and features. The only issue with this is that when users update their app, they will not be able to access their saved lists, which was previously stored on the HTML5's local storage. I believe that this will only be a minimal issue compared to the improved experience that they will be receiving. During this time, I've even taken advantage to implement a feature where users will be able to access their saved lists on multiple devices that has Randomizer install. This was accomplished by getting the user to create an account with an email and password, and their lists will be updated on our servers. On the server side, this accomplished by using nodeJS and PostgreSQL as our database. I must note that users are not forced to login and they can just skip the login process, but they will not be able to access their saved lists on multiple servers. If the users do happen to login, I suggest that they DO NOT store any valuable information like credit card numbers, social identity numbers, and so on.

In the meantime, I will continue to observe the progress of my Randomizer app and within the next two weeks I will bring an update with new and very important features.

Randomizer on Google Play Store HERE.
Randomizer source code HERE.

Friday, August 23, 2013

iPoo!!!

Last week, we've introduced iPoo. iPoo is a simple application that helps people find washrooms near their current location if they are in a dire need to go. Currently, we've only made this application available in Canada, while focusing our efforts on Toronto (city where we are currently located).

iPoo has proven to be a difficult launch for us with the main issue of not having any initial washroom data for our app. Initially we do not want users to download iPoo hoping that they will collaborate and input washrooms into our database. This idea wouldn't be wise and prevent the growth of our initial user base. Having initial washroom data, we are hoping that users would like this application and in turn spark a chain reaction where they would contribute by either reporting/rating existing washrooms and if they encounter a washroom not in our database then they would add into our database. In the end we must provide users with at least initial good quality listings of washrooms and in time they would contribute in some way to our application.

Right now, in our Toronto region, we have Starbucks, Second Cup, McDonalds, and Burger King as our main washroom locations. It also includes some non cafe/restaurant locations. This would seem like there would be a lot of washrooms listed in our Toronto region (which is true), but the problem we have with this is that not every single one of these cafe/restaurants have washrooms. So some of the places listed on there do not have washrooms and must be removed, which is the difficult part. Another issue we have in terms of usability is that in the downtown Toronto area, with the underground PATH walkway and financial/office buildings, it is proving difficult to find some of these locations as they can either be location in the PATH walkway, street level, or hidden within one of the office buildings. We would need find a solution to counteract this issue as it will pose problems to our users if they really need to go to the washroom.

Our washroom database also includes library and public park washrooms in Vancouver, library locations in both the city of Calgary and Edmonton.

So for now, with our focus in Toronto, we are hoping that we will further improve our iPoo usability, have more better quality washroom listings, and fix any known bugs with the application. We can only hope right now that people using this application to PLEASE contribute in some way to our application either by reporting, commenting/rating, and adding washrooms.

Download iPoo from Google Play Store!

Thanks!! =)

Friday, August 9, 2013

Android Gallery Intent Example

Android gallery intent is a simple way for users to select images for use in your application. It also makes the  mobile app developer's life easier by not having to implement a graphic user interface for users to use to import an image. There are two different intents that you can implement for users to select an image and import it into your application. You can view my gallery intent example source code in my android-api-example Github project.


Gallery Intent Using Default Gallery Application

If you want to start a gallery application that uses the device's default gallery app, you just need to call the Intent with MediaStore.Image.Media.EXTERNAL_CONTENT_URI and do Activity.startActivityForResult() instead of Activity.startActivity() on that intent. This way, you can retrieve the image path that the user has selected. Then in your overridden Activity.startActivityForResult() it just a matter of retrieving the path where the image is located. Now the tricky part is getting the file path. Tricky because the image file path isn't simply just store in the Intent data variable. Basically, the information returned will in a form of database query, thus a bit of code required to get that file path. Below is the code that I use to get the image file path (for now ignore the else if block of the code). And that is it, with that image file path decode into Bitmap and use it however you like!

Gallery Intent Using with Ability to Choose Gallery Application

Just automatically opening up the default gallery application does not give much choice for your users, hence I will describe how you can give users more flexibility when selecting images on the device. Simply when you create the intent, first specify what type of file you would like to import using MIME type and telling that you want to get some form of content using the constant Intent.ACTION_GET_CONTENT and then finally invoke Activity.startActivityForResult().
Similar to using gallery intent on default gallery app, in Activity.startActivityForResult() get the image file path using the provide code above. I have also mentioned above to ignore the else if block of code. This is where that block of code becomes useful. In the case where the user uses other apps (not the default gallery app), it will return the file path in the Intent data variable, thus it can get easily retrieved.
You can view my Android Camera Intent example HERE.
Relevant files are:
src/com/choiboi/apiexamples/gallery/GalleryMainActivity.java
res/layout/activity_gallery_main.xml

Enjoy!!

Thursday, August 8, 2013

Android Camera Intent Example

Need to incorporate camera into your application? You can follow this instruction HERE provided by Google on creating custom camera app. Or you can do it the easier way which is to start a camera intent. If all you need to do is to capture photos, and do not have the time and resources to create your own custom camera app, then using intent to start the device's camera app is the right way to go. Doing this provides users the ability adjust camera settings provided by the camera app without having you to go through all the trouble creating one from scratch. There are two ways to start a camera intent, which will be described below. In the meantime, if you are eager to look at the source code, it can be view in my android-api-example Github project.

Start Camera Intent without Specified File Path

Basically, all you need to do is create an Intent indicating that you want to capture and image. The value indicating that you would like to capture an image is MediaStore.ACTION_IMAGE_CAPTURE. After when you have created the Intent, we then would want to Activity.startActivityForResult() The reason for using Activity.startActivityForResult() instead of Activity.startActivity() is because we need to retrieve the image that the camera intent returns. You must then override Activity.startActivityForResult() method like in the code below: Since, we have not specified to the camera intent where to save the captured image file, it will return the image as a Bundle within the Intent data. Just as a side note, depending on the device that is being used it will either save a copy of the image file on the device (usually where the camera app saves captured images) or it doesn't.

Start Camera Intent with Specified File Path

In order to provide the Intent with a file path, we must come-up with a file path that we would like it to save it to and the filename. Different device have different starting file paths and to do this safely, I first check there is internal storage available and if there is then I retrieve the root public folder of the device's internal storage. This can be done using Android's Environment class. Then in that public root directory I create a standard Android pictures folder using Environment.DIRECTORY_PICTURES. This code is shown below: Once you have the file path, you just need specify the path into the Intent like this: Then finally in your overridden Activity.startActivityForResult(), since you already know the location of the image, you just need to decode the Bitmap using that file path.


You can view my Android Camera Intent example HERE.
Relevant files are:
src/com/choiboi/apiexamples/camera/CameraMainActivity.java
res/layout/activity_camera_main.xml

Hope this was helpful!!

Saturday, August 3, 2013

Android Toast Example

In this post I will be describing how Android Toasts can be done. Toast implementations are pretty simple and does not require many lines of code. To see my working example application of Toast implementation, you can take a look here android-api-example.




Basic Toast

Creating toasts requires only one line as shown below:
Basically all you need to do is invoke the static method Toast.makeText(), which will create a Toast object. The first argument takes in the current activity's Context object, second argument is the message that you would like to display, and finally the third argument would be the length of time that you would like it to be displayed for. Currently, the third argument will only either accept Toast.LENGTH_SHORT or Toast.LENGTH_LONG and you will not be able specify your own set time. Once the Toast object is created, invoke Toast.show() with that Toast object. If you want to display Toast longer then just replace Toast.LENGTH_SHORT with Toast.LENGTH_LONG and you are done!

Display Toast Even Longer

Currently, I was only able to find one way to display Toasts longer than Toast.LENGTH_LONG. What I did was basically invoke show() on the same Toast object more than once consecutively. This was simply done by using a for loop and looping it as many times as you like. Depending on how many times you loop, it will display it for Toast.LENGTH_LONG times the number of times you loop.
In the above code, I am looping 4 times which results to a Toast message displaying for 4×Toast.LENGTH_LONG amount of time.

Custom Toast Background

If you happen to not like the default background, you create your own custom background and display Toasts messages using that background. To do this, you will first need to create a 9-patch image that you want to use for your Toast background. One tool that you can use to create 9-patch images from an existing image is Nine-patch GeneratorOnce you have placed the 9-patch images to their corresponding folders in your Android project, you need to then create a separate layout for your Toast and set that 9-patch image as background value for your root layout. Like this:
Creating a layout like the above gives you the flexibility on how you want to display your Toast. Once you have created your Toast message layout, next step is just a matter of writing few simple lines of code, shown below.
There is also another way customizing your Toast messages. This is done through Android's XML styling and more information can be found here in this link.

You can view my Android Toast example HERE.
Relevant files are:
src/com/choiboi/apiexamples/toast/ToastMainActivity.java
res/layout/activity_toast.xml
res/layout/activity_toast_custom_toast.xml

Happy Coding!

Wednesday, July 24, 2013

Android Image Cropping Example

When I was creating PsyYourself, I was faced with a challenge on how I can crop out the face with an image that the user provides. One option was to somehow apply Optical Character Recognition (OCR) to detect faces in an image and crop that part out, but at the time OCR was something out of my league to create.

Instead I optioned to have a set of templates that make up
the various shapes of faces and from there, users will be able to orient, either by zooming in or out or moving the image, to fit inside the template. Once that was done, it was up to the device to crop out the image. The problem with this is that there were no available cropping tools/algorithms that I can make use of. I mean, there are existing cropping APIs, but the only problem with that is that they crop out rectangular shaped images, which is something that I did not want. Therefore I am posting this blog to show how I did this. The example project can be found on Github android-cropping-example.

Project Setup

Now, both the image that is going to cropped and the template image has to be overlapped on the screen so that users can easily orient the image to fit into the template. This can be accomplished by using FrameLayout and having two ImageView as its children. As seen below.

The first ImageView with the id cp_img will be the image that user will be orienting. While the second ImageView cp_face_template with scaleType as centerInside because I want to use the exact size of my templates that I have created.

Once the users are done with orienting the image, we then now have to get those images from ImageView the way how it is displayed on the screen. To do this we must first call View.buildDrawingCache() and View.setDrawingCacheEnabled() with the boolean value true as their arguments. Then, to get the bitmap, call View.getDrawingCache(). Lastly, call View.setDrawingCacheEnabled() again and this time with the boolean value false passed in. This process will allow you to retrieve images from ImageView multiple times.

Once, we have retrieved both the template and the oriented image, it's time to put the device to work. As we can see above, I created another thread to handle that work as we don't want the main thread to be blocked because it's processing. So, now this is where my algorithm that I have create comes into play.

Cropping Algorithm

The main idea of how my algorithm works is:
  1. I merge the two bitmaps together making sure template is placed on top.
  2. Since I know the size of the template, create a new blank bitmap with those dimensions.
  3. From the centre of the combined image, go out quadrant by quadrant, going through every pixel value and copy it onto the blank bitmap.
  4. Once it hits the colour of the template lines, then from that point on set the pixel value of the blank bitmap transparent.
  5. After it has gotten through all 4 quadrants, return the created bitmap, which is the cropped image. 
Here is the cropping code:
Feel free to view, download, and make use of my code HERE!!
Enjoy :)

Link to android-cropping-example.