package org.music.player;
import org.music.player.R;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.util.DisplayMetrics;
import android.util.TypedValue;
/**
* Class containing utility functions to create Bitmaps display song info and
* album art.
*/
public final class CoverBitmap {
/**
* Draw cover in background and a box with song info on top.
*/
public static final int STYLE_OVERLAPPING_BOX = 0;
/**
* Draw cover on top or left with song info on bottom or right (depending
* on orientation).
*/
public static final int STYLE_INFO_BELOW = 1;
/**
* Draw no song info, only the cover.
*/
public static final int STYLE_NO_INFO = 2;
private static int TEXT_SIZE = -1;
private static int TEXT_SIZE_BIG;
private static int PADDING;
private static int TEXT_SPACE;
private static Bitmap SONG_ICON;
private static Bitmap ALBUM_ICON;
private static Bitmap ARTIST_ICON;
/**
* Initialize the regular text size members.
*
* @param context A context to use.
*/
private static void loadTextSizes(Context context)
{
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
TEXT_SIZE = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 14, metrics);
TEXT_SIZE_BIG = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, metrics);
PADDING = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, metrics);
TEXT_SPACE = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 150, metrics);
}
/**
* Initialize the icon bitmaps.
*
* @param context A context to use.
*/
private static void loadIcons(Context context)
{
Resources res = context.getResources();
SONG_ICON = BitmapFactory.decodeResource(res, R.drawable.ic_tab_songs_selected);
ALBUM_ICON = BitmapFactory.decodeResource(res, R.drawable.ic_tab_albums_selected);
ARTIST_ICON = BitmapFactory.decodeResource(res, R.drawable.ic_tab_artists_selected);
}
/**
* Helper function to draw text within a set width
*
* @param canvas The canvas to draw to
* @param text The text to draw
* @param left The x coordinate of the left edge of the text
* @param top The y coordinate of the top edge of the text
* @param width The measured width of the text
* @param maxWidth The maximum width of the text. Text outside of this width
* will be truncated.
* @param paint The paint style to use
*/
private static void drawText(Canvas canvas, String text, int left, int top, int width, int maxWidth, Paint paint)
{
canvas.save();
int offset = Math.max(0, maxWidth - width) / 2;
canvas.clipRect(left, top, left + maxWidth, top + paint.getTextSize() * 2);
canvas.drawText(text, left + offset, top - paint.ascent(), paint);
canvas.restore();
}
/**
* Create an image representing the given song. Includes cover art and
* possibly song title/artist/ablum, depending on the given style.
*
* @param context A context to use.
* @param style One of CoverBitmap.STYLE_*
* @param coverArt The cover art for the song.
* @param song Title and other data are taken from here for info modes.
* @param width Maximum width of image
* @param height Maximum height of image
* @return The image, or null if the song was null, or width or height
* were less than 1
*/
public static Bitmap createBitmap(Context context, int style, Bitmap coverArt, Song song, int width, int height)
{
switch (style) {
case STYLE_OVERLAPPING_BOX:
return createOverlappingBitmap(context, coverArt, song, width, height);
case STYLE_INFO_BELOW:
return createSeparatedBitmap(context, coverArt, song, width, height);
case STYLE_NO_INFO:
return createScaledBitmap(coverArt, width, height);
default:
throw new IllegalArgumentException("Invalid bitmap type given: " + style);
}
}
private static Bitmap createOverlappingBitmap(Context context, Bitmap cover, Song song, int width, int height)
{
if (TEXT_SIZE == -1)
loadTextSizes(context);
Paint paint = new Paint();
paint.setAntiAlias(true);
String title = song.title == null ? "" : song.title;
String album = song.album == null ? "" : song.album;
String artist = song.artist == null ? "" : song.artist;
int titleSize = TEXT_SIZE_BIG;
int subSize = TEXT_SIZE;
int padding = PADDING;
paint.setTextSize(titleSize);
int titleWidth = (int)paint.measureText(title);
paint.setTextSize(subSize);
int albumWidth = (int)paint.measureText(album);
int artistWidth = (int)paint.measureText(artist);
int boxWidth = Math.min(width, Math.max(titleWidth, Math.max(artistWidth, albumWidth)) + padding * 2);
int boxHeight = Math.min(height, titleSize + subSize * 2 + padding * 4);
int coverWidth;
int coverHeight;
if (cover == null) {
coverWidth = 0;
coverHeight = 0;
} else {
coverWidth = cover.getWidth();
coverHeight = cover.getHeight();
float scale = Math.min((float)width / coverWidth, (float)height / coverHeight);
coverWidth *= scale;
coverHeight *= scale;
}
int bitmapWidth = Math.max(coverWidth, boxWidth);
int bitmapHeight = Math.max(coverHeight, boxHeight);
Bitmap bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(bitmap);
if (cover != null) {
int x = (bitmapWidth - coverWidth) / 2;
int y = (bitmapHeight - coverHeight) / 2;
Rect rect = new Rect(x, y, x + coverWidth, y + coverHeight);
canvas.drawBitmap(cover, null, rect, paint);
}
int left = (bitmapWidth - boxWidth) / 2;
int top = (bitmapHeight - boxHeight) / 2;
int right = (bitmapWidth + boxWidth) / 2;
int bottom = (bitmapHeight + boxHeight) / 2;
paint.setARGB(150, 0, 0, 0);
canvas.drawRect(left, top, right, bottom, paint);
int maxWidth = boxWidth - padding * 2;
paint.setARGB(255, 255, 255, 255);
top += padding;
left += padding;
paint.setTextSize(titleSize);
drawText(canvas, title, left, top, titleWidth, maxWidth, paint);
top += titleSize + padding;
paint.setTextSize(subSize);
drawText(canvas, album, left, top, albumWidth, maxWidth, paint);
top += subSize + padding;
drawText(canvas, artist, left, top, artistWidth, maxWidth, paint);
return bitmap;
}
private static Bitmap createSeparatedBitmap(Context context, Bitmap cover, Song song, int width, int height)
{
if (TEXT_SIZE == -1)
loadTextSizes(context);
if (SONG_ICON == null)
loadIcons(context);
boolean horizontal = width > height;
Paint paint = new Paint();
paint.setAntiAlias(true);
String title = song.title == null ? "" : song.title;
String album = song.album == null ? "" : song.album;
String artist = song.artist == null ? "" : song.artist;
int textSize = TEXT_SIZE;
int padding = PADDING;
int coverWidth;
int coverHeight;
if (cover == null) {
coverWidth = 0;
coverHeight = 0;
} else {
coverWidth = cover.getWidth();
coverHeight = cover.getHeight();
int maxWidth = horizontal ? width - TEXT_SPACE : width;
int maxHeight = horizontal ? height : height - textSize * 3 - padding * 4;
float scale = Math.min((float)maxWidth / coverWidth, (float)maxHeight / coverHeight);
coverWidth *= scale;
coverHeight *= scale;
}
paint.setTextSize(textSize);
int titleWidth = (int)paint.measureText(title);
int albumWidth = (int)paint.measureText(album);
int artistWidth = (int)paint.measureText(artist);
int maxBoxWidth = horizontal ? width - coverWidth : width;
int maxBoxHeight = horizontal ? height : height - coverHeight;
int boxWidth = Math.min(maxBoxWidth, textSize + Math.max(titleWidth, Math.max(artistWidth, albumWidth)) + padding * 3);
int boxHeight = Math.min(maxBoxHeight, textSize * 3 + padding * 4);
int bitmapWidth = horizontal ? coverWidth + boxWidth : Math.max(coverWidth, boxWidth);
int bitmapHeight = horizontal ? Math.max(coverHeight, boxHeight) : coverHeight + boxHeight;
Bitmap bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(bitmap);
if (cover != null) {
int x = horizontal ? 0 : (bitmapWidth - coverWidth) / 2;
int y = horizontal ? (bitmapHeight - coverHeight) / 2 : 0;
Rect rect = new Rect(x, y, x + coverWidth, y + coverHeight);
canvas.drawBitmap(cover, null, rect, paint);
}
int top;
int left;
if (horizontal) {
top = (bitmapHeight - boxHeight) / 2;
left = padding + coverWidth;
} else {
top = padding + coverHeight;
left = padding;
}
int maxWidth = boxWidth - padding * 3 - textSize;
paint.setARGB(255, 255, 255, 255);
canvas.drawBitmap(SONG_ICON, left, top, paint);
drawText(canvas, title, left + padding + textSize, top, maxWidth, maxWidth, paint);
top += textSize + padding;
canvas.drawBitmap(ALBUM_ICON, left, top, paint);
drawText(canvas, album, left + padding + textSize, top, maxWidth, maxWidth, paint);
top += textSize + padding;
canvas.drawBitmap(ARTIST_ICON, left, top, paint);
drawText(canvas, artist, left + padding + textSize, top, maxWidth, maxWidth, paint);
return bitmap;
}
/**
* Scales a bitmap to fit in a rectangle of the given size. Aspect ratio is
* preserved. At least one dimension of the result will match the provided
* dimension exactly.
*
* @param source The bitmap to be scaled
* @param width Maximum width of image
* @param height Maximum height of image
* @return The scaled bitmap.
*/
private static Bitmap createScaledBitmap(Bitmap source, int width, int height)
{
int sourceWidth = source.getWidth();
int sourceHeight = source.getHeight();
float scale = Math.min((float)width / sourceWidth, (float)height / sourceHeight);
sourceWidth *= scale;
sourceHeight *= scale;
return Bitmap.createScaledBitmap(source, sourceWidth, sourceHeight, false);
}
/**
* Generate the default cover (a rendition of a CD). Returns a square iamge.
* Both dimensions are the lesser of width and height.
*
* @param width The max width
* @param height The max height
* @return The default cover.
*/
public static Bitmap generateDefaultCover(int width, int height)
{
int size = Math.min(width, height);
int halfSize = size / 2;
int eightSize = size / 8;
Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.RGB_565);
LinearGradient gradient = new LinearGradient(size, 0, 0, size, 0xff646464, 0xff464646, Shader.TileMode.CLAMP);
RectF oval = new RectF(eightSize, 0, size - eightSize, size);
Paint paint = new Paint();
paint.setAntiAlias(true);
Canvas canvas = new Canvas(bitmap);
canvas.rotate(-45, halfSize, halfSize);
paint.setShader(gradient);
canvas.translate(size / 20, size / 20);
canvas.scale(0.9f, 0.9f);
canvas.drawOval(oval, paint);
paint.setShader(null);
paint.setColor(0xff000000);
canvas.translate(size / 3, size / 3);
canvas.scale(0.333f, 0.333f);
canvas.drawOval(oval, paint);
paint.setShader(gradient);
canvas.translate(size / 3, size / 3);
canvas.scale(0.333f, 0.333f);
canvas.drawOval(oval, paint);
return bitmap;
}
}