how to simplify an img array that uses many drawable ressources - android

I have an array which contains several drawables needed by my main java code I use this to call them when needed:
mImagesArray = new int[]{R.drawable.img_0, R.drawable.img_1, R.drawable.img_2,...,R.drawable.img_m}
this direct implementation method works but imagine if i have an array containing +100 images, I would call each drawable value from img_1 to the final img_100 which is pretty frustrating.
What I need is a function which use an increment int i value that is defined by (for i=0;i<m;i++) so this function would look much simpler than the previous one that I used.. something like mImagesArray = new int[]{R.drawable.img_i} maybe ?
I hope you understood my question, basically I want an all-set function which requires only mImagesArray's number of elements..
edit ** mImagesArray is used in:
private void drawImage(Canvas canvas) {
//Get the image and resize it
Bitmap image = BitmapFactory.decodeResource(getResources(),
mImagesArray_ar[mImagesArrayIndex]);
//Draw background
// customWallpaperHelper.setBackground(canvas);
//Scale the canvas
PointF mScale = customWallpaperHelper.getCanvasScale(mImageScale, image.getWidth(), image.getHeight());
canvas.scale(mScale.x, mScale.y);
//Draw the image on screen
Point mPos = customWallpaperHelper.getImagePos(mScale, image.getWidth(), image.getHeight());
canvas.drawBitmap(image, mPos.x, mPos.y, null);
}
THANKS.

Add this method to your code:
protected final static int getResourceID
(final String resName, final String resType, final Context ctx)
{
final int ResourceID =
ctx.getResources().getIdentifier(resName, resType,
ctx.getApplicationInfo().packageName);
if (ResourceID == 0)
{
throw new IllegalArgumentException
(
"No resource string found with name " + resName
);
}
else
{
return ResourceID;
}
}
And use it like this:
int myID =
getResourceID("your_resource_name", "drawable", getApplicationContext());
Note: no path nor extension, in case of images.
You can even not use the mImagesArray array: just use int myID = getResourceID("img_" + i, "drawable", getApplicationContext());, where i is an integer (the same integer you would use as your array index).
Like this:
Bitmap image =
BitmapFactory.decodeResource(getResources(),
getResourceID("img_" + mImagesArrayIndex, "drawable", getApplicationContext()));

I would rather suggest you to just create a string array with all the drawable names and then extract the drawable from the names.
I mean to say similar to this:-
String[] drawables=new String[100]
for(int i=0;i<100;i++)
drawables[i]="img"+i;
Then finally when you want it you get by name like this:-
int drawableResourceId = this.getResources().getIdentifier(drawables[i], "drawable", this.getPackageName());

Had the same problem.
int x,i=0;
While(i<100){
ImageView view = new ImageView(this);
name="img_"+i;
x=getResources().getIdentifier(name, "drawable, getPackageName());
view.setImageResurse(x);
mainActivity.addView(view);
i++;
}

Related

How to create a Dynamic decodeResource?

I want to create a dynamic decodeResource to use very images in the object.
This is my code:
for(int i=42; i<55; i++) {
bitmap = BitmapFactory.decodeResource(context.getResources(),
Integer.parseInt("R.drawable.a"+i));
}
I want to get the files
R.drawable.a43 to a54
Its possible to create a loop for decodeResource?
To retrieve the resource ID for 'R.drawable.a##' dynamically we can use Resources.getIdentifier as follows:
final String pkg = context.getPackageName();
final Resources resources = context.getResources();
...
int num = ...; /* between 43 and 54 */
final int id = resources.getIdentifier("a" + num, "drawable", pkg);
You can store these in a List using a loop much like the one you have now, only with slightly modified bounds:
final String pkg = context.getPackageName();
final Resources resources = context.getResources();
final List<Bitmap> bitmaps = new ArrayList<Bitmap>();
for (int i = 43; i <= 54; ++i) {
/* decode bitmap with id R.drawable.a{i} */
final Bitmap bitmap = BitmapFactory.decodeResource(resources,
resources.getIdentifier("a" + i, "drawable", pkg));
bitmaps.add(bitmap);
}
/* now bitmaps contains the Bitmaps */

How to implement photo collage on Android

I am working on photo collage project on Android. I want to know how to implement the following collage effect?
So there are two photos will fit into each triangle.
or more complex shape like this: (this will hod 5 photos)
It's not that easy.
One solution would be to remove the unwanted pixel of your image like the following snippet from this thread (cuts off the top right corner):
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ImageView iv = (ImageView) findViewById(R.id.your_image);
int drawableId = R.drawable.your_drawable;
cutOffTopRightCorner(iv, drawableId, skewWidth);
}
#SuppressLint("NewApi")
private void cutOffTopRightCorner(ImageView iv, int resId, int skewWidth) {
Bitmap bm = BitmapFactory.decodeResource(getResources(), resId).copy(Config.ARGB_8888, true);
bm.setHasAlpha(true);
final int bmWidth = bm.getWidth();
for (int i = bmWidth; i > bmWidth - skewWidth; --i) {
for (int k = 0; k < i - (bmWidth - skewWidth); ++k) {
bm.setPixel(i - 1, k, Color.TRANSPARENT);
}
}
iv.setImageBitmap(bm);
}
Another solution would be to work with FrameLayouts (differenz z-indices) and to overlay your images with other images or drawables.
You can also have a look into this thread.

