Get bitmap of RelativeLayout having invisible TextView or ImageView - android-bitmap

I am to create bitmap of a relative layout having a visible ImageView with two invisible TextViews and one invisible ImageView. But invisible views data was not shown in bitmap. If I set visible all those invisible views it is shown in bitmap, but not if hidden.
I am using below code -
private Bitmap getBitmap(View v) {
Bitmap bmp = null, b1 = null;
RelativeLayout targetView = (RelativeLayout) v;
targetView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
targetView.buildDrawingCache();
b1 = targetView.getDrawingCache();
bmp = b1.copy(Bitmap.Config.ARGB_8888, true);
targetView.destroyDrawingCache();
return bmp;
}
I also used below link but that also didn't give me expected result.
Getting bitmap from a view visible-invisible
I am really in a fix.

The drawing cache saves a bitmap of what's currently drawn on screen. Naturally, this does not include hidden views.
The key difference between the article you provided in the link, and your code is that in the article, the bitmap cache is constructed for the invisible view.
However, you have a visible parent, which contains invisible views. When you create the drawing cache of the parent, the invisible views are, of course, not rendered.
In order for you invisible views to appear, you need to draw the views yourself in a bitmap, then draw that bitmap inside the bitmap which contins the parent.
Code sample:
//these fields should be initialized before using
TextView invisibleTextView1;
TextView invisibleTextView2;
ImageView invisibleImageView;
private Bitmap getBitmap(View v) {
Bitmap bmp = null;
Bitmap b1 = null;
RelativeLayout targetView = (RelativeLayout) v;
targetView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
targetView.buildDrawingCache();
b1 = targetView.getDrawingCache();
bmp = b1.copy(Bitmap.Config.ARGB_8888, true);
targetView.destroyDrawingCache();
//create a canvas which will be used to draw the invisible views
//inside the bitmap returned from the drawing cache
Canvas fullCanvas = new Canvas(bmp);
//create a list of invisible views
List<View> invisibleViews = Arrays.asList(invisibleTextView1, invisibleImageView, invisibleTextView2);
//iterate over the invisible views list
for (View invisibleView : invisibleViews) {
//create a bitmap the size of the current invisible view
//in this bitmap the view will draw itself
Bitmap invisibleViewBitmap = Bitmap.createBitmap(invisibleView.getWidth(), invisibleView.getHeight(), Bitmap.Config.ARGB_8888);
//wrap the bitmap in a canvas. in this canvas the view will draw itself when calling "draw"
Canvas invisibleViewCanvas = new Canvas(invisibleViewBitmap);
//instruct the invisible view to draw itself in the canvas we created
invisibleView.draw(invisibleViewCanvas);
//the view drew itself in the invisibleViewCanvas, which in term modified the invisibleViewBitmap
//now, draw the invisibleViewBitmap in the fullCanvas, at the view's position
fullCanvas.drawBitmap(invisibleViewBitmap, invisibleView.getLeft(), invisibleView.getTop(), null);
//finally recycle the invisibleViewBitmap
invisibleViewBitmap.recycle();
}
return bmp;
}
Final mentions:
if your invisible views have visibility = View.GONE, you should layout(...) on each one, before calling draw(...) in the loop.
if the parent view of your invisible views does not occupy the whole screen, then your invisible views will not be drawn at the correct position, since getLeft() & getTop() return the left & top properties in pixels, relative to the parent location. If your invisible views are within a parent which only covers part of the screen, then use instead:
fullCanvas.drawBitmap(invisibleViewBitmap, invisibleView.getLeft() + parent.getLeft(), v.getTop() + v.getTop(), null);
Let me know if this works!

Related

How to position tabs on a tabcontrol vb.net

