Scaled down a PDF Document Page in Android Studio - android-studio

I need to print a Bitmap on a PDF Document without loosing the image quality.
The thing is Bitmap has always few times large width & height than the A4 sheet. So there may be two options to achieve the expected output.
Scaled the Bitmap and then print on A4 size PDF Page.
Print the Bitmap as it is on a PDF page and the scaled down the PDF Page.
Option No.1 is not gave the result as what I expected. Yes it print on A4 size PDF with correct dimensions and the position, but the image quality is worst and it's totally unusable after scale the Bitmap.
Option No.2 will work (at least I hope so), but the thing is I don't know how to scaled down the PDF page with the content on it.
So please give me help to get the output as I expected.
Option 1 Codes Sample
//boolean img1_SetImage - used to check Img1 is available or not
//img1_Uri - Uri of Img1
if (img1_SetImage) {
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inScaled = false;
Bitmap bmp = BitmapFactory.decodeFile(img1_Uri.getPath(), opt);
int[] xyImg = xy(bmp.getWidth(), bmp.getHeight(), 298, 175);
PdfDocument.PageInfo myPageInfo2 =
new PdfDocument.PageInfo.Builder(595, 842, 1).create();
PdfDocument.Page myPage2 = myPDFDoc.startPage(myPageInfo2);
Canvas myCanvas2 = myPage2.getCanvas();
Bitmap scaledBmp = Bitmap.createScaledBitmap(bmp, xyImg[0], xyImg[1], false);
myCanvas2.drawBitmap(scaledBmp, xyImg[2], xyImg[3], new Paint(Paint.FILTER_BITMAP_FLAG));
bmp.recycle();
scaledBmp.recycle();
}
private int[] xy(float width, float height, float left, float top) {
int finalWidth, finalHeight, finalLeft, finalTop;
float wScale, hScale, scaleFactor;
wScale = (436 / width);
hScale = (270 / height);
if (wScale >= hScale) {
scaleFactor = hScale;
} else {
scaleFactor = wScale;
}
finalWidth = (int) (width * scaleFactor);
finalHeight = (int) (height * scaleFactor);
finalLeft = (int) (left - (finalWidth / 2));
finalTop = (int) (top - (finalHeight / 2));
int[] returnValues = {finalWidth, finalHeight, finalLeft, finalTop};
return returnValues;
}
Thanks.

Related

How can I make an image used on multiple Excel spreadsheets always display at its full size (Aspose Cells)?

