In my android studio project I am trying to select an image from external storage via startActivityForResult and load the selected image into memory. Also I have a BitmapLoader helper class. Here is the piece of code where I call the activity to get the result
private void pickFromGallery() {
//Create an Intent with action as ACTION_PICK
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
// Sets the type as image/*. This ensures only components of type image are selected
intent.setType("image/*");
//We pass an extra array with the accepted mime types. This will ensure only components with these MIME types as targeted.
String[] mimeTypes = {"image/jpeg", "image/png"};
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
// Launching the Intent
startActivityForResult(intent, GALLERY_REQUEST_CODE); //GALLERY_REQUEST_CODE is a constant integer
}
And here is the activity result callback
public void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Result code is RESULT_OK only if the user selects an Image
if(resultCode == Activity.RESULT_OK) {
Bitmap imageBitmap = null;
switch(requestCode) {
case GALLERY_REQUEST_CODE:
//data.getData returns the content URI for the selected Image
File file = new File(data.getData().getPath());
try {
//BitmapLoader is my helper class
imageBitmap = BitmapLoader.decodeSampleBitmapFromFile(file, 100, 100);
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(this, "Error while reading a file!", Toast.LENGTH_SHORT).show();
return;
}
userImage.setImageBitmap(imageBitmap);
break;
}
}
}
Finally, here is the BitmapLoader helper class.
public class BitmapLoader {
private BitmapLoader() {}
private static Bitmap rotateImageIfRequired(Bitmap img, File file) throws IOException {
ExifInterface ei = new ExifInterface(file);
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
return rotateImage(img, 90);
case ExifInterface.ORIENTATION_ROTATE_180:
return rotateImage(img, 180);
case ExifInterface.ORIENTATION_ROTATE_270:
return rotateImage(img, 270);
default:
return img;
}
}
private static Bitmap rotateImage(Bitmap img, int degree) {
Matrix matrix = new Matrix();
matrix.postRotate(degree);
Bitmap rotatedImg = Bitmap.createBitmap(img, 0, 0, img.getWidth(), img.getHeight(), matrix, true);
img.recycle();
return rotatedImg;
}
private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) >= reqHeight
&& (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize += 1;
}
}
return inSampleSize;
}
public static Bitmap decodeSampleBitmapFromFile(File file, int reqWidth, int reqHeight) throws IOException {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(file.getPath(), options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeFile(file.getPath(), options);
return rotateImageIfRequired(bitmap, file);
}
}
The problem is, when I call imageBitmap = BitmapLoader.decodeSampleBitmapFromFile(file, 100, 100); , it always throws an exception. I think the problem is the part where I create a File object from the Uri returned as a result. Can anyone please describe to me where the problem is coming from and help me write the correct code?
I found the right way to solve the problem. Here is the commented code describing the true way to solve the problem.
private void pickFromGallery() {
// intent with ACTION_OPEN_DOCUMENT to make
// content providers (gallery application, downloads application and so on)
// to show their files
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
//and that files must be openable
intent.addCategory(Intent.CATEGORY_OPENABLE);
//setting mime type to get only image files
intent.setType("image/*");
//just invoking intent
startActivityForResult(intent, GALLERY_REQUEST_CODE);
}
//getting picked image
public void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Result code is RESULT_OK only if the user selects an Image
if(resultCode == Activity.RESULT_OK) {
Bitmap imageBitmap;
switch(requestCode) {
case GALLERY_REQUEST_CODE:
if(data == null) return;
//ParcelFileDescriptor allowing you to close it when done with it.
ParcelFileDescriptor parcelFileDescriptor;
try {
//a method to get file descriptor via Uri(data.getData() returns a Uri, "r" means for reading)
parcelFileDescriptor = getContentResolver().openFileDescriptor(data.getData(), "r");
//getting a descriptor from ParcelFileDescriptor
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
// and sending that descriptor to BitmapLoader, which now takes only descriptor and required width and height to load bitmap
imageBitmap = BitmapLoader.decodeSampleBitmapFromDescriptor(fileDescriptor, 100, 100);
parcelFileDescriptor.close();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(this, "Error while reading a file!", Toast.LENGTH_SHORT).show();
return;
}
//here you can use the loaded bitmap as you like
userImage.setImageBitmap(imageBitmap);
break;
}
}
}
Finally the Bitmaploader class
public class BitmapLoader {
private BitmapLoader() {}
//this method uses ExifInterface to figure out how to rotate the image to bring it back to normal orientation, but that's another story.
private static Bitmap rotateImageIfRequired(Bitmap img, FileDescriptor descriptor) throws IOException {
ExifInterface ei = new ExifInterface(descriptor);
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
return rotateImage(img, 90);
case ExifInterface.ORIENTATION_ROTATE_180:
return rotateImage(img, 180);
case ExifInterface.ORIENTATION_ROTATE_270:
return rotateImage(img, 270);
default:
return img;
}
}
//just a helper for the previous method
private static Bitmap rotateImage(Bitmap img, int degree) {
Matrix matrix = new Matrix();
matrix.postRotate(degree);
Bitmap rotatedImg = Bitmap.createBitmap(img, 0, 0, img.getWidth(), img.getHeight(), matrix, true);
img.recycle();
return rotatedImg;
}
// calculates how many times a bitmap should be reduced
private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) >= reqHeight
&& (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize += 1;
}
}
return inSampleSize;
}
//main working method that throws an IOException because there might be problems reading the file
public static Bitmap decodeSampleBitmapFromDescriptor(#NonNull FileDescriptor descriptor, int reqWidth, int reqHeight) throws IOException {
// BitmapFactory.Options helps to load only the image information first.
final BitmapFactory.Options options = new BitmapFactory.Options();
// must set to true to load only the image information
options.inJustDecodeBounds = true;
/**null is just a padding*/
//loading into options the information about image
BitmapFactory.decodeFileDescriptor(descriptor, null, options);
// Calculation of the dimensions of the image for loading in accordance with the required width and height
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// now setting to false to load real bitmap with required dimensions
options.inJustDecodeBounds = false;
//decoding an image and returning a bitmap
Bitmap bitmap = BitmapFactory.decodeFileDescriptor(descriptor, null, options);
return rotateImageIfRequired(bitmap, descriptor);
}
}
It is very important to load the image into memory at a reduced size, because a bitmap of a real image may require over 500MB of RAM.
Related
EDIT:: Reading through this again now realize it isn’t very clear as to how the pictures were captured, how they’re being displayed, and why/what makes them different.
To that end— We are using AVCapture library to manually take photos within our app. We have a preview display in the app so the user can see what the image they’re taking looks like, just how any standard photo app these days does it. So what these two images are showing are the preview of the image on the screen, before the image is captured and the captured image. This was done by taking a screenshot of the preview and then a screenshot of the resulting capture image.
All this to say the captured image appears to be returned with differing dimensions or scaling attributes. We are displaying the preview and the resulting captures using a native iOS preview view and a Xamarin.Image respectively.
Below details our attempts at addressing the issue by changing sizing, layering, and stretching attributes to no avail.
To that end we’ve created a support ticket with MSFT regarding this issue.
These two images are the camera preview and the resulting capture (in that order, respectively [taken via screenshots]). We want the captured photo to match the preview/vice versa. How can we address this?
Tried manipulating the CALayer containing the photo data to size the image like how a Xamarin.Forms' image sizes with AspectFit by assigning the ContentsGravity with various options like kCAGravityResizeAspect. Fiddled with other Contents options such as ContentsRect and ContentsScale but no dice. Below is the View and its corresponding Renderer. So how to address the sizing issue?
Native Camera View
namespace App.iOS.Views
{
public class NativeCameraView : UIView
{
AVCaptureVideoPreviewLayer previewLayer;
CameraOptions cameraOptions;
public AVCaptureSession CaptureSession { get; private set; }
public AVCaptureStillImageOutput CaptureOutput { get; set; }
public bool IsPreviewing { get; set; }
public NativeCameraPreview(CameraOptions options)
{
cameraOptions = options;
IsPreviewing = false;
Initialize();
}
public override void LayoutSubviews()
{
base.LayoutSubviews();
UIDevice device = UIDevice.CurrentDevice;
UIDeviceOrientation orientation = device.Orientation;
AVCaptureConnection previewLayerConnection = this.previewLayer.Connection;
if (previewLayerConnection.SupportsVideoOrientation)
{
switch (orientation)
{
case UIDeviceOrientation.Portrait:
UpdatePreviewLayer(previewLayerConnection,
AVCaptureVideoOrientation.Portrait);
break;
case UIDeviceOrientation.LandscapeRight:
UpdatePreviewLayer(previewLayerConnection,
AVCaptureVideoOrientation.LandscapeLeft);
break;
case UIDeviceOrientation.LandscapeLeft:
UpdatePreviewLayer(previewLayerConnection,
AVCaptureVideoOrientation.LandscapeRight);
break;
case UIDeviceOrientation.PortraitUpsideDown:
UpdatePreviewLayer(previewLayerConnection,
AVCaptureVideoOrientation.PortraitUpsideDown);
break;
default:
UpdatePreviewLayer(previewLayerConnection,
AVCaptureVideoOrientation.Portrait);
break;
}
}
}
private void UpdatePreviewLayer(AVCaptureConnection layer,
AVCaptureVideoOrientation orientation)
{
layer.VideoOrientation = orientation;
previewLayer.Frame = this.Bounds;
}
public async Task CapturePhoto()
{
var videoConnection = CaptureOutput.ConnectionFromMediaType(AVMediaType.Video);
var sampleBuffer = await CaptureOutput.CaptureStillImageTaskAsync(videoConnection);
var jpegData = AVCaptureStillImageOutput.JpegStillToNSData(sampleBuffer);
var photo = new UIImage(jpegData);
var rotatedPhoto = RotateImage(photo, 180f);
CALayer layer = new CALayer
{
//ContentsGravity = "kCAGravityResizeAspect",
//ContentsRect = rect,
//GeometryFlipped = true,
ContentsScale = 1.0f,
Frame = Bounds,
Contents = rotatedPhoto.CGImage //Contents = photo.CGImage,
};
MainPage.UpdateSource(UIImageFromLayer(layer).AsJPEG().AsStream());
MainPage.UpdateImage(UIImageFromLayer(layer).AsJPEG().AsStream());
}
public UIImage RotateImage(UIImage image, float degree)
{
float Radians = degree * (float)Math.PI / 180;
UIView view = new UIView(frame: new CGRect(0, 0, image.Size.Width, image.Size.Height));
CGAffineTransform t = CGAffineTransform.MakeRotation(Radians);
view.Transform = t;
CGSize size = view.Frame.Size;
UIGraphics.BeginImageContext(size);
CGContext context = UIGraphics.GetCurrentContext();
context.TranslateCTM(size.Width / 2, size.Height / 2);
context.RotateCTM(Radians);
context.ScaleCTM(1, -1);
context.DrawImage(new CGRect(-image.Size.Width / 2, -image.Size.Height / 2, image.Size.Width, image.Size.Height), image.CGImage);
UIImage imageCopy = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
return imageCopy;
}
UIImage ImageFromLayer(CALayer layer)
{
UIGraphics.BeginImageContextWithOptions(
layer.Frame.Size,
layer.Opaque,
0);
layer.RenderInContext(UIGraphics.GetCurrentContext());
var outputImage = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
return outputImage;
}
void Initialize()
{
CaptureSession = new AVCaptureSession();
CaptureSession.SessionPreset = AVCaptureSession.PresetPhoto;
previewLayer = new AVCaptureVideoPreviewLayer(CaptureSession)
{
Frame = Bounds,
VideoGravity = AVLayerVideoGravity.ResizeAspectFill
};
var videoDevices = AVCaptureDevice.DevicesWithMediaType(AVMediaType.Video);
var cameraPosition = (cameraOptions == CameraOptions.Front) ? AVCaptureDevicePosition.Front : AVCaptureDevicePosition.Back;
var device = videoDevices.FirstOrDefault(d => d.Position == cameraPosition);
if (device == null)
{
return;
}
NSError error;
var input = new AVCaptureDeviceInput(device, out error);
var dictionary = new NSMutableDictionary();
dictionary[AVVideo.CodecKey] = new NSNumber((int)AVVideoCodec.JPEG);
CaptureOutput = new AVCaptureStillImageOutput()
{
OutputSettings = new NSDictionary()
};
CaptureSession.AddOutput(CaptureOutput);
CaptureSession.AddInput(input);
Layer.AddSublayer(previewLayer);
CaptureSession.StartRunning();
IsPreviewing = true;
}
}
}
Native Camera Renderer
[assembly: ExportRenderer(typeof(CameraView), typeof(CameraViewRenderer))]
namespace App.iOS.Renderers
{
public class CameraViewRenderer : ViewRenderer<CameraView, NativeCameraView>
{
NativeCameraView uiCameraView;
protected override void OnElementChanged(ElementChangedEventArgs<CameraView> e)
{
base.OnElementChanged(e);
if (Control == null)
{
uiCameraView = new NativeCameraView(e.NewElement.Camera);
SetNativeControl(uiCameraView);
}
if (e.OldElement != null)
{
// Unsubscribe
uiCameraView.Tapped -= OnCameraViewTapped;
}
if (e.NewElement != null)
{
// Subscribe
uiCameraView.Tapped += OnCameraViewTapped;
}
}
async void OnCameraViewTapped(object sender, EventArgs e)
{
await uiCameraView.CapturePhoto();
}
}
}
NOTE A similar question appears to have been asked quite some time ago.
Hello am new to Android studio
I have made recylerview for transaction details . I need to create pdf for this recylerview items.
Example: I have 24 cardviews in recylerview so need to create pdf with each page 4 cardviews only . So totally I need to get pdf as 6 pages .
How to do that . Thanks in advance.
This is sample image of my view
Am passing below code
recyclerView.measure(View.MeasureSpec.makeMeasureSpec(recyclerView.getWidth(),View.MeasureSpec.EXACTLY),View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED));
Bitmap bm=Bitmap.createBitmap(recyclerView.getWidth(),recyclerView.getMeasuredHeight(),Bitmap.Config.ARGB_8888);
String mpath2="/mnt/sdcard/mathanpaymentpdf";
File imageFile = new File(mpath2);
PDFHelper pdfHelper = new PDFHelper(imageFile,this);
pdfHelper.saveImageToPDF(recyclerView,bm,"mathan"+System.currentTimeMillis());
public class PDFHelper {
private File mFolder;
private File mFile;
private Context mContext;
public PDFHelper(File folder, Context context) {
this.mContext = context;
this.mFolder = folder;
if(!mFolder.exists())
mFolder.mkdirs();
}
public void saveImageToPDF(View title, Bitmap bitmap, String filename) {
mFile = new File(mFolder, filename + ".pdf");
if (!mFile.exists()) {
int height = title.getHeight() + bitmap.getHeight();
PdfDocument document = new PdfDocument();
PdfDocument.PageInfo pageInfo = new PdfDocument.PageInfo.Builder(bitmap.getWidth(), height, 1).create();
PdfDocument.Page page = document.startPage(pageInfo);
Canvas canvas = page.getCanvas();
title.draw(canvas);
canvas.drawBitmap(bitmap, null, new Rect(0, title.getHeight(), bitmap.getWidth(),bitmap.getHeight()), null);
document.finishPage(page);
try {
mFile.createNewFile();
OutputStream out = new FileOutputStream(mFile);
document.writeTo(out);
document.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
This am tried am getting pdf on a single page only
Just I need to split into multiple pages.
Note: I need code in java, not in kotlin
Am solved this by using itext library
implementation 'com.itextpdf:itextpdf:5.0.6'
Then call with RecylerView
public void generatePDF(RecyclerView view) {
RecyclerView.Adapter adapter = view.getAdapter();
int sie2=adapter.getItemCount();
if (sie2 == 0) {
Toast.makeText(this,"No Transactions",Toast.LENGTH_LONG).show();
}else{
Bitmap bigBitmap = null;
if (adapter != null) {
int size = adapter.getItemCount();
int height = 0;
Paint paint = new Paint();
int iHeight = 0;
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
// Use 1/8th of the available memory for this memory cache.
final int cacheSize = maxMemory / 8;
LruCache<String, Bitmap> bitmaCache = new LruCache<>(cacheSize);
for (int i = 0; i < size; i++) {
RecyclerView.ViewHolder holder = adapter.createViewHolder(view, adapter.getItemViewType(i));
adapter.onBindViewHolder(holder, i);
holder.itemView.measure(View.MeasureSpec.makeMeasureSpec(view.getWidth(), View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
holder.itemView.layout(0, 0, holder.itemView.getMeasuredWidth(), holder.itemView.getMeasuredHeight());
holder.itemView.setDrawingCacheEnabled(true);
holder.itemView.buildDrawingCache();
Bitmap drawingCache = holder.itemView.getDrawingCache();
if (drawingCache != null) {
bitmaCache.put(String.valueOf(i), drawingCache);
}
height += holder.itemView.getMeasuredHeight();
}
bigBitmap = Bitmap.createBitmap(view.getMeasuredWidth(), height, Bitmap.Config.ARGB_8888);
Canvas bigCanvas = new Canvas(bigBitmap);
bigCanvas.drawColor(Color.WHITE);
Document document=new Document();
final File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "MAT"+System.currentTimeMillis()+".pdf");
try {
PdfWriter.getInstance(document, new FileOutputStream(file));
} catch (DocumentException | FileNotFoundException e) {
e.printStackTrace();
}
for (int i = 0; i < size; i++) {
try {
//Adding the content to the document
Bitmap bmp = bitmaCache.get(String.valueOf(i));
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
com.itextpdf.text.Image image= com.itextpdf.text.Image.getInstance(stream.toByteArray());
//Image image = Image.getInstance(stream.toByteArray());
float scaler = ((document.getPageSize().getWidth() - document.leftMargin()
- document.rightMargin() - 50) / image.getWidth()) * 100; // 0 means you have no indentation. If you have any, change it.
image.scalePercent(scaler);
image.setAlignment(com.itextpdf.text.Image.ALIGN_CENTER | com.itextpdf.text.Image.ALIGN_TOP);
if (!document.isOpen()) {
document.open();
}
document.add(image);
} catch (Exception ex) {
Log.e("TAG-ORDER PRINT ERROR", ex.getMessage());
}
}
if (document.isOpen()) {
document.close();
}
// Set on UI Thread
runOnUiThread(new Runnable() {
#Override
public void run() {
android.app.AlertDialog.Builder builder = new android.app.AlertDialog.Builder(MainActivityAdminMain.this);
builder.setTitle("Success")
.setMessage("PDF File Generated Successfully.")
.setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton("Open", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// dialog.dismiss();
Intent target = new Intent(Intent.ACTION_VIEW);
target.setDataAndType(Uri.fromFile(file), "application/pdf");
target.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
Intent intent56 = Intent.createChooser(target, "Open File");
try {
startActivity(intent56);
} catch (ActivityNotFoundException e) {
Toast.makeText(MainActivityAdminMain.this,"No PDF Viewer Installed.",Toast.LENGTH_LONG).show();
}
}
}).show();
}
});
}}
}
100% working.. This helps to anyone needs
Related post: Stride of the BitmapData is different than the original
dimension.
I have taken the source code from here and modified it.
The code is generating a variety of exceptions in different occasions.
.
Error in BitmapLocker.cs
At the following line in Lock(),
// Copy data from IntegerPointer to _imageData
Marshal.Copy(IntegerPointer, _imageData, 0, _imageData.Length);
The following exception is being generated:
An unhandled exception of type 'System.AccessViolationException'
occurred in mscorlib.dll
Additional information: Attempted to read or write protected memory.
This is often an indication that other memory is corrupt.
For the following driver code,
double[,] mask = new double[,]
{
{ .11, .11, .11, },
{ .11, .11, .11, },
{ .11, .11, .11, },
};
Bitmap bitmap = ImageDataConverter.ToBitmap(mask);
BitmapLocker locker = new BitmapLocker(bitmap);
locker.Lock();
for (int i = 0; i < bitmap.Width; i++)
{
for (int j = 0; j < bitmap.Height; j++)
{
Color c = locker.GetPixel(i, j);
locker.SetPixel(i, j, c);
}
}
locker.Unlock();
At the following line in GetPixel(),
if (i > dataLength)
{
throw new IndexOutOfRangeException();
}
An unhandled exception of type 'System.IndexOutOfRangeException'
occurred in Simple.ImageProcessing.Framework.dll
Additional information: Index was outside the bounds of the array.
.
At the following line in SetPixel(),
if (ColorDepth == 8)
{
_imageData[i] = color.B;
}
An unhandled exception of type 'System.Exception' occurred in
Simple.ImageProcessing.Framework.dll
Additional information: (0, 0), 262144, Index was outside the bounds
of the array., i=262144
.
Error in Driver program
At the line,
Color c = bmp.GetPixel(i, j);
An unhandled exception of type 'System.InvalidOperationException'
occurred in System.Drawing.dll
Additional information: Bitmap region is already locked.
Source Code:
public class BitmapLocker : IDisposable
{
//private properties
Bitmap _bitmap = null;
bool _isLocked = false;
BitmapData _bitmapData = null;
private byte[] _imageData = null;
//public properties
public IntPtr IntegerPointer { get; private set; }
public int Width { get { return _bitmap.Width; } }
public int Height { get { return _bitmap.Height; } }
public int Stride { get { return _bitmapData.Stride; } }
public int ColorDepth { get { return Bitmap.GetPixelFormatSize(_bitmap.PixelFormat); } }
public int Channels { get { return ColorDepth / 8; } }
public int PaddingOffset { get { return _bitmapData.Stride - (_bitmap.Width * Channels); } }
public PixelFormat ImagePixelFormat { get { return _bitmap.PixelFormat; } }
public bool IsGrayscale { get { return Grayscale.IsGrayscale(_bitmap); } }
//Constructor
public BitmapLocker(Bitmap source)
{
IntegerPointer = IntPtr.Zero;
this._bitmap = source;
}
/// Lock bitmap
public void Lock()
{
if (_isLocked == false)
{
try
{
// Lock bitmap (so that no movement of data by .NET framework) and return bitmap data
_bitmapData = _bitmap.LockBits(
new Rectangle(0, 0, _bitmap.Width, _bitmap.Height),
ImageLockMode.ReadWrite,
_bitmap.PixelFormat);
// Create byte array to copy pixel values
int noOfBitsNeededForStorage = _bitmapData.Stride * _bitmapData.Height;
int noOfBytesNeededForStorage = noOfBitsNeededForStorage / 8;
_imageData = new byte[noOfBytesNeededForStorage * ColorDepth];//# of bytes needed for storage
IntegerPointer = _bitmapData.Scan0;
// Copy data from IntegerPointer to _imageData
Marshal.Copy(IntegerPointer, _imageData, 0, _imageData.Length);
_isLocked = true;
}
catch (Exception)
{
throw;
}
}
else
{
throw new Exception("Bitmap is already locked.");
}
}
/// Unlock bitmap
public void Unlock()
{
if (_isLocked == true)
{
try
{
// Copy data from _imageData to IntegerPointer
Marshal.Copy(_imageData, 0, IntegerPointer, _imageData.Length);
// Unlock bitmap data
_bitmap.UnlockBits(_bitmapData);
_isLocked = false;
}
catch (Exception)
{
throw;
}
}
else
{
throw new Exception("Bitmap is not locked.");
}
}
public Color GetPixel(int x, int y)
{
Color clr = Color.Empty;
// Get color components count
int channels = ColorDepth / 8;
// Get start index of the specified pixel
int i = (Height - y - 1) * Stride + x * channels;
int dataLength = _imageData.Length - channels;
if (i > dataLength)
{
throw new IndexOutOfRangeException();
}
if (ColorDepth == 32) // For 32 bpp get Red, Green, Blue and Alpha
{
byte b = _imageData[i];
byte g = _imageData[i + 1];
byte r = _imageData[i + 2];
byte a = _imageData[i + 3]; // a
clr = Color.FromArgb(a, r, g, b);
}
if (ColorDepth == 24) // For 24 bpp get Red, Green and Blue
{
byte b = _imageData[i];
byte g = _imageData[i + 1];
byte r = _imageData[i + 2];
clr = Color.FromArgb(r, g, b);
}
if (ColorDepth == 8)
// For 8 bpp get color value (Red, Green and Blue values are the same)
{
byte c = _imageData[i];
clr = Color.FromArgb(c, c, c);
}
return clr;
}
public void SetPixel(int x, int y, Color color)
{
// Get color components count
int cCount = ColorDepth / 8;
// Get start index of the specified pixel
int i = ((Height - y -1) * Stride + x * cCount);
try
{
if (ColorDepth == 32) // For 32 bpp set Red, Green, Blue and Alpha
{
_imageData[i] = color.B;
_imageData[i + 1] = color.G;
_imageData[i + 2] = color.R;
_imageData[i + 3] = color.A;
}
if (ColorDepth == 24) // For 24 bpp set Red, Green and Blue
{
_imageData[i] = color.B;
_imageData[i + 1] = color.G;
_imageData[i + 2] = color.R;
}
if (ColorDepth == 8)
// For 8 bpp set color value (Red, Green and Blue values are the same)
{
_imageData[i] = color.B;
}
}
catch(Exception ex)
{
throw new Exception("("+x+", "+y+"), "+_imageData.Length+", "+ ex.Message+", i=" + i);
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// free managed resources
_bitmap = null;
_bitmapData = null;_imageData = null;IntegerPointer = IntPtr.Zero;
}
// free native resources if there are any.
//private properties
//public properties
}
}
.
ImageDataConverter.cs
public static Bitmap ToBitmap(double[,] input)
{
int width = input.GetLength(0);
int height = input.GetLength(1);
Bitmap output = Grayscale.CreateGrayscaleImage(width, height);
BitmapData data = output.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.WriteOnly,
output.PixelFormat);
int pixelSize = System.Drawing.Image.GetPixelFormatSize(PixelFormat.Format8bppIndexed) / 8;
int offset = data.Stride - width * pixelSize;
double Min = 0.0;
double Max = 255.0;
unsafe
{
byte* address = (byte*)data.Scan0.ToPointer();
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
double v = 255 * (input[x, y] - Min) / (Max - Min);
byte value = unchecked((byte)v);
for (int c = 0; c < pixelSize; c++, address++)
{
*address = value;
}
}
address += offset;
}
}
output.UnlockBits(data);
return output;
}
Here is the picture I used for the test,
int noOfBitsNeededForStorage = _bitmapData.Stride * _bitmapData.Height;
That is the most essential bug in the code. Stride * Height are the number of bytes needed for storage. So it doesn't make the _imageData array large enough and IndexOutOfRangeException is the expected outcome.
int pixelSize = System.Drawing.Image.GetPixelFormatSize(PixelFormat.Format8bppIndexed) / 8;
Lots of possible mishaps from this statement. It hard-codes the pixel format to 8bpp but that is not the actual pixel format that the LockBits() call used. Which was output.PixelFormat. Notably fatal on the sample image, although it is not clear how it is used in the code, 8bpp is a very awkward pixel format since it requires a palette. The PNG codec will create a 32bpp image in memory, even though the original file uses 8bpp. You must use output.PixelFormat here to get a match with the locked data and adjust the pixel writing code accordingly. Not clear why it is being used at all, the SetPixel() method provided by the library code should already be good enough.
int dataLength = _imageData.Length - channels;
Unclear what that statement tries to do, subtracting the number of channels is not a sensible operation. It will generate a spurious IndexOutOfRangeException. There is no obvious reason to help, the CLR already provides array index checking on the _imageData array. So just delete that code.
Additional information: Bitmap region is already locked.
Exception handling in the code is not confident, a possible reason for this exception. In general it must be noted that the underlying bitmap is completely inaccessible, other than through _imageData, after the Lock() method was called and Unlock() wasn't called yet. Best way to do this is with try/finally with the Unlock() call in the finally block so you can always be sure that the bitmap doesn't remain locked by accident.
byte c = _imageData[i];
This is not correct, except in the corner case of an 8bpp image that has a palette that was explicitly created to handle grayscale images. The default palette for an 8bpp image does not qualify that requirement nor is it something you can blindly rely on when loading images from a file. Indexed pixel formats where a dreadful hack that was necessary in the early 1990s because video adapters where not yet powerful enough. It no longer makes any sense at all today. Note that SetPixel() also doesn't handle a 16-bit pixel formats. And that the PNG codec will never create an 8bpp memory image and cannot encode an 8bpp file. Best advice is to eliminate 8bpp support completely to arrive at more reliable code.
In fact, the point of directly accessing pixel data is to make image manipulation fast. There is only one pixel format that consistently produces fast code, it is Format32bppArgb. The pixels can now be accessed with an int* instead of a byte*, moving pixels ~4 times faster. And no special tweaks are necessary to deal with stride or special-case the code for methods like SetPixel(). So pass that format into LockBits(), the codec will do the work necessary if the actual image format is not 32bpp as well.
I should note that Format32bppPArgb is the fast pixel format for displaying images on the screen since it is compatible with the pixel format used by all modern video adapters. But that isn't the point of this code and dealing with the pre-multiplied alpha is awkward.
i need to print the part of the windows form in pdf or in word can any one help me out..
i have tried this code this is printing only 1st half of the form.
and also it is its displaying preview in image in word.
private System.IO.Stream streamToPrint;
string streamType;
[System.Runtime.InteropServices.DllImportAttribute("gdi32.dll")]
private static extern bool BitBlt
(
IntPtr hdcDest, // handle to destination DC
int nXDest, // x-coord of destination upper-left corner
int nYDest, // y-coord of destination upper-left corner
int nWidth, // width of destination rectangle
int nHeight, // height of destination rectangle
IntPtr hdcSrc, // handle to source DC
int nXSrc, // x-coordinate of source upper-left corner
int nYSrc, // y-coordinate of source upper-left corner
System.Int32 dwRop // raster operation code
);
private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
System.Drawing.Image image = System.Drawing.Image.FromStream(this.streamToPrint);
int x = -200;
int y = -50;
int width = image.Width / 4;
int height = image.Height;
if ((width / e.MarginBounds.Width) > (height / e.MarginBounds.Height))
{
width = e.MarginBounds.Width;
height = image.Height * e.MarginBounds.Width / image.Width;
}
else
{
height = e.MarginBounds.Height;
width = image.Width * e.MarginBounds.Height / image.Height;
}
System.Drawing.Rectangle destRect = new System.Drawing.Rectangle(x, y, width, height);
e.Graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, System.Drawing.GraphicsUnit.Pixel);
}
private void button1_Click(object sender, EventArgs e)
{
}
public void StartPrint(Stream streamToPrint, string streamType)
{
this.printDocument1.PrintPage += new PrintPageEventHandler(printDocument1_PrintPage);
this.streamToPrint = streamToPrint;
this.streamType = streamType;
System.Windows.Forms.PrintDialog PrintDialog1 = new PrintDialog();
PrintDialog1.AllowSomePages = true;
PrintDialog1.ShowHelp = true;
PrintDialog1.Document = printDocument1;
DialogResult result = PrintDialog1.ShowDialog();
if (result == DialogResult.OK)
{
printDocument1.Print();
}
}
//public Form1()
//{
// InitializeComponent();
//}
private void preview_Click(object sender, EventArgs e)
{
String filename = System.IO.Path.GetTempFileName();
Graphics g1 = this.CreateGraphics();
Image MyImage = new Bitmap(this.ClientRectangle.Width, this.ClientRectangle.Height, g1);
Graphics g2 = Graphics.FromImage(MyImage);
IntPtr dc1 = g1.GetHdc();
IntPtr dc2 = g2.GetHdc();
BitBlt(dc2, 0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height, dc1, 0, 0, 13369376);
g1.ReleaseHdc(dc1);
g2.ReleaseHdc(dc2);
MyImage.Save(filename, ImageFormat.Png);
FileStream fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
StartPrint(fileStream, "Image");
fileStream.Close();
if (System.IO.File.Exists(filename))
{
System.IO.File.Delete(filename);
}
}
I want to make the clock application where user enters the number in the textbox and click ok then user get the number at every 1 sec.
Example if user enter 5 then the timer start the display screen shows the number 1,2,3,4,5,0,1,2,3,4,5,0,1,2,3,...so on.
Now i had taken form and text field for user to enter the number,then a timer which will change the number at every second.and 10 images of number (0-9).As i want to dispaly the number in very large size.Now i had implement this logic in below way:-
public class Clock extends MIDlet implements CommandListener {
public Command GO, Exit;
TextField TxtData;
protected Display display;
int number, counter;
Form form;
private Timer timer;
private TestTimerTask task;
boolean increment, time;
private StringItem s1 = new StringItem("", "");
Image image0;
Image image1;
Image image2;
Image image3;
Image image4;
Image image5;
Image image6;
Image image7;
Image image8;
Image image9;
Image[] secondAnimation;
protected void startApp() {
display = Display.getDisplay(this);
increment = true;
time = false;
form = new Form("Clock");
TxtData = new TextField("Number:-", "", 5, TextField.NUMERIC);
try {
image0 = Image.createImage("/images/0.png");
image1 = Image.createImage("/images/1.png");
image2 = Image.createImage("/images/2.png");
image3 = Image.createImage("/images/3.png");
image4 = Image.createImage("/images/4.png");
image5 = Image.createImage("/images/5.png");
image6 = Image.createImage("/images/6.png");
image7 = Image.createImage("/images/7.png");
image8 = Image.createImage("/images/8.png");
image9 = Image.createImage("/images/9.png");
secondAnimation = new Image[]{image0,image1,image2, image3, image4, image5, image6, image7, image8, image9};
} catch (IOException ex) {
System.out.println("exception");
}
GO = new Command("Go", Command.OK, 1);
Exit = new Command("Exit", Command.EXIT, 2);
form.append(TxtData);
form.append(s1);
form.addCommand(GO);
form.addCommand(Exit);
form.setCommandListener(this);
display.setCurrent(form);
}
protected void pauseApp() {
}
protected void destroyApp(boolean unconditional) {
timer.cancel();
notifyDestroyed();
}
public void commandAction(Command cmnd, Displayable dsplbl) {
String label = cmnd.getLabel();
if (label.equals("Go")) {
try {
System.out.println("txt==" + (TxtData.getString()));
if (!TxtData.getString().equalsIgnoreCase("")) {
counter = Integer.parseInt(TxtData.getString());
if (time) {
timer.cancel();
task.cancel();
}
number = 1;
timer = new Timer();
task = new TestTimerTask();
timer.schedule(task, 1000, 1000);
}
} catch (NumberFormatException ex) {
System.out.println("exception");
}
} else if (label.equals("Exit")) {
destroyApp(true);
}
}
private class TestTimerTask extends TimerTask {
public final void run() {
time = true;
s1.setText(""+ number);
if (counter < 10) {
form.append(secondAnimation[0]);
form.append(secondAnimation[0]);
form.append(secondAnimation[number]);
} else if (counter < 100) {
form.append(secondAnimation[0]);
form.append(secondAnimation[(number % 100) / 10]);
form.append(secondAnimation[(number % 10)]);
} else if (counter < 1000) {
form.append(secondAnimation[(number % 10)]);
form.append(secondAnimation[(number % 100) / 10]);
form.append(secondAnimation[(number / 100)]);
}
number++;
if (number == counter + 1) {
number = 0;
}
}
} }
But as the form goes on appending the image as timer moves it is not showing the desired output!
I had tried to do it through LWUIT but as i had user 10 .png files and adding LWUIT.jar file make the size of .jar file 557kb which is very heavy.
So i want to do it through normal forms only.
I cant use canvas as the keypad can vary like (touch,qwerty etc).So i need to do normal form or LWUIT only.Can anyone please help me for this.
I noticed you only append items but never remove - is that intended?
Also, did you try two different forms to animate instead of one? For simple test, say, fill them in parallel, just call setCurrent for one that is not displayed in the moment of update
//...
private void appendTwice(Image image) {
form1.append(image);
form2.append(image);
}
//...
public final void run() {
time = true;
s1.setText(""+ number);
if (counter < 10) {
appendTwice(secondAnimation[0]);
//...
}
display.setCurrent(number & 1 == 0 ? form1 : form2);
number++;
//...
}
//...