VB.Net, TabStrip control,
Tabs are Align Left or Right and Top or Bottom
I need to start tabs from my own position On Top of the Tab control
Like Internet Explorer, Tabs are starting after HTTP address box, but it will cover full page and Align on the left=0.
To display right-aligned tabs
Add a TabControl to your form.
Set the Alignment property to Right.
Set the SizeMode property to Fixed, so that all tabs are the same width.
Set the ItemSize property to the preferred fixed size for the tabs. Keep in mind that the ItemSize property behaves as though the tabs were on top, although they are right-aligned. As a result, in order to make the tabs wider, you must change the Height property, and in order to make them taller, you must change the Width property.
In the code example below, Width is set to 25 and Height is set to 150.
Set the DrawMode property to OwnerDrawFixed.
Define a handler for the DrawItem event of TabControl that renders the text from left to right.
C#
public Form1()
{
// Remove this call if you do not program using Visual Studio.
InitializeComponent();
tabControl1.DrawItem += new DrawItemEventHandler(tabControl1_DrawItem);
}
private void tabControl1_DrawItem(Object sender, System.Windows.Forms.DrawItemEventArgs e)
{
Graphics g = e.Graphics;
Brush _textBrush;
// Get the item from the collection.
TabPage _tabPage = tabControl1.TabPages[e.Index];
// Get the real bounds for the tab rectangle.
Rectangle _tabBounds = tabControl1.GetTabRect(e.Index);
if (e.State == DrawItemState.Selected)
{
// Draw a different background color, and don't paint a focus rectangle.
_textBrush = new SolidBrush(Color.Red);
g.FillRectangle(Brushes.Gray, e.Bounds);
}
else
{
_textBrush = new System.Drawing.SolidBrush(e.ForeColor);
e.DrawBackground();
}
// Use our own font.
Font _tabFont = new Font("Arial", (float)10.0, FontStyle.Bold, GraphicsUnit.Pixel);
// Draw string. Center the text.
StringFormat _stringFlags = new StringFormat();
_stringFlags.Alignment = StringAlignment.Center;
_stringFlags.LineAlignment = StringAlignment.Center;
g.DrawString(_tabPage.Text, _tabFont, _textBrush, _tabBounds, new StringFormat(_stringFlags));

AndEngine visible rectangle

I'm trying to create an additional visibility rectangle on a main Scene.
So I'v a main Camera 480x800 that is showing me a scene as it is and i'd like to attach an aditional entity or a scene that will have a rectangle of visibility.
So if I'll drag items inside it they will not dissapier in a single moment they will dissapier gradually.
As described in my previous comment you could stamp out a square alpha hole in your background Sprite. You could do this simply with an image editor, adding alpha pixels or you could do it dynamically as follows,
//set the background to white - so we can see our square alpha
//cut out later
mScene.setBackground(new ColorBackground(1.0f, 1.0f, 1.0f));
//Create and load bitmap texture atlas
BitmapTextureAtlas mBitmapBGTextureAtlas = new BitmapTextureAtlas(1024, 1024, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
mActivity.getEngine().getTextureManager().loadTextures(mBitmapBGTextureAtlas);
//Get image in assets and decode into bitmap
InputStream ims;
try {
ims = mActivity.getAssets().open("gfx/my_backgound.jpg");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
}
Bitmap Bitmap_bg = BitmapFactory.decodeStream(ims);
//In my case the image is different than the height and width of the camera
//so store the ratio of size and height that the image will be resized to
float XScale = Bitmap_bg.getWidth()/mCamera.getWidth();
float YScale = Bitmap_bg.getHeight()/mCamera.getHeight();
//Cut out the alpha square, if our camera is 480x800, the square will appear
//at (40,200) and will be size 400x400
Bitmap_bg = cutSquareOutOfBitmap(Bitmap_bg, 40 * XScale, 200 * YScale, 400 * XScale , 400 * YScale);
//Get our edited bitmap into a region of the texture atlas
BitmapTextureAtlasSource source = new BitmapTextureAtlasSource(Bitmap_bg);
mBackground = BitmapTextureAtlasTextureRegionFactory.createFromSource(mBitmapBGTextureAtlas, source, 0, 0);
Bitmap_bg.recycle();
//Finally, create our background sprite with this new texture region
Sprite mBackgroundSprite = new Sprite(0, 0, mCamera.getWidth(), mCamera.getHeight(), mBackground);
mBackgroundSprite.setZIndex(1);
mScene.attachChild(mBackgroundSprite);
And the function cutSquareOutOfBitmap()
public static Bitmap cutSquareOutOfBitmap(Bitmap MyImage, float Xpos, float Ypos, float Width, float Height) {
Bitmap mBitmap = MyImage.copy(Bitmap.Config.ARGB_8888, true);
Paint mPaint = new Paint();
Canvas mCanvas = new Canvas(mBitmap );
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint .setXfermode(new PorterDuffXfermode(Mode.SRC_OUT));
mPaint .setColor(Color.TRANSPARENT);
mCanvas.drawBitmap(mBitmap , 0, 0, null);
mCanvas.drawRect(Xpos, Ypos, Xpos + Width, Ypos + Height, mPaint );
return mBitmap ;
}
If you run this - not a lot to look at but a big white square, however, this is a transparent region, the square is actually the background we set earlier.
To demonstrate how the contents will be obscured, you could create a scrollable area, as mentioned in my previous comment I wrote a small container class you are welcome to use,
Custom ScrollView in andengine
Underneath the first code block in this answer, after,
mScene.attachChild(mBackgroundSprite);
You could now add,
//Now we can use the ShapeScrollContainer just as an example so the user can
//scroll our container shapes around
//Create it around the same area as the cut out
ShapeScrollContainer mShapeScrollContainer = new ShapeScrollContainer(40, 200, 400, 400, new IShapeScrollContainerTouchListener() {
#Override
public void OnContentClicked(Shape pShape) {
// TODO Auto-generated method stub
//Add code here for content click event
}
});
//Disable the ShapeScrollContainer ability to change the visibility
//of contents - we no longer require this as the background will
//cover them outside of the bounds of the ShapeScrollContainer itself
mShapeScrollContainer.SetContentVisiblitiyControl(false);
//Disable alpha
mShapeScrollContainer.SetAlphaVisiblitiyControl(false);
//Allow user to scroll both horizontally and vertically
mShapeScrollContainer.SetScrollableDirections(true, true);
//Don't allow the user to scroll to no where
mShapeScrollContainer.SetScrollLock(true);
//Allow use to scroll half the container over in either direction
mShapeScrollContainer.SetScrollLockPadding(50.0f,50.0f);
//Attach the container to the scene and register the event listener
mScene.registerTouchArea(mShapeScrollContainer);
mScene.attachChild(mShapeScrollContainer);
//Finally add some content to the container, what ever extends Shape,
//Sprite, Animated Sprite, Text, ChangeableText e.t.c.
Rectangle mRectangle = new Rectangle(200, 360, 80, 80);
mRectangle.setColor(0.0f, 1.0f, 0.0f);
mRectangle.setZIndex(0);
//Attach to the scene and the ShapeScrollContainer
mScene.attachChild(mRectangle);
mShapeScrollContainer.Add(mRectangle);
Rectangle mRectangle2 = new Rectangle(40, 360, 80, 80);
mRectangle2.setColor(0.0f, 0.0f, 1.0f);
mRectangle2.setZIndex(0);
mScene.attachChild(mRectangle2);
mShapeScrollContainer.Add(mRectangle2);
Rectangle mRectangle3 = new Rectangle(360, 360, 80, 80);
mRectangle3.setColor(1.0f, 1.0f, 0.0f);
mRectangle3.setZIndex(0);
mScene.attachChild(mRectangle3);
mShapeScrollContainer.Add(mRectangle3);
//And sort the order in which shapes are rendered
mScene.sortChildren();
Now you should get something like the following after scrolling,
As another alternative if you are going for a simpler background you could forgo the bitmap manipulation and simply make the square with four surrounding rectangles making up the sides to the edge of the screen.
Or you could physically split your background into 4 surrounding rectangles and a central square with an image editor. Then create 5 sprites, set the z order of the four rectangles to 2, the square to 0 and any content sprites to 1.
Hope this is of use.

JPanel resize and scroll errors

I use a text area with variable hight and some other things (a combo box in the sample code) filling the window width.
The following error happens:
- When using "innerPanel.setPreferredSize", the scroller does not appear when the text area becomes higher than the window by typing line feeds into the text area or when resizing the window vertically.
- When not using "innerPanel.setPreferredSize", (as shown commented in the sample code below), the used swing elements enlarge horizontally when resizing the window width, but do never shrink horizontally.
JPanel innerPanel = new JPanel(new GridBagLayout());
JTextArea editArea = new JTextArea();
editArea.setLineWrap(true);
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1.;
innerPanel.add(editArea, gbc);
JComboBox combo = new JComboBox();
gbc.gridy = 1;
innerPanel.add(combo, gbc);
JScrollPane scroller = new JScrollPane(innerPanel,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
//innerPanel.setPreferredSize(new Dimension(50, 50));
JPanel outerPanel = new JPanel(new BorderLayout());
outerPanel.add(scroller);
frame.setContentPane(outerPanel);

How is iBooks rendering the index view so quickly when viewing a PDF? Or: how do draw UIImages on UIScrollView directly without UIImageView?

I have a 140 pages test PDF (the full Adobe PDF specification, http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/adobe_supplement_iso32000.pdf) and open it in iBooks. Then switch to index (thumbnail) view. If I scroll to the end fast enough I can see that I can scroll faster than iBooks renders the pages but it catches up pretty quickly on iPad 2.
I learn two things from this:
First iBooks is showing 140 empty squares in the right size and then populates the preview.
iBooks really renders all of the previews and keeps them in memory (if I scroll around I cannot spot any re-rendering)
I also tested with another Adobe Spec that has 700+ pages: exactly same behavior! Fascinating!
The question is how are they doing it? I wrote some code that gets each page of the PDF as an image, adds it to a UIImageView and adds that to the scrollview.
I use the same technique and layout as iBooks does. It renders just as quick as iBooks but memory consumption is insane and especially when scrolling the app gets totally stuck after a while. Can anybody point me in the right direction? I already removed the PDF rendering for testing and it is really fast, so I can pin it down to the thumbnail generation.
EDIT:
If from the code below the PDF generation is removed and an empty UIImageView is returned instead, the performance is still extremely weak. So my assumption is that the UIImageView is causing the problem. How can I draw the PDF thumbs onto my UIScrollView without the requirement of 140 UIImageViews?
For those firm in Monotouch, here's the code I'm using to render the thumbs, maybe it shows an obvious weakness:
/// <summary>
/// Gets the low res page preview of a PDF page. Does a quick image render of the page.
/// </summary>
/// <param name="iPage">the number of the page to render</param>
/// <param name="oTergetRect">the target rect to fit the PDF page into</param>
/// <returns>
/// The low res page image view.
/// </returns>
public static UIImageView GetLowResPagePreview (CGPDFPage oPdfPage, RectangleF oTargetRect)
{
RectangleF oOriginalPdfPageRect = oPdfPage.GetBoxRect (CGPDFBox.Media);
RectangleF oPdfPageRect = PdfViewerHelpers.RotateRectangle( oPdfPage.GetBoxRect (CGPDFBox.Media), oPdfPage.RotationAngle);
// If preview is requested for the PDF index view, render a smaller version.
if (!oTargetRect.IsEmpty)
{
// Resize the PDF page so that it fits the target rectangle.
oPdfPageRect = new RectangleF (new PointF (0, 0), GetFittingBox (oTargetRect.Size, oPdfPageRect.Size));
}
// Create a low res image representation of the PDF page to display before the TiledPDFView
// renders its content.
int iWidth = Convert.ToInt32 ( oPdfPageRect.Size.Width );
int iHeight = Convert.ToInt32 ( oPdfPageRect.Size.Height );
CGColorSpace oColorSpace = CGColorSpace.CreateDeviceRGB();
CGBitmapContext oContext = new CGBitmapContext(null, iWidth, iHeight, 8, iWidth * 4, oColorSpace, CGImageAlphaInfo.PremultipliedLast);
// First fill the background with white.
oContext.SetFillColor (1.0f, 1.0f, 1.0f, 1.0f);
oContext.FillRect (oOriginalPdfPageRect);
// Scale the context so that the PDF page is rendered
// at the correct size for the zoom level.
oContext.ConcatCTM ( oPdfPage.GetDrawingTransform ( CGPDFBox.Media, oPdfPageRect, 0, true ) );
oContext.DrawPDFPage (oPdfPage);
CGImage oImage = oContext.ToImage();
UIImage oBackgroundImage = UIImage.FromImage( oImage );
oContext.Dispose();
oImage.Dispose ();
oColorSpace.Dispose ();
UIImageView oBackgroundImageView = new UIImageView (oBackgroundImage);
oBackgroundImageView.Frame = new RectangleF (new PointF (0, 0), oPdfPageRect.Size);
oBackgroundImageView.ContentMode = UIViewContentMode.ScaleToFill;
oBackgroundImageView.UserInteractionEnabled = false;
oBackgroundImageView.AutoresizingMask = UIViewAutoresizing.None;
return oBackgroundImageView;
}
internal static RectangleF RotateRectangle ( RectangleF oRect, int iRotationAngle )
{
if ( iRotationAngle == 90 || iRotationAngle == 270 )
{
return new RectangleF (oRect.X, oRect.Y, oRect.Height, oRect.Width);
}
return oRect;
}
You shouldn't be using 140 UIImageViews !!! use only just enough to fill the area and then recycle the ones that are no longer displayed.
How did Apple implement UITableView ?? Do you think they keep all tableview cells in memory??
Look at the PhotoScroller sample code and the corresponding WWDC 2010 video. I think it is named "Desigining apps with scrollViews"
WWDC 2011 video of similar name is continuation of the same trick of view reuse.
Hope this helps.
Have you checked the size of each UIImageView? Perhaps each of your thumbnails is actually the size of a full page.
Perhaps iBooks doesn't put each thumbnail in a UIImageView? Maybe the app is using something from CoreAnimation or even OpenGL ES?

Android View.onDraw() always has a clean Canvas

I am trying to draw an animation. To do so I have extended View and overridden the onDraw() method. What I would expect is that each time onDraw() is called the canvas would be in the state that I left it in and I could choose to clear it or just draw over parts of it (This is how it worked when I used a SurfaceView) but each time the canvas comes back already cleared. Is there a way that I can not have it cleared? Or maybe save the previous state into a Bitmap so I can just draw that Bitmap and then draw over top of it?
I'm not sure if there is a way or not. But for my custom views I either redraw everything each time onDraw() is called, or draw to a bitmap and then draw the bitmap to the canvas (like you suggested in your question).
Here is how i do it
class A extends View {
private Canvas canvas;
private Bitmap bitmap;
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
if (bitmap != null) {
bitmap .recycle();
}
canvas= new Canvas();
bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
canvas.setBitmap(bitmap);
}
public void destroy() {
if (bitmap != null) {
bitmap.recycle();
}
}
public void onDraw(Canvas c) {
//draw onto the canvas if needed (maybe only the parts of animation that changed)
canvas.drawRect(0,0,10,10,paint);
//draw the bitmap to the real canvas c
c.drawBitmap(bitmap,
new Rect(0,0,bitmap.getWidth(),bitmap.getHeight()),
new Rect(0,0,bitmap.getWidth(),bitmap.getHeight()), null);
}
}
you should have a look here to see the difference between basic view and surfaceView. A surfaceView has a dedicated layer for drawing, which I suppose keeps track of what you drew before. Now if you really want to do it on a basic View, you could try to put each item you draw in an array, like the exemple of itemized overlay for the mapview.
It should work pretty much the same way
Your expectations do not jib w/ reality :) The canvas will not be the way you left it, but it blank instead. You could create an ArrayList of objects to be drawn (canvas.drawCircle(), canvas.drawBitmap() etc.), then iterate though the ArrayList in the OnDraw(). I am new to graphics programming but I have used this on a small scale. Maybe there is a much better way.