How to load multiple drawables from id using a loop?

Must be a way looping through this code:
private void loadSprites() {
this.sprites[0] = BitmapFactory.decodeResource(getResources(), R.drawable.ic_boom01);
this.sprites[1] = BitmapFactory.decodeResource(getResources(), R.drawable.ic_boom02);
this.sprites[2] = BitmapFactory.decodeResource(getResources(), R.drawable.ic_boom03);
this.sprites[3] = BitmapFactory.decodeResource(getResources(), R.drawable.ic_boom04);
this.sprites[4] = BitmapFactory.decodeResource(getResources(), R.drawable.ic_boom05);
this.sprites[5] = BitmapFactory.decodeResource(getResources(), R.drawable.ic_boom06);
this.sprites[6] = BitmapFactory.decodeResource(getResources(), R.drawable.ic_boom07);
}
Thanks!
If I am understand your question, you want something like,
int[] drawables = {R.drawable.ic_boom01,R.drawable.ic_boom02,R.drawable.ic_boom03,R.drawable.ic_boom04,R.drawable.ic_boom05,R.drawable.ic_boom06,R.drawable.ic_boom07}
private void loadSprites() {
for(int i=0; i<this.sprites.length; i++)
this.sprites[i] = BitmapFactory.decodeResource(getResources(), drawables[i]);
}
You should place your images in the assets folder. From their you can access them via their file name. See http://developer.android.com/reference/android/content/res/AssetManager.html.
Please look at below code for that.
First make int array
int[] mImgArray = { R.drawable.ic_boom01, R.drawable.ic_boom02,
R.drawable.ic_boom03, R.drawable.ic_boom04, R.drawable.ic_boom05,
R.drawable.ic_boom06, R.drawable.ic_boom07 };
or Set this Image to ImageView using below code
mImgView1.setImageResource(mImgArray[0]);
And you can convert this image directly to bitmap and store into bitmap array using below code.
Bitmap mBmpArray=new Bitmap[mImgArray.length];
for(int i=0; i<mImgArray.length; i++)
mBmpArray[i] = BitmapFactory.decodeResource(getResources(), mImgArray[i]);
}
This works for me
//Bitmap of images for fly asset
private Bitmap fly[] = new Bitmap[8];
//Initialize array of images
for(int i = 0; i < fly.length; i++){
this.fly[i] = BitmapFactory.decodeResource( getResources(), getResources().getIdentifier("fly_frame" + i, "drawable", context.getPackageName() ) );
}
You can do that in a simple for loop.. and start from the first id and increment it by 1 at each loop.. though I don't recommend you to do this..

NinePatchDrawable does not get padding from chunk

