
Not so long ago, on duty, I was faced with one task: it was necessary to invent and implement the design of a media player for Android. And if to think over and organize more or less tolerable placement of controls and information turned out to be no tricky business, then I had to think carefully to introduce some zest to the design. Fortunately, in stock I had such an element as a picture with an album cover of the melody being played. It was he who had to add color to the whole picture.
However, being simply displayed among the buttons and inscriptions, the cover looked like a paper sticker pasted on the screen. I realized that without image processing is not enough.
Some thoughts about what could be thought up here were crowned with the decision to make the effect of reflection and shadow on the cover image. At once I will make a reservation that the practical implementation of reflection is not my original idea. I spied it in the found English-language
article . In this post, I just want to give some insight into the manipulations performed on the image, my additions to the processing process and note some nuances of working with Bitmap in Android.
So at the entrance I had a bitmap with a picture. To start, I created an empty Bitmap the size of the original image, which later was supposed to become the same cover, but with a shadow applied to it.
width = sourceBitmap.getWidth(); height = sourceBitmap.getHeight(); Bitmap gradCover; try { gradCover = Bitmap.createBitmap(width, height, config); } catch (OutOfMemoryError e) { gradCover = null; }
This method creates a mutable (importantly) Bitmap.
Here it is necessary to note that when working with Bitmaps it is necessary to closely monitor the memory. We'll have to catch exceptions. And one more thing: studying with the profiler showed that before calling the createBitmap () method, the garbage collector works. Consider this if speed is critical in your application.
Next, I created a canvas and painted on it the original image.
Canvas canvas = new Canvas(gradCover); canvas.drawBitmap(sourceBitmap, 0, 0, null);
In this place, I note that always, as soon as the Bitmap is not needed, it must be destroyed using the recycle () method. The fact is that an object of this type is just a link to the memory with the image itself and looks very small for the garbage collector (although in fact it takes a lot of memory). This can cause the memory to end at the most inopportune moment.
After all the preparation, I painted on the canvas with a shade.
Paint paint = new Paint(); int[] colors = {0xffffffff, 0xffffffff, 0xb0c0c0c0, 0xb0c0c0c0}; float radius = (((float) width * (float) width) / 4 + (float) height * (float) height) / ((float) width); int fullRadius = (int) (1.92 * radius); float[] positions = {0, 0.499f, 0.511f, 1}; RadialGradient shader = new RadialGradient((width - radius), 0, fullRadius, colors, positions, Shader.TileMode.CLAMP); paint.setShader(shader); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); canvas.drawRect(0, 0, width, height, paint); int[] linColors = {0x00ffffff, 0xffffffff, 0xff000000, 0x00000000}; float[] linPositions = {0, 0.03f, 0.97f, 1}; LinearGradient vertical = new LinearGradient(0, 0, 0, height, linColors, linPositions, Shader.TileMode.CLAMP); paint.setShader(vertical); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); canvas.drawRect(0, 0, width, height, paint); LinearGradient horizontal = new LinearGradient(0, 0, width, 0, linColors, linPositions, Shader.TileMode.CLAMP); paint.setShader(horizontal); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); canvas.drawRect(0, 0, width, height, paint);
RadialGradient in my case represents a shadow falling in a semicircle from the upper right corner of the image to the center of the bottom face. He needs to set the center (may go beyond the image), the radius, the sequence of colors and the distance from the center along the radius for each color. For the shadow, a change in alpha in colors on the radius was used.
LinearGradient was used to fade the edges of the picture. Its application is very similar to RadialGradient. It is necessary to set the beginning and end of the line along which the gradient will go, the colors and their positions on this line.
')
Finally, I started drawing the reflection. By this time, I already had a Bitmap with gradBitmap shadows. Again, it was necessary to create a canvas, create an empty image (this time a third longer than the original one), place it on the canvas and apply a Bitmap with shadows on top of it.
Bitmap refCover = Bitmap.createBitmap(width, height + height / 3, Bitmap.Config.ARGB_8888); Canvas refCanvas = new Canvas(refCover); refCanvas.drawBitmap(gradCover, 0, 0, null);
After some preparations, the most interesting began. I created a matrix that flips the image upwards. With its help I created Bitmap from a third of the original one and put it on the canvas under the original image.
Matrix matrix = new Matrix(); matrix.preScale(1, -1); Bitmap reflectionImage = Bitmap.createBitmap(gradCover, 0, 2 * height / 3, width, height / 3, matrix, false); refCanvas.drawBitmap(reflectionImage, 0, height, null); reflectionImage.recycle();
By the way, a brief note: there are several createBitmap methods in the Bitmap class, and only one of them creates mutable Bitmaps on which to draw. The rest for drawing ON them are not suitable.
Finally, a transparent gradient is applied to give a reflection effect.
Paint refPaint = new Paint(); LinearGradient refShader = new LinearGradient(0, height, 0, height + height / 3, 0xc0ffffff, 0x00ffffff, Shader.TileMode.CLAMP); refPaint.setShader(refShader); refPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); refCanvas.drawRect(0, height, width, refCover.getHeight() + height, refPaint);
The paint is applied to the part of the pattern that is a reflection.
Everything. I received a refCover - Bitmap, which shows the album cover with shadow, smooth edges and reflection.
PS In this article, it was not the fact of the achievement of visual effects that was important to me, but the means of obtaining them and the nuances associated with them. If for someone the things described here are obvious - fine. All the rest, I hope the article will help in writing their applications for Android.
UPD: pictures before and after

