I'm working with Android and I really need a fast way to get a bitmap of a predetermined size to be filled with a predetermined colour.
The following code is not working for me however;
Bitmap input is a mutable bitmap
int old = input.getPixel(0, 0);
Canvas c = new Canvas(input);
Rect rect = c.getClipBounds(); // The dimensions of the bitmap are returned
c.drawARGB(a, r, g, b);
int n = input.getPixel(0, 0);
if(old==n)
Log.e(TAG, "Values didn't change!");
return input;
Rest assured, the 'old' value and the value of (a|r|g|b) are different but having 'drawn' the colour using a canvas with my mutable bitmap underneath, the bitmap retains it's old value.
I'd be happy with any method that takes a bitmap and a colour value and returns a bitmap filled with that colour.
I didn't provide enough info!
My alpha value was out of range;
int a = 0xFF<<24
So when I called
c.drawARGB(a,r,g,b);
It failed quietly and didn't change the values.
Related
In my code I need create a Bitmap using double values. It´s important use the correct value.
I´m using:
Bitmap bmp = Bitmap.createBitmap(int, int, Bitmap.Config.ARGB_8888);
... When i would need something like:
Bitmap bmp = Bitmap.createBitmap(double, double, Bitmap.Config.ARGB_8888);
Everything I've trying to make the conversion ( possible ? ) Only returns the initial value or integer
How I can use double values when creating the bitmap?
Perhaps I misunderstand the question, but bitmaps are rasters of whole pixels. You can't have fractions of pixels, so you can only have integer numbers of rows and columns in the parameters for createBitmap.
Having said that, you can rescale how the bitmap is drawn using float scale factors applied via Matrix drawBitmap methods, e.g.
Canvas.drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint)
Matrix matrix = new android.graphics.Matrix();
matrix.postScale(3.14f, 3.14f);
canvas.drawBitmap(bitmap, matrix, paint);
However, when it comes to rendering this on screen, it will again draw only whole pixels, so you still don't get fractional pixels displayed.
Try this, convert double to int:
double myDouble = 10.4;
int myInt = (int) (myDouble);
Using (int) casts the double into an int
I have a list of items where I am displaying a bitmap next to the item's name. This bitmap is to be created from 2 images, I have a background image with a smaller foreground image to add on top of the background.
I am seeing that the background image appears to not be present on some of my rows in my list. It is not consistent when and which row has the combined bitmap without the background. It is not always the same row where the combined bitmap does not have the background and it is not always the first or not always the last row where the bitmap does not have the background. And sometimes the whole list has every row with the correct image.
The image below is a mockup showing my issue.
My code for creating the combined bitmap is as follows.
Bitmap combinedBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas combinedCanvas = new Canvas(combinedBitmap);
// Add the first bitmap to the canvas (this is my background and this is what appears to be
// missing on some rows in my list on some occasions)
combinedCanvas.drawBitmap(backgroundBitmap, 0, 0, null);
// my second smaller image, on top of the first image but 1 pixel in
// from the left and 20 pixels down from the top
combinedCanvas.drawBitmap(foregroundBitmap, 1, 20, null);
return combinedBitmap;
Note: My backgroundBitmap is generated from a Drawable using the following code
Bitmap backgroundBitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
drawable.getMinimumHeight(),
Bitmap.Config.ARGB_8888);
backgroundBitmap.setDensity(resources.getDisplayMetrics().densityDpi);
Canvas canvas = new Canvas(backgroundBitmap);
drawable.draw(canvas);
Any suggestions of what I have wrong or even where to look to try and resolve this would be greatly appreciated.
EDIT: I have tested adding a colour to the background of my combinedCanvas to try and see where the image generation is going wrong by adding the following code
// TEMP: fill the canvas in red for now so I can see which combinedBitmaps are missing
// the background image
combinedCanvas.drawColor(Color.RED);
Now the rows which do not have the background are coloured in red. This indicates that the code above to create the combined canvas is somehow not adding the backgroundBitmap. I have checked and my background image is not null for every row in my list.
This method works fine for me. It's in C# (Xamarin), you'll have to translate it to Java I'm afraid.
public static Bitmap CombineImages(Bitmap background, Bitmap foreground)
{
int width = background.Width, height = background.Height;
Bitmap cs = Bitmap.CreateBitmap(width, height, Bitmap.Config.Argb8888);
Canvas comboImage = new Canvas(cs);
background = Bitmap.CreateScaledBitmap(background, width, height, true);
comboImage.DrawBitmap(background, 0, 0, null);
int top = (int)(0.05 * height);
int left = (int)(width - (foreground.Width + (width * 0.05)));
comboImage.DrawBitmap(foreground, left, top, null);
return cs;
}
The left and top are hardcoded for my requirements, it would be better to pass them in as arguments.
I need to "compute" the resulting bitmap obtained from overlapping two different bitmaps that have an alpha value somewhere between 0 and 255. I need to do this in java code, not xml, because bitmaps are being loaded dinamically and not from resources.
Here is my first try (which always yields a black bitmap...):
private Drawable composeBitmaps(int alpha1, BitmapDrawable bm1,
int alpha2, BitmapDrawable bm2)
{
Canvas c = new Canvas();
Bitmap b1 = bm1.getBitmap();
BitmapDrawable draw1 = new BitmapDrawable(b1.copy(b1.getConfig(), true));
draw1.setAlpha(alpha1);
c.setBitmap(draw1.getBitmap());
Paint p = new Paint();
p.setAlpha(alpha2);
c.drawBitmap(bm2.getBitmap(), 0, 0, p);
return draw1;
}
...
View v = // whatever
v.setBackgroundDrawable(composeBitmaps(100, bdrawable1, 150, bdrawable2));
And the view goes black background. What am I doing wrong?
My code above is absolutely correct. The bug that made the bitmap go black was elsewhere. Found it, fixed it, now it works.
The only thing to note is that my code is slow as hell and it cannot be used to crossfade two fullscreen bitmaps at a reasonable fps rate.
I have a white background image, it is not fit for my app's black background.
I want to make it have black background, or reverse all the colors in the bitmap image.
How can I do that?
Get the width and the height of the bitmap. Store the pixels in array, then iterate each pixel, test for white color (hex value) if it is true than swap it with value for black. This is not the best solution. Why dont you just load black bitmap?
Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.r); //example,
int[] pixels = new int[bm.getWidth()*bm.getHeight()];
bm.getPixels(pixels, 0, bm.getWidth(),0, 0, bm.getWidth(), bm.getHeight()); //filling the array, this might throw some outofboundaryindex exception for the array, check again.
int i = 0;
while(i!=bm.getWidth()*bm.getHeight())
{
if(pixels[i]==hexforblack)
{
swap it with hex of white
}
i++;
}
Here you can find hex values of the colors
http://www.w3schools.com/html/html_colors.asp
I'm currently working on a steganogrpahy android app as a class project. I've created an object that will encode an image with in another image and return an encoded bitmap. This code is run in a seprate thread.
new Thread(new Runnable()
{
public void run()
{
Bitmap encoded_image = null;
Encryptor encryptor = new Encryptor();
encoded_image = encryptor.encode_image_in_image(
image_location,message_image_location);
}
}).start();
After encoding the bitmap I was passing the bitmap to a file browser activity that I've created to save the bitmap as a png image. This method works for smaller images however, when a large image is encoded and passed to the sub activity the application freezes and returns to the main activity.
private void pass_image_to_file_browser( Bitmap image )
{
Intent intent = new Intent(Encrypt.this,FileBrowser.class);
intent.putExtra( Intent.EXTRA_STREAM, image );
startActivity( intent );
}
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Bundle bundle = this.getIntent().getExtras();
Bitmap image = bundle.getParacable(Intent.EXTRA_STREAM);
}
I was assuming a large bitmap was to large to send between activities using an intent so I decided to simply save the image in a temporary location and pass the image's location to the sub activity. Which then saves the png image where the user specifies and deletes the temporary image file.
private void save_bitmap( Bitmap image, String location )
{
FileOutputStream fileOutputStream = new FileOutputStream(location);
BufferedOutputStream buffered_output_stream = new
BufferOutputStream(fileOutputStream);
image.compress(CompressFormat.PNG, 0, buffered_output_stream);
buffered_output_stream.flush();
buffered_output_stream.close();
}
This solves the problem of sending a large bitmap from one activity to another however, has created a new problem that I haven't been able to solve. Both the temporary image that is saved before passing the file location to the sub activity and the image file after re saving the image using the file browser have both had their color changed slightly. This color change is unrecognizable to the naked eye but, when decoding the image it causes lots of problems.
One thought I had was that the Bitmap.Config was changing from ARGB_8888 to ARGB_4444 or RGB_565 however, after debug this is not the case. The bitmap is instantiated as an ARGB_8888 and saved as an ARGB_8888 bitmap and never changes in between. The code still works if I pass the entire bitmap to the file browser activity and I'm saving the bitmaps exactly the same in both places. I do not have any thoughts on what else could be causing this. I'm looking for suggestions on what else could be causing the problem. Sorry I was going to post images on the output in both cases however, stack overflow wouldn't let me at my reputation level Thanks.
Ok, after many long wasted hours worrying about the thread and the algorithm I was using to encode the the bitmap the problem was a little simpler. While decoding the image file that was to be encoded with a message I was using options.inPreferredConfig = Config.ARGB_8888; During debugging I was checking to make sure this didn't change to RGB_565. Although the bitmap object was loaded as ARBG_8888 the image file did not contain an alpha channel and thus even though the bitmap had a byte for the alpha level and would allow me to edit the alpha byte of a pixel through Bitmap.setPixel( x, y, color) the bitmap object never recognized that it had alpha values set. When compressing the bitmap compressed to RGB_565 since the object thought that there was no alpha channel. Somehow this problem was resolved by passing the bitmap to a sub activity and parsing it. I'm guessing when object was being recreated the alpha values I had set were recognized. To solve the problem with out passing the bitmap to a subactivity one must add an alpha channel after decoding a bitmap from a file. I found a function to do so here.
private Bitmap adjustOpacity( Bitmap bitmap )
{
int width = bitmap.getWidth();
int height = bitmap.getHeight();
Bitmap dest = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
int[] pixels = new int[width * height];
bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
dest.setPixels(pixels, 0, width, 0, 0, width, height);
return dest;
}
I'm not sure if there is a more efficient method
For anyone who stumbles upon it, like me, wondering why bitnap colors change once you write it out in PNG. I have found out that using bitmap.setPreMultiplied(false) before calling bitmap.compress(PNG, 100, fileout) preserves the color of your image if it has alpha channel values. Setpremultiplied prevents the pixels written onto disk from being multiplied by alpha channel, thus generating different pixel color values.