Implementing Clickable Images

PSLab Android application is a feature rich compact app to user interface the PSLab hardware device. Similarly the PSLab device itself is a compact device with a plenty of features to replace almost all the analytical instruments in a school science lab. When a first time user takes the device and connect it with the Android app, there are so many pins labeled with abbreviations. This creates lots of complications unless the user checks the pinout diagram separately. As a workaround a UI is proposed to integrate a layout containing the PSLab PCB image where user can click on each pin to get a dialog box explaining him what that specific pin is and what it does. This implementation can be done it two ways; Using an Image map Using (x,y) coordinates The first implementation is more practical and can be applied with any device with any dimension. The latter requires some transformation to capture the correct position when user has clicked on a pin. So the first method will be implemented. The idea behind using an image map is to have two images with exact dimensions on top of each other. The topmost image will be the color map which we create ourselves using unique colors at unique heat points. This image will have the visibility setting invisible as the main idea is to let the  user see a meaningful image and capture the positions using a secondary in the back end. To make things much clear, let's have a look at a color map image I am suggesting here for a general case. If we overlap the color map with the PSLab layout, we will be able to detect where user has clicked using Android onTouchEvent. @Override public boolean onTouchEvent(MotionEvent ev) { final int action = ev.getAction(); final int evX = (int) ev.getX(); final int evY = (int) ev.getY(); switch (action) { case MotionEvent.ACTION_UP : int touchColor = getHotspotColor (R.id.backgroundMap, evX, evY); /* Display the relevant pin description dialog box here */ break; } return true; }   Color of the clicked position can be captured using the following code; public int getHotspotColor (int hotspotId, int x, int y) { ImageView img = (ImageView) findViewById (hotspotId); img.setDrawingCacheEnabled(true); Bitmap hotspots = Bitmap.createBitmap(img.getDrawingCache()); img.setDrawingCacheEnabled(false); return hotspots.getPixel(x, y); }   If we go into details, from the onTouchEvent we capture the (x,y) coordinates related to user click. Then this location is looked up for a unique color by creating a temporary bitmap and then getting the pixel value at the captured coordinate. There is an error in this method as the height parameter always have an offset. This offset is introduced by the status bar and the action bar of the application. If we use this method directly, there will be an exception thrown out saying image height is less than the height defined by y. Solving this issue involves calculating status bar and actionbar heights separately and then subtract them from the y coordinate. Actionbar and status bar heights can…

Continue ReadingImplementing Clickable Images

Encoding and Saving Images as Strings in Preferences in SUSI Android App

In this blog post, I’ll be telling about how to store images in preferences by encoding them into Strings and also how to retrieve them back. Many a times, you need to store an image in preferences for various purposes and then need to retrieve it back when required. In SUSI Android App, we need to store an image in preference to set the chat background. We just simply select image from gallery, convert image to a byte array, then do a Base 64 encoding to string, store it in preferences and later decode it and set the chat background. Base64 Encoding-Decoding in Java You may already know what Base 64 is but still here is a link to Wikipedia article explaining it. So, how to do a Base64 encoding-decoding in java? For that java has a class with all such methods already present. https://docs.oracle.com/javase/8/docs/api/java/util/Base64.html According to the docs: This class consists exclusively of static methods for obtaining encoders and decoders for the Base64 encoding scheme. The implementation of this class supports the following types of Base64 as specified in RFC 4648 and RFC 2045. Basic URL and Filename safe MIME So, you may just use Base64.encode to encode a byte array and Base64.decode to decode a byte array. Implementation 1. Selecting image from gallery      Start Image Picker Intent and pick an image from gallery. After selecting you may also start a Crop Intent to crop image also. After selecting and cropping image, you will get a URI of the image. override fun openImagePickerActivity() { val i = Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI) startActivityForResult(i, SELECT_PICTURE) } val thePic = data.extras.getParcelable<Bitmap>("data") val encodedImage = ImageUtils.Companion.cropImage(thePic) chatPresenter.cropPicture(encodedImage) 2. Getting image from the URI using inputstream Next step is to get the image from file using URI from the previous step and InputStream class and store it in a BitMap variable. val imageStream: InputStream = context.contentResolver.openInputStream(selectedImageUri) val selectedImage: Bitmap val filePathColumn = arrayOf(MediaStore.Images.Media.DATA) val cursor = context.contentResolver.query(getImageUrl(context.applicationContext, selectedImageUri), filePathColumn, null, null, null) cursor?.moveToFirst() selectedImage = BitmapFactory.decodeStream(imageStream) 3. Converting the bitmap to ByteArray Now, just convert the Bitmap thus obtained to a ByteArray using below code. val baos = ByteArrayOutputStream() selectedImage.compress(Bitmap.CompressFormat.JPEG, 100, baos) val b = baos.toByteArray() 4. Base64 encode the ByteArray and store in preference Encode the the byte array obtained in last step to a String and store it in preferences. val encodedImage = Base64.encodeToString(b, Base64.DEFAULT) //now you have a string. You can store it in preferences 5. Decoding the String to image Now whenever you want, you can just decode the stored Base64 encoded string to a byte array and then from byte array to a bitmap and use wherever you want. fun decodeImage(context: Context, previouslyChatImage: String): Drawable { val b = Base64.decode(previouslyChatImage, Base64.DEFAULT) val bitmap = BitmapFactory.decodeByteArray(b, 0, b.size) return BitmapDrawable(context.resources, bitmap) } Summary So, the main aim of this blog was to give an idea about how can you store images in preferences. There is no way to store them directly. So, you have to convert them to String by encoding…

Continue ReadingEncoding and Saving Images as Strings in Preferences in SUSI Android App