I am using the following code to place an image on a spreadsheet:
var ms = new MemoryStream();
Image _logo = RoboReporterConstsAndUtils.GetURLImage("http://www.proactusa.com/bla/pa_logo_notag.png");
_logo.Save(ms, ImageFormat.Png);
ms.Position = 0;
locationWorksheet.Pictures.Add(0, 4, ms);
AutoFitterOptions options = new AutoFitterOptions { OnlyAuto = true };
locationWorksheet.AutoFitRows(options);
It works fine; however, I use this same code on two different reports, and the image displays at different sizes. On one it has a height of 0.85" (63%) and a width of 1.1" (53%), while on the other it has a height of 1.44" (106%) and a width of 2.07" (100%).
Why would they differ in size? And why wouldn't they be 100% of the original image size?
The other code, which seems to be exactly the same (although in this case the column at which the image appears is dynamic), is:
var ms = new MemoryStream();
Image _logo = RoboReporterConstsAndUtils.GetURLImage("http://www.proactusa.com/bla/pa_logo_notag.png");
_logo.Save(ms, ImageFormat.Png);
ms.Position = 0;
pivotTableSheet.Pictures.Add(0, _grandTotalsColumnPivotTable - 1, ms);
AutoFitterOptions options = new AutoFitterOptions { OnlyAuto = true };
pivotTableSheet.AutoFitRows(options);
The image itself, at the location referenced, has a height of 1.35" and a width of 2.07"
The method called is:
internal static Image GetURLImage(string url)
{
WebClient wc = new WebClient();
byte[] bytes = wc.DownloadData(url);
MemoryStream ms = new MemoryStream(bytes);
return Image.FromStream(ms);
}
How can I get the image to always display at 100%, or at least at a given size?
UPDATE
I also have (at least for now) some reports in the same project that are generated using EPPlus. In these, I have the following code, which allows me to set the exact size of the image:
private void AddImage(ExcelWorksheet oSheet, int rowIndex, int colIndex)
{
Image _logo = RoboReporterConstsAndUtils.GetURLImage("http://www.proactusa.com/bla/pa_logo_notag.png");
var excelImage = oSheet.Drawings.AddPicture("PRO*ACT Logo", _logo);
excelImage.From.Column = colIndex - 1;
excelImage.From.Row = rowIndex - 1;
excelImage.SetSize(199, 130); // 199WX130H is the actual size of the image
excelImage.From.ColumnOff = Pixel2MTU(2);
excelImage.From.RowOff = Pixel2MTU(2);
}
...which is called like so:
AddImage(deliveryPerformanceWorksheet, UNIT_ROW, LOGO_FIRST_COLUMN);
...but this won't fly in the Aspose code, because the sheet is of a different type - an Aspose.Cells.Worksheet instead of an ExcelWorksheet, and thus this code:
AddImage(locationWorksheet, 0, 4);
... won't compile in the Aspose report. I wish I could temporarily convert the Aspose.Cells.Worksheet to an ExcelWorksheet as cavalierly as this:
ExcelWorksheet ews = locationWorksheet; // naive attempt to magically morph an Aspose.Cells.Worksheet to an ExcelWorksheet
AddImage(ews, 0, 4);
...so that I could call AddImage(), but that flagrant attempt is tweeted to a halt by the compiler whistling, "Cannot implicitly convert type 'Aspose.Cells.Worksheet' to 'OfficeOpenXml.ExcelWorksheet'"
UPDATE 2
The image is the expected size; this code:
int h = _logo.Height; //130, as expected
int w = _logo.Width; //199, " "
...showed the image was the original size. Could the problem be the AutoFitterOptions setting? Does OnlyAuto allow stretching/squashing of the image, depending on the size of the cell into which it is plopped?
UPDATE 3
In EPPlus I can get the images to display at exactly the same size using this code:
private void AddImage(ExcelWorksheet oSheet, int rowIndex, int colIndex)
{
Image _logo = RoboReporterConstsAndUtils.GetURLImage("http://www.proactusa.com/bla/pa_logo_notag.png");
var excelImage = oSheet.Drawings.AddPicture("PRO*ACT Logo", _logo);
excelImage.From.Column = colIndex - 2;
excelImage.From.Row = rowIndex - 1;
excelImage.SetSize(199, 130);
excelImage.From.ColumnOff = Pixel2MTU(2);
excelImage.From.RowOff = Pixel2MTU(2);
}
...but in Aspose I can only come close using:
var ms = new MemoryStream();
Image _logo = RoboReporterConstsAndUtils.GetURLImage("http://www.proactusa.com/bla/pa_logo_notag.png");
_logo.Save(ms, ImageFormat.Png);
ms.Position = 0;
pivotTableSheet.Pictures.Add(0, _grandTotalsColumnPivotTable - 1, ms);
And the EPPlus code also retains the height/width ratio:
The original image is 199 pixels wide and 130 pixels high.
The EPPlus-plopped images are 1.33 X 2.05, so the ratio of 1.5:1 (close approximation) is retained.
The Aspose-plopped images, though, are 1.63 and 1.67 X 2.07, so the ratio is more like 1.25:1
So even with the AutoFitter jazz commented out of the Aspose code, the image still gets either squashed in width or stretched in height.
UPDATE 4
Based on a thread here, I tried this (afer copying the image to my bin folder):
int index = locationWorksheet.Pictures.Add(0, 4, 6, 5, "LogoFromSite.png");
Picture pic = locationWorksheet.Pictures[index];
pic.Placement = PlacementType.FreeFloating;
The first four arguments to [sheet].Pictures.Add() are Upper Left Row, Upper Left Column, Lower Right Row, and Lower Right Column.
However, this puts the image on the page in the right place, but then moves it to the left several columns (!?!)
UPDATE 5
I found another ray of hope here, and tried this code:
Aspose.Cells.Rendering.ImageOrPrintOptions opts = new Aspose.Cells.Rendering.ImageOrPrintOptions();
opts.OnePagePerSheet = true;
opts.ImageFormat = ImageFormat.Png;
opts.SetDesiredSize(199, 130);
Aspose.Cells.Rendering.SheetRender sr = new Aspose.Cells.Rendering.SheetRender(locationWorksheet, opts);
sr.ToImage(0, "LogoFromSite.png");
...but got this:
So: squashed again.
UPDATE 6
I tried some code provided by the Aspose Cells cats themselves, but they admitted there was a problem with it, and were looking into it. Just for grins, I gave it a shot to see what would transpire. This code:
byte[] bts1 = File.ReadAllBytes("LogoFromSite.png");
byte[] bts2 = File.ReadAllBytes("LogoFromSite.png");
MemoryStream ms1 = new MemoryStream();
ms1.Write(bts1, 0, bts1.Length);
ms1.Position = 0;
//This is for second picture in sheet2
MemoryStream ms2 = new MemoryStream();
ms2.Write(bts2, 0, bts2.Length);
ms2.Position = 0;
//Add picture in first worksheet
int idx = locationWorksheet.Pictures.Add(0, 4, ms1);
//Add picture in second worksheet with original size
idx = locationWorksheet.Pictures.Add(0, 10, ms2);
Picture pic = locationWorksheet.Pictures[idx];
pic.HeightScale = 100;
pic.WidthScale = 100;
...resulted in these "no image images":
UPDATE 7
I made another venture; as the height was being increased above and beyond 100%, I thought I would resize the image into another one, and use that:
var ms = new MemoryStream();
Image _logo = GetURLImage("http://www.proactusa.com/bla/pa_logo_notag.png");
double newHeightDbl = _logo.Height * 0.8;
int newHeightInt = (int)Math.Ceiling(newHeightDbl);
Image resizedImage = ResizeImage(_logo, newHeightInt, _logo.Width);
resizedImage.Save(ms, ImageFormat.Png);
ms.Position = 0;
locationWorksheet.Pictures.Add(0, 4, ms);
...but no! It stuffs the whole shebang into one measly column, like so:
...and gumbifies it galore vertically, thus making it look queasier than a lubber on a tempest-tossed tug.
Here is the (stolen/borrowed) code to resize the image:
// from http://stackoverflow.com/questions/1922040/resize-an-image-c-sharp
public static Bitmap ResizeImage(Image image, int width, int height)
{
var destRect = new Rectangle(0, 0, width, height);
var destImage = new Bitmap(width, height);
destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destImage;
}
Please check your thread in Aspose.Cells forum which answers two of your following questions.
1 - Can we reuse same memory stream object containing picture in workbooks and worksheets?
2 - How to add picture with original size?
Note: I am working as Developer Evangelist at Aspose
Simply a matter of commenting out the fancy-pants autofitting code:
//AutoFitterOptions options = new AutoFitterOptions { OnlyAuto = true };
//pivotTableSheet.AutoFitRows(options);
Now the image is displayed uniformly at pretty much its actual size (but note the caveat below); a scosh "spilly" at times, but if they complain about that, I'll create a second image, and resize it using this:
// from http://stackoverflow.com/questions/1922040/resize-an-image-c-sharp
public static Bitmap ResizeImage(Image image, int width, int height)
{
var destRect = new Rectangle(0, 0, width, height);
var destImage = new Bitmap(width, height);
destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destImage;
}
Caveat emptor: This works well enough that I am grudgingly accepting it, but the images placed on the sheet are not exactly the same size. One is 1.67" X 2.07", the other is 1.63" X 2.07" - close enough for horseshoes, hand-grenades, and images on Excel spreadsheets, I guess.

