If I were to initialize a Paint, and set it's text size like so:
Paint = new Paint();
Paint.setAntiAlias(true);
Paint.setARGB(255, 255, 0, 0);
Paint.setTextSize(screenWidth/100);
//screenWidth is the width of the screen in pixels given via display metrics.
And then draw text to the canvas like so:
String text = "Hello"
canvas.drawText(text, (screenWidth/13), (screenHeight/5), Paint);
Would the text Show up in the same relative spot the same relative size regardless of screen metrics? I ask because I only have 1 device and the Emulator doesn't run very well on my multi-core machine.
What I've been doing up until this point is simply using a bitmap with the text written over a background, but my memory usage is getting quite heavy, so I'm looking to cut down on the number of bitmaps loaded.
My other option is to save the text as a bitmap with a transparent background and overlay it on a single bitmap background. But that seems to be only half as productive, as it is actually creating 1 more bitmap, just reducing the total size of all the bitmaps stored. I also don't like this idea because i'd eventually like to take more control over the object life cycle and this will make that less effective.
Also, is there any method of adding styles to text (such as complicated fonts and color patterns besides using pre-made Drawables) so that the text can be drawn to canvas? (As cheaply as possible)
NVM, Solved By Poking around all day I figured out that DP units can be called from the res folder and will give a fairly uniform position of the text. and that paint is not as customization friendly as I wish.
Related
I have a set of small images. If I draw these images individually on canvas, the draw quality is significantly low, compared to the case where I draw them on a screen size large bitmap and draw that bitmap on the canvas. Specially the lines get distorted. See the below (right side).
From the code below, the canvas also supports zooming (scaling). This issue occurs on small scale factors.
Question is how to improve the draw quantity of multiple small images to the standard of large image.
This is a code of multiple bitmaps drawn on canvas
canvas.scale(game.mScaleFactor, game.mScaleFactor);
canvas.translate(game.mPosX, game.mPosY);
for (int i = 0; i < game.clusters.size(); i++) {
Cluster cluster = game.clusters.get(i);
canvas.drawBitmap(cluster.Picture, cluster.left,
cluster.top, canvasPaint);
}
This is the code for single bitmap, game.board is a screen size image which has all the small bitmaps drawn on.
canvas.scale(game.mScaleFactor, game.mScaleFactor);
canvas.translate(game.mPosX, game.mPosY);
canvas.drawBitmap(game.board, matrix, canvasPaint)
The paint brush has following properties set.` All bitmaps are Bitmap.Config.ARGB_8888.
canvasPaint.setAntiAlias(true);
canvasPaint.setFilterBitmap(true);
canvasPaint.setDither(true);`
I can think of a couple, depending on you you are drawing the borders of the puzzle pieces.
The problem you are having is that when the single image is scaled, the lines are filtered with the rest of the image and it looks smooth (the blending is correct). When the puzzle is draw per-piece, the filtering reads adjacent pixels on the puzzle piece and blends them with the piece.
Approach 1
The first approach (one that is easy to do) is to render to FBO (RTT) at the logical size of the game and then scale the whole texture to the canvas with a fullscreen quad. This will get you the same result as single because the pixel blending involves neighboring pieces.
Approach B
Use bleeding to solve the issue. When you cut your puzzle piece, include the overlapping section of the adjacent pieces. Instead of setting the discarded pixels to zero, only set the alpha to zero. This will cause your blending function to pickup the same values as if it were placed on a single image. Also, double the lines for the border, but set the outside border alpha to zero.
Approach the Final
This last one is the most complicated, but will be smooth (AF) for any scaling.
Turn the alpha channel of your puzzle piece into a Signed Distance Field and render using a specialized shader that will smooth the output at any distance. Also, SDF allows you to draw the outline with a shader during rendering, and the outline will be smooth.
In fact, your SDF can be a separate texture and you can load it into the second texture stage. Bind the source image as tex unit 0, the sdf puzzle piece cutout(s) on tex unit 1 and use the SDF shader to determine the alpha from the SDF and the color from tex0, then mix in the outline as calculated from the SDF.
http://www.valvesoftware.com/publications/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf
https://github.com/Chlumsky/msdfgen
http://catlikecoding.com/sdf-toolkit/docs/texture-generator/
SDF is generated from a Boolean map. Your puzzle piece cutouts will need to start as monochrome cutout and then turned into SDF (offline) using a tool or similar as listed above. Valve and LibGDX have example SDF shaders, as well as the tools listed above.
I have an array of strings and I have drawn those strings on screen using android graphics library (Canvas, Paint). Firstly, a transparent rectangle is drawn then on this rectangle I paint the strings, giving the impression of text with border line and filled.
The problem is some strings are long and some are short, how can I modify the rectangle so that it is as long and as wide as the string is? (Like WRAP_CONTENT in textView)
Currently I am using this method
canvas.drawRect(_x-10, _y-10, _x+620, _y+30, rectanglePaint);
canvas.drawText(placeName, _x, _y, textPaint); //text
If there is a better way then please do let me know.
Note: It will be used in an AR app so the text will be moving from left to right and vice versa as the mobile is moving. _x, _y for place name works perfectly in 2nd line, I want text should remain highlighted, no matter how the mobile is moving.
Paint has a measure text method that will give the width of the text if it were to be drawn with that paint. Its get font metrics will probably give you some data that you can calculate the height from. The sizing, positioning, wrapping and rendering of text is a very complicated problem and I would advise using a child TextView (with a background) in your ViewGroup rather than trying to roll your own if you're doing anything complicated.
To place a custom font on my widget I am creating a bitmap with the font inside of it, and then placing that bitmap into my RemoteViews. However the text on the bitmap is pretty fuzzy, and looks really pixelated compared to how crystal clear it is within an Activity.
There are quite a few apps already that use custom fonts on a widget. I haven't found a solid way to do this yet though. If anyone has a better solution to this problem I would love to hear it!
Right now this is what I am using to create the bitmap and place it on the widget:
RemoteViews widgetView = new RemoteViews(this.getPackageName(), R.layout.widget);
widgetView.setImageViewBitmap(R.id.widgetImage, buildBitmap());
with
public Bitmap buildBitmap() {
Bitmap bitmap = Bitmap.createBitmap(160, 84, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
TextPaint textPaint = new TextPaint(TextPaint.LINEAR_TEXT_FLAG | TextPaint.ANTI_ALIAS_FLAG);
textPaint.setTypeface(getFont());
textPaint.setStyle(Style.FILL);
textPaint.setColor(fontColor);
textPaint.setTextSize(fontSize);
StaticLayout staticLayout = new StaticLayout(textString, textPaint, bitmap.getWidth(), Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
staticLayout.draw(canvas);
return bitmap;
}
The culprit Widgets! The one on the top is with the custom font, the middle image is with the default Sans font on a bitmap, to show that the text is fuzzy no matter what font is used.
The Last image is what the text looks like when using the default remoteView.setTextViewText("Text"); instead of a bitmap.
Any assistance on this problem would be greatly appreciated!
You can't assume 160x84. That's a very small size. When scaled it will likely be fuzzy as you can see. Instead, you'll want to actually measure out the bitmap size based on measurements of your text at a given sp. Paint.measureText is useful sometimes for these kinds of things to get the width, but you'll need height as well to do it right, so getTextBounds might be more useful. You'll probably need to add some padding too, but this should get you started. As you can see in your pictures, the clarity is not the only problem you have to deal with. You'll have to figure out word wrapping too (perhaps here is where Paint.measureText will come in handy).
The ImageView you are using requires android:scaleType="matrix" attribute to be added. Edit your widget layout xml and add that attribute where needed. The ImageView will then not try and scale your image to fit the view.
As previous posts have said your pixel dimensions are wrong. You should be maintaining a record of the size of each of your widgets so you can later use it for creating the bitmap.
If you want help working this bit out I can post some code. Accept this answer and post another about that question specifically and I will answer there with the code.
I have a bitmap and want to be able to change all black pixels in that bitmap to blue. I know you can do this via Bitmap.setPixel but that process is extremely slow (believe me, I tried it...even doing the setPixels instead of setPixel).
Researching this is see where people recommend using PorterDuff Xor, but there isn't any posts on how this was successfully done. Lots of people asking...no one spelling out the answer.
So using, paint, bitmap, and canvas, how do you change every black pixel to all blue ones?
Thanks!
you just pull the pixels of the bitmap
myBitmap.getPixels(myPixels, 0 0, 0, 0, myBitmap.getWidth(), myBitmap.getHeight())
and loop over myPixels looking for whatever color you wish and modifying that pixel to whatever color you prefer.
I'm trying to dynamically create images in android by taking an existing Bitmap and removing the centre of it in order to make a "cropped" version. The resulting image's height would naturally be smaller than the original, something like the attached example.
I've got a rough way of doing this by creating two new Bitmaps from the original, one containing the top of the image above the crop section (e.g. the android's head in the example) and the other containing the remaining image below the crop section (the android's feet) using the Bitmap.createBitmap(source, x, y, width, height) method, then drawing both of these bitmaps onto a canvas of a size equal to the original image minus the removed space.
This feels a bit clunky, and as I could be calling this method several times a second, it seems wasteful to create two bitmaps each time.
I was wondering if there was a more efficient way of doing this. Something like drawing the original Bitmap onto a canvas using a Path with it's Paint's xfermode set to a
new PorterDuffXfermode(Mode.DST_OUT) in order to cut out the portion of the image I wish to delete. But this seems to clear that area and not shrink the image down i.e. it leaves a big empty gap in the Android's middle.
Any suggestions greatly appreciated!
Why do you create two bitmaps? You only need to create one bitmap and then do canvas.drawBitmap() twice.
Bitmap bmpOriginal;
Bitmap bmpDerived = Bitmap.create(...);
Canvas canvas = new Canvas(bmpDerived);
canvas.drawBitmap(bmpOriginal, rectTopSrc, rectTopDst, null);
canvas.drawBitmap(bmpOriginal, rectBottomSrc, rectBottomDst, null);
Done.