I need help with NinePatchDrawable:
My app can download themes from the network.
Almost all things work fine, except 9-Patch PNGs.
final Bitmap bubble = getFromTheme("bubble");
if (bubble == null) return null;
final byte[] chunk = bubble.getNinePatchChunk();
if (!NinePatch.isNinePatchChunk(chunk)) return null;
NinePatchDrawable d = new NinePatchDrawable(getResources(), bubble, chunk, new Rect(), null);
v.setBackgroundDrawable(d);
d = null;
System.gc();
getFromTheme() loads the Bitmap from the SD card. The 9-Patch PNGs are already compiled, that means they include the required chunk.
The way how I convert the Bitmap to a NinePatchDrawable object seems to be working, because the image is stretchable as well as I drew it.
The only thing that doesn't work is the padding. I already tried to set the padding to the view like this:
final Rect rect = new Rect(); // or just use the new Rect() set
d.getPadding(rect); // in the constructor
v.setPadding(rect.left, rect.top, rect.right, rect.bottom);
d.getPadding(rect) should fill the variable rect with the padding got from the chunk, shouldn't it? But it doesn't.
Result: The TextView (v) does not show the text in the content area of the 9-Patch image. The paddings are set to 0 in each coordinate.
Thanks for reading.
Finally, I did it. Android wasn't interpreting the chunk data correctly. There might be bug. So you have to deserialize the chunk yourself to get the padding data.
Here we go:
package com.dragonwork.example;
import android.graphics.Rect;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
class NinePatchChunk {
public static final int NO_COLOR = 0x00000001;
public static final int TRANSPARENT_COLOR = 0x00000000;
public final Rect mPaddings = new Rect();
public int mDivX[];
public int mDivY[];
public int mColor[];
private static void readIntArray(final int[] data, final ByteBuffer buffer) {
for (int i = 0, n = data.length; i < n; ++i)
data[i] = buffer.getInt();
}
private static void checkDivCount(final int length) {
if (length == 0 || (length & 0x01) != 0)
throw new RuntimeException("invalid nine-patch: " + length);
}
public static NinePatchChunk deserialize(final byte[] data) {
final ByteBuffer byteBuffer =
ByteBuffer.wrap(data).order(ByteOrder.nativeOrder());
if (byteBuffer.get() == 0) return null; // is not serialized
final NinePatchChunk chunk = new NinePatchChunk();
chunk.mDivX = new int[byteBuffer.get()];
chunk.mDivY = new int[byteBuffer.get()];
chunk.mColor = new int[byteBuffer.get()];
checkDivCount(chunk.mDivX.length);
checkDivCount(chunk.mDivY.length);
// skip 8 bytes
byteBuffer.getInt();
byteBuffer.getInt();
chunk.mPaddings.left = byteBuffer.getInt();
chunk.mPaddings.right = byteBuffer.getInt();
chunk.mPaddings.top = byteBuffer.getInt();
chunk.mPaddings.bottom = byteBuffer.getInt();
// skip 4 bytes
byteBuffer.getInt();
readIntArray(chunk.mDivX, byteBuffer);
readIntArray(chunk.mDivY, byteBuffer);
readIntArray(chunk.mColor, byteBuffer);
return chunk;
}
}
Use the class above as following:
final byte[] chunk = bitmap.getNinePatchChunk();
if (NinePatch.isNinePatchChunk(chunk)) {
textView.setBackgroundDrawable(new NinePatchDrawable(getResources(),
bitmap, chunk, NinePatchChunk.deserialize(chunk).mPaddings, null));
}
And it will work perfectly!
It's actually slightly more complicated than that, but what it boils down to is pretty simple:
The padding rect is returned by BitmapFactory.decodeStream(InputStream, Rect, Options). There is no version of decodeByteArray() which can return the padding rect.
The whole nine-patch API is a bit silly:
decodeByteArray() calls nativeDecodeByteArray(), which is presumably more efficient than nativeDecodeStream() on a ByteArrayInputStream, but obviously the devs never expected you to want to decode a nine-patch from memory.
The padding rect is only used by nine-patches, so it makes more sense for it to be part of NinePatch instead of BitmapFactory. Sadly, NinePatch.java is not much more than a wrapper that passes the bitmap and nine-patch chunk to drawing methods (and most of the NinePatch.draw() calls aren't thread-safe due to the call to mRect.set(location)).
NinePatchDrawable doesn't offer a way to take a NinePatch and a padding rect, which makes NinePatch somewhat useless in application code (unless you want to do the padding yourself). There is no NinePatchDrawable.getNinePatch() or NinePatch.getBitmap().
This comment sums it up pretty well:
ugh. The decodeStream contract is that we have already allocated
the pad rect, but if the bitmap does not had a ninepatch chunk,
then the pad will be ignored. If we could change this to lazily
alloc/assign the rect, we could avoid the GC churn of making new
Rects only to drop them on the floor.
My fix is fairly simple:
public final class NinePatchWrapper {
private final Bitmap mBitmap;
private final Rect mPadding;
/**
* The caller must ensure that that bitmap and padding are not modified after
* this method returns. We could copy them, but Bitmap.createBitmap(Bitmap)
* does not copy the nine-patch chunk on some Android versions.
*/
public NinePatchWrapper(Bitmap bitmap, Rect padding) {
mBitmap = bitmap;
mPadding = padding;
}
public NinePatchDrawable newDrawable(Resources resources) {
return new NinePatchDrawable(mBitmap, mBitmap.getNinePatchChunk(), mPadding, null);
}
}
...
public NinePatchWrapper decodeNinePatch(byte[] byteArray, int density) {
Rect padding = new Rect();
ByteArrayInputStream stream = new ByteArrayInputStream(byteArray);
Bitmap bitmap = BitmapFactory.decodeStream(stream, padding, null);
bitmap.setDensity(density);
return new NinePatchWrapper(bitmap, padding);
}
Untested, since it's greatly simplified. In particular, you might want to check that the nine-patch chunk is valid.
I've never seen an example where the Padding isn't included as part of the 9-patch like so:
To do this you should first construct a NinePatch and then create you're Drawable from it:
NinePatch ninePatch = new NinePatch(bitmap, chunk, srcName);
NinePatchDrawable d = new NinePatchDrawable(res, ninePatch);
However, you seem to be constructing your Drawable with an empty rectangle:
NinePatchDrawable d = new NinePatchDrawable(getResources(), bubble, chunk, new Rect(), null);
If you want to programatically specify the padding try this:
Rect paddingRectangle = new Rect(left, top, right, bottom);
NinePatchDrawable d = new NinePatchDrawable(getResources(), bubble, chunk, paddingRectangle, null);
A bit late to the party, but here is how I solved it:
I use the decoder method that NinePatchDrawable provides, it reads the padding correctly:
var myDrawable = NinePatchDrawable.createFromStream(sr, null);

combining two png files in android

I have two png image files that I would like my android app to combine programmatically into one png image file and am wondering if it is possible to do so? if so, what I would like to do is just overlay them on each other to create one file.
the idea behind this is that I have a handful of png files, some with a portion of the image on the left with the rest transparent and the others with an image on the right and the rest transparent. and based on user input it will combine the two to make one file to display. (and i cant just display the two images side by side, they need to be one file)
is this possible to do programmatically in android and how so?
I've been trying to figure this out for a little while now.
Here's (essentially) the code I used to make it work.
// Get your images from their files
Bitmap bottomImage = BitmapFactory.decodeFile("myFirstPNG.png");
Bitmap topImage = BitmapFactory.decodeFile("myOtherPNG.png");
// As described by Steve Pomeroy in a previous comment,
// use the canvas to combine them.
// Start with the first in the constructor..
Canvas comboImage = new Canvas(bottomImage);
// Then draw the second on top of that
comboImage.drawBitmap(topImage, 0f, 0f, null);
// comboImage is now a composite of the two.
// To write the file out to the SDCard:
OutputStream os = null;
try {
os = new FileOutputStream("/sdcard/DCIM/Camera/" + "myNewFileName.png");
comboImage.compress(CompressFormat.PNG, 50, os)
} catch(IOException e) {
e.printStackTrace();
}
EDIT :
there was a typo,
So, I've changed
image.compress(CompressFormat.PNG, 50, os)
to
bottomImage.compress(CompressFormat.PNG, 50, os)
You can do blending. This is not particular to Android. It's just universal image processing.
EDIT:
You may find these articles & samples & code useful:
http://www.jhlabs.com/ip/
http://kfb-android.blogspot.com/2009/04/image-processing-in-android.html
http://code.google.com/p/jjil/
Image Processing on Android
I use this code
private class PhotoComposition extends AsyncTask<Object, Void, Boolean> {
private String pathSave;//path save combined images
#Override
protected Boolean doInBackground(Object... objects) {
List<String> images = (List<String>) objects[0]; //lsit of path iamges
pathSave = (String) objects[1];//path save combined images
if (images.size() == 0) {
return false;
}
List<Bitmap> bitmaps = new ArrayList<>();
for (int i = 0; i < images.size(); i++) {
bitmaps.add(BitmapFactory.decodeFile( images.get(i)));
}
int width = findWidth(bitmaps);//Find the width of the composite image
int height = findMaxHeight(bitmaps);//Find the height of the composite image
Bitmap combineBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);//create bitmap of composite image
combineBitmap.eraseColor(Color.parseColor("#00000000")); //bcakgraound color of composite image
Bitmap mutableCombineBitmap = combineBitmap.copy(Bitmap.Config.ARGB_8888, true);//create mutable bitmap to create canvas
Canvas canvas = new Canvas(mutableCombineBitmap);// create canvas to add bitmaps
float left = 0f;
for (int i = 0; i < bitmaps.size(); i++) {
canvas.drawBitmap(bitmaps.get(i), left, 0f, null);//Taking photos horizontally
left += bitmaps.get(i).getWidth();//Take right to the size of the previous photo
}
OutputStream outputStream = null;
try {
outputStream = new FileOutputStream(pathSave);//path of save composite image
mutableCombineBitmap.compress(Bitmap.CompressFormat.PNG, 80, outputStream);
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
#Override
protected void onPostExecute(Boolean isSave) {
if (isSave) {
//iamge save on pathSave
Log.i("PhotoComposition", "onPostExecute: " + pathSave);
}
super.onPostExecute(isSave);
}
private int findMaxHeight(List<Bitmap> bitmaps) {
int maxHeight = Integer.MIN_VALUE;
for (int i = 0; i < bitmaps.size(); i++) {
if (bitmaps.get(i).getHeight() > maxHeight) {
maxHeight = bitmaps.get(i).getHeight();
}
}
return maxHeight;
}
private int findWidth(List<Bitmap> bitmaps) {
int width = 0;
for (int i = 0; i < bitmaps.size(); i++) {
width += bitmaps.get(i).getWidth();
}
return width;
}
USAGE
List<String> images = new ArrayList<>();
images.add("/storage/emulated/0/imageOne.png");//path of image in storage
images.add("/storage/emulated/0/imageTwo.png");
// images.add("/storage/emulated/0/imageThree");
// ... //add more images
String pathSaveCombinedImage = "/storage/emulated/0/CombinedImage.png";//path save result image
new PhotoComposition().execute(images, pathSaveCombinedImage);
And the result of using the above code will be as follows
You may wish to look into the Canvas object, which would make it easy to do other drawing operations as well. You can just draw your bitmaps onto a canvas where you want them, then save the resulting bitmap.
If they have transparent sections, then if you draw one on top of the other, only the non-transparent portions will overlap. It will be up to you to arrange the bitmaps however you like.
For the separate issue of re-saving your image to a png, use bitmap.compress().
Try this .
public Bitmap mergeBitmap(Bitmap frame, Bitmap img){
Bitmap bmOverlay = Bitmap.createBitmap(frame.getWidth(), frame.getHeight(), frame.getConfig());
Canvas canvas = new Canvas(bmOverlay);
canvas.drawBitmap(img, 0, 0, null);
canvas.drawBitmap(frame, new Matrix(), null);
return bmOverlay;
}
Returns a bitmap image
Pass two bitmap images to your function as shown below
Bitmap img= mergeBitmap(imgone, imagetwo);
See the entire post or also see merge multiple images in android programmatically

Categories

Resources