Scalr resize and crop to size

I would like to show an image in all sort of placements with different width and height.
I am using a method for crop and resize with Sclar,
But I have 2 problems:
The result doesn't look so good in some cases. I think it is because the image in the code is first scaled.
I get an exception in other cases. For example:
Invalid crop bounds: x [32], y [-1], width [64] and height [64] must
all be >= 0
What is the best way of resizing a cropping and image to some target width and height?
Here is my current method:
public static BufferedImage resizeAndCropToCenter(BufferedImage image, int width, int height) {
image = Scalr.resize(image, Scalr.Method.QUALITY, Scalr.Mode.FIT_TO_WIDTH,
width * 2, height * 2, Scalr.OP_ANTIALIAS);
int x, y;
int imageWidth = image.getWidth();
int imageHeight = image.getHeight();
if (imageWidth > imageHeight) {
x = width / 2;
y = (imageHeight - height) / 2;
} else {
x = (imageWidth - width) / 2;
y = height / 2;
}
return Scalr.crop(image, x, y, width, height);
}
In the resize method, you are always doing FIT_TO_WIDTH no matter what the dimensions are. Perhaps you should do something different depending on whether the image and the desired size are both portrait or landscape format. What do you aim to achieve here?
Instead of
y = (imageHeight - height) / 2;
use
y = Math.abs((imageHeight - height) / 2);
to make sure y is never negative. Do the same for x in the else block.

Noise on CCSprite

I made my project to show simple texture by using CCSprite.
But I found that the texture contains some tiny noise , black pixel bug.
I divided the png file into small piece by using code. And add it to the mainview.
Not all of them have noise, But some of them have it.
I can't know the reason.
Please send your opinion.
CCSprite *sprite = [[CCSprite spriteWithFile:[NSString stringWithUTF8String:name] rect:CGRectMake(startx, starty, w, h)] retain];
float drawX = x, drawY = y;
CGSize size = [sprite contentSize];
int nWidth = size.width;
int nHeight = size.height;
nWidth *= scale;
nHeight *= scale;
drawX = drawX + nWidth/2;
drawY = drawY - nHeight/2;
ConvertCoordf(&drawX, &drawY);
drawY -= nHeight;
[sprite setScale:scale];
[sprite setPosition:ccp(drawX, drawY)];
[_mainLayer addChild:sprite];
[sprite release];
For every image, it has some noise pixel around it (Only 1 pixel). For example, if you want to include an image with 30px*30px, you'd better make it into a 31px*31px image and put your image in the middle of it.In other words, surround your image with 1px.

Rotating an Image in Silverlight without cropping

I am currently working on a simple Silverlight app that will allow people to upload an image, crop, resize and rotate it and then load it via a webservice to a CMS.
Cropping and resizing is done, however rotation is causing some problems. The image gets cropped and is off centre after the rotation.
WriteableBitmap wb = new WriteableBitmap(destWidth, destHeight);
RotateTransform rt = new RotateTransform();
rt.Angle = 90;
rt.CenterX = width/2;
rt.CenterY = height/2;
//Draw to the Writeable Bitmap
Image tempImage2 = new Image();
tempImage2.Width = width;
tempImage2.Height = height;
tempImage2.Source = rawImage;
wb.Render(tempImage2,rt);
wb.Invalidate();
rawImage = wb;
message.Text = "h:" + rawImage.PixelHeight.ToString();
message.Text += ":w:" + rawImage.PixelWidth.ToString();
//Finally set the Image back
MyImage.Source = wb;
MyImage.Width = destWidth;
MyImage.Height = destHeight;
The code above only needs to rotate by 90° at this time so I'm just setting destWidth and destHeight to the height and width of the original image.
It looks like your target image is the same size as your source image. If you want to rotate over 90 degrees, your width and height should be exchanged:
WriteableBitmap wb = new WriteableBitmap(destHeight, destWidth);
Also, if you rotate about the centre of the original image, part of it will end up outside the boundaries. You could either include some translation transforms, or simply rotate the image about a different point:
rt.CenterX = rt.CenterY = Math.Min(width / 2, height / 2);
Try it with a piece of rectangular paper to see why that makes sense.
Many thanks to those above.. they helped a lot. I include here a simple example which includes the additional transform necessary to move the rotated image back to the top left corner of the result.
int width = currentImage.PixelWidth;
int height = currentImage.PixelHeight;
int full = Math.Max(width, height);
Image tempImage2 = new Image();
tempImage2.Width = full;
tempImage2.Height = full;
tempImage2.Source = currentImage;
// New bitmap has swapped width/height
WriteableBitmap wb1 = new WriteableBitmap(height,width);
TransformGroup transformGroup = new TransformGroup();
// Rotate around centre
RotateTransform rotate = new RotateTransform();
rotate.Angle = 90;
rotate.CenterX = full/2;
rotate.CenterY = full/2;
transformGroup.Children.Add(rotate);
// and transform back to top left corner of new image
TranslateTransform translate = new TranslateTransform();
translate.X = -(full - height) / 2;
translate.Y = -(full - width) / 2;
transformGroup.Children.Add(translate);
wb1.Render(tempImage2, transformGroup);
wb1.Invalidate();
If the image isn't square you will get cropping.
I know this won't give you exactly the right result, you'll need to crop it afterwards, but it will create a bitmap big enough in each direction to take the rotated image.
//Draw to the Writeable Bitmap
Image tempImage2 = new Image();
tempImage2.Width = Math.Max(width, height);
tempImage2.Height = Math.Max(width, height);
tempImage2.Source = rawImage;
You need to calculate the scaling based on the rotation of the corners relative to the centre.
If the image is a square only one corner is needed, but for a rectangle you need to check 2 corners in order to see if a vertical or horizontal edge is overlapped. This check is a linear comparison of how much the rectangle's height and width are exceeded.
Click here for the working testbed app created for this answer (image below):
double CalculateConstraintScale(double rotation, int pixelWidth, int pixelHeight)
The pseudo-code is as follows (actual C# code at the end):
Convert rotation angle into Radians
Calculate the "radius" from the rectangle centre to a corner
Convert BR corner position to polar coordinates
Convert BL corner position to polar coordinates
Apply the rotation to both polar coordinates
Convert the new positions back to Cartesian coordinates (ABS value)
Find the largest of the 2 horizontal positions
Find the largest of the 2 vertical positions
Calculate the delta change for horizontal size
Calculate the delta change for vertical size
Return width/2 / x if horizontal change is greater
Return height/2 / y if vertical change is greater
The result is a multiplier that will scale the image down to fit the original rectangle regardless of rotation.
**Note: While it is possible to do much of the maths using matrix operations, there are not enough calculations to warrant that. I also thought it would make a better example from first-principles.*
C# Code:
/// <summary>
/// Calculate the scaling required to fit a rectangle into a rotation of that same rectangle
/// </summary>
/// <param name="rotation">Rotation in degrees</param>
/// <param name="pixelWidth">Width in pixels</param>
/// <param name="pixelHeight">Height in pixels</param>
/// <returns>A scaling value between 1 and 0</returns>
/// <remarks>Released to the public domain 2011 - David Johnston (HiTech Magic Ltd)</remarks>
private double CalculateConstraintScale(double rotation, int pixelWidth, int pixelHeight)
{
// Convert angle to radians for the math lib
double rotationRadians = rotation * PiDiv180;
// Centre is half the width and height
double width = pixelWidth / 2.0;
double height = pixelHeight / 2.0;
double radius = Math.Sqrt(width * width + height * height);
// Convert BR corner into polar coordinates
double angle = Math.Atan(height / width);
// Now create the matching BL corner in polar coordinates
double angle2 = Math.Atan(height / -width);
// Apply the rotation to the points
angle += rotationRadians;
angle2 += rotationRadians;
// Convert back to rectangular coordinate
double x = Math.Abs(radius * Math.Cos(angle));
double y = Math.Abs(radius * Math.Sin(angle));
double x2 = Math.Abs(radius * Math.Cos(angle2));
double y2 = Math.Abs(radius * Math.Sin(angle2));
// Find the largest extents in X & Y
x = Math.Max(x, x2);
y = Math.Max(y, y2);
// Find the largest change (pixel, not ratio)
double deltaX = x - width;
double deltaY = y - height;
// Return the ratio that will bring the largest change into the region
return (deltaX > deltaY) ? width / x : height / y;
}
Example of use:
private WriteableBitmap GenerateConstrainedBitmap(BitmapImage sourceImage, int pixelWidth, int pixelHeight, double rotation)
{
double scale = CalculateConstraintScale(rotation, pixelWidth, pixelHeight);
// Create a transform to render the image rotated and scaled
var transform = new TransformGroup();
var rt = new RotateTransform()
{
Angle = rotation,
CenterX = (pixelWidth / 2.0),
CenterY = (pixelHeight / 2.0)
};
transform.Children.Add(rt);
var st = new ScaleTransform()
{
ScaleX = scale,
ScaleY = scale,
CenterX = (pixelWidth / 2.0),
CenterY = (pixelHeight / 2.0)
};
transform.Children.Add(st);
// Resize to specified target size
var tempImage = new Image()
{
Stretch = Stretch.Fill,
Width = pixelWidth,
Height = pixelHeight,
Source = sourceImage,
};
tempImage.UpdateLayout();
// Render to a writeable bitmap
var writeableBitmap = new WriteableBitmap(pixelWidth, pixelHeight);
writeableBitmap.Render(tempImage, transform);
writeableBitmap.Invalidate();
return writeableBitmap;
}
I released a Test-bed of the code on my website so you can try it for real - click to try it
P.S. Yes this is my answer from another question, duplicated exactly, but the question does require the same answer as that one to be complete.

BlackBerry - image 3D transform

I know how to rotate image on any angle with drawTexturePath:
int displayWidth = Display.getWidth();
int displayHeight = Display.getHeight();
int[] x = new int[] { 0, displayWidth, displayWidth, 0 };
int[] x = new int[] { 0, 0, displayHeight, displayHeight };
int angle = Fixed32.toFP( 45 );
int dux = Fixed32.cosd(angle );
int dvx = -Fixed32.sind( angle );
int duy = Fixed32.sind( angle );
int dvy = Fixed32.cosd( angle );
graphics.drawTexturedPath( x, y, null, null, 0, 0, dvx, dux, dvy, duy, image);
but what I need is a 3d projection of simple image with 3d transformation (something like this)
Can you please advice me how to do this with drawTexturedPath (I'm almost sure it's possible)?
Are there any alternatives?
The method used by this function(2 walk vectors) is the same as the oldskool coding tricks used for the famous 'rotozoomer' effect. rotozoomer example video
This method is a very fast way to rotate, zoom, and skew an image. The rotation is done simply by rotating the walk vectors. The zooming is done simply by scaling the walk vectors. The skewing is done by rotating the walkvectors in respect to one another (e.g. they don't make a 90 degree angle anymore).
Nintendo had made hardware in their SNES to use the same effect on any of the sprites and or backgrounds. This made way for some very cool effects.
One big shortcoming of this technique is that one can not perspectively warp a texture. To do this, every new horizontal line, the walk vectors should be changed slightly. (hard to explain without a drawing).
On the snes they overcame this by altering every scanline the walkvectors (In those days one could set an interrupt when the monitor was drawing any scanline). This mode was later referred to as MODE 7 (since it behaved like a new virtual kind of graphics mode). The most famous games using this mode were Mario kart and F-zero
So to get this working on the blackberry, you'll have to draw your image "displayHeight" times (e.g. Every time one scanline of the image). This is the only way to achieve the desired effect. (This will undoubtedly cost you a performance hit since you are now calling the drawTexturedPath function a lot of times with new values, instead of just one time).
I guess with a bit of googling you can find some formulas (or even an implementation) how to calc the varying walkvectors. With a bit of paper (given your not too bad at math) you might deduce it yourself too. I've done it myself too when I was making games for the Gameboy Advance so I know it can be done.
Be sure to precalc everything! Speed is everything (especially on slow machines like phones)
EDIT: did some googling for you. Here's a detailed explanation how to create the mode7 effect. This will help you achieve the same with the Blackberry function. Mode 7 implementation
With the following code you can skew your image and get a perspective like effect:
int displayWidth = Display.getWidth();
int displayHeight = Display.getHeight();
int[] x = new int[] { 0, displayWidth, displayWidth, 0 };
int[] y = new int[] { 0, 0, displayHeight, displayHeight };
int dux = Fixed32.toFP(-1);
int dvx = Fixed32.toFP(1);
int duy = Fixed32.toFP(1);
int dvy = Fixed32.toFP(0);
graphics.drawTexturedPath( x, y, null, null, 0, 0, dvx, dux, dvy, duy, image);
This will skew your image in a 45º angle, if you want a certain angle you just need to use some trigonometry to determine the lengths of your vectors.
Thanks for answers and guidance, +1 to you all.
MODE 7 was the way I choose to implement 3D transformation, but unfortunately I couldn't make drawTexturedPath to resize my scanlines... so I came down to simple drawImage.
Assuming you have a Bitmap inBmp (input texture), create new Bitmap outBmp (output texture).
Bitmap mInBmp = Bitmap.getBitmapResource("map.png");
int inHeight = mInBmp.getHeight();
int inWidth = mInBmp.getWidth();
int outHeight = 0;
int outWidth = 0;
int outDrawX = 0;
int outDrawY = 0;
Bitmap mOutBmp = null;
public Scr() {
super();
mOutBmp = getMode7YTransform();
outWidth = mOutBmp.getWidth();
outHeight = mOutBmp.getHeight();
outDrawX = (Display.getWidth() - outWidth) / 2;
outDrawY = Display.getHeight() - outHeight;
}
Somewhere in code create a Graphics outBmpGraphics for outBmp.
Then do following in iteration from start y to (texture height)* y transform factor:
1.create a Bitmap lineBmp = new Bitmap(width, 1) for one line
2.create a Graphics lineBmpGraphics from lineBmp
3.paint i line from texture to lineBmpGraphics
4.encode lineBmp to EncodedImage img
5.scale img according to MODE 7
6.paint img to outBmpGraphics
Note: Richard Puckett's PNGEncoder BB port used in my code
private Bitmap getMode7YTransform() {
Bitmap outBmp = new Bitmap(inWidth, inHeight / 2);
Graphics outBmpGraphics = new Graphics(outBmp);
for (int i = 0; i < inHeight / 2; i++) {
Bitmap lineBmp = new Bitmap(inWidth, 1);
Graphics lineBmpGraphics = new Graphics(lineBmp);
lineBmpGraphics.drawBitmap(0, 0, inWidth, 1, mInBmp, 0, 2 * i);
PNGEncoder encoder = new PNGEncoder(lineBmp, true);
byte[] data = null;
try {
data = encoder.encode(true);
} catch (IOException e) {
e.printStackTrace();
}
EncodedImage img = PNGEncodedImage.createEncodedImage(data,
0, -1);
float xScaleFactor = ((float) (inHeight / 2 + i))
/ (float) inHeight;
img = scaleImage(img, xScaleFactor, 1);
int startX = (inWidth - img.getScaledWidth()) / 2;
int imgHeight = img.getScaledHeight();
int imgWidth = img.getScaledWidth();
outBmpGraphics.drawImage(startX, i, imgWidth, imgHeight, img,
0, 0, 0);
}
return outBmp;
}
Then just draw it in paint()
protected void paint(Graphics graphics) {
graphics.drawBitmap(outDrawX, outDrawY, outWidth, outHeight, mOutBmp,
0, 0);
}
To scale, I've do something similar to method described in Resizing a Bitmap using .scaleImage32 instead of .setScale
private EncodedImage scaleImage(EncodedImage image, float ratioX,
float ratioY) {
int currentWidthFixed32 = Fixed32.toFP(image.getWidth());
int currentHeightFixed32 = Fixed32.toFP(image.getHeight());
double w = (double) image.getWidth() * ratioX;
double h = (double) image.getHeight() * ratioY;
int width = (int) w;
int height = (int) h;
int requiredWidthFixed32 = Fixed32.toFP(width);
int requiredHeightFixed32 = Fixed32.toFP(height);
int scaleXFixed32 = Fixed32.div(currentWidthFixed32,
requiredWidthFixed32);
int scaleYFixed32 = Fixed32.div(currentHeightFixed32,
requiredHeightFixed32);
EncodedImage result = image.scaleImage32(scaleXFixed32, scaleYFixed32);
return result;
}
See also
J2ME Mode 7 Floor Renderer - something much more detailed & exciting if you writing a 3D game!
You want to do texture mapping, and that function won't cut it. Maybe you can kludge your way around it but the better option is to use a texture mapping algorithm.
This involves, for each row of pixels, determining the edges of the shape and where on the shape those screen pixels map to (the texture pixels). It's not so hard actually but may take a bit of work. And you'll be drawing the pic only once.
GameDev has a bunch of articles with sourcecode here:
http://www.gamedev.net/reference/list.asp?categoryid=40#212
Wikipedia also has a nice article:
http://en.wikipedia.org/wiki/Texture_mapping
Another site with 3d tutorials:
http://tfpsly.free.fr/Docs/TomHammersley/index.html
In your place I'd seek out a simple demo program that did something close to what you want and use their sources as base to develop my own - or even find a portable source library, I´m sure there must be a few.

Resources