I want to write a simple code - resize function without library. I must use getPixel and setPixel, result may be without normal quality. But I don't know how make it.
fun resuzeimage(bitmap:Bitmap,newWidth,newHeight){
for (j in 0 until bitmap.height) {
for (i in 0 until butmap.width) {
///code
}
}
}
Pleas, help me
fun resizeImage(yourBitmap: Bitmap, newWidth :Int, newHeight :Int):Bitmap
{
var resized = Bitmap.createScaledBitmap(yourBitmap!!, newWidth, newHeight, true)
return resized
}
You can change height and width return type as per your need.
Related
Given a file (which of course is an Image) in Android i want to make a preview image which of course should be smaller in size. I use the code below
override fun createImagePreview(serverId: Long, fileName: String) {
if (fileName.fileType() != IMAGE_TYPE) return
val file = serverDir.getFileByName(fileName)
val originalBitmap = BitmapFactory.decodeFile(file.absolutePath) ?: return
var newWidth = DEFAULT_IMAGE_SIZE.toDouble()
var newHeight = DEFAULT_IMAGE_SIZE.toDouble()
if (originalBitmap.width > originalBitmap.height) {
val ratio = originalBitmap.width / originalBitmap.height
newHeight = newWidth / ratio
} else if (originalBitmap.width < originalBitmap.height) {
val ratio = originalBitmap.height / originalBitmap.width
newWidth = newHeight / ratio
}
val bmp = ThumbnailUtils.extractThumbnail(
originalBitmap,
newWidth.toInt().dpToPixel(appContext),
newHeight.toInt().dpToPixel(appContext)
)
FileOutputStream(File(serverDir, "p_$fileName")).use {
it.write(bmp.toByteArray())
it.flush()
}
}
However, i see inside my internalStorage that if the File is 5KB then the PreviewFile is 19KB. What is wrong with that?
bmp.toByteArray is the wrong way to store an image. The Bitmap object is uncompressed. That means it uses 4 bytes per pixel. A jpg or png is compressed, that means it uses less data per pixel. You want to store it in one of those formats. The way to do that is to use Bitmap.compress() and pass it a stream to the file you want to use.
I am developing an Android app using Kotlin.
I need to convert a layout (that is actually a report of the user's input data, some views converted to bitmap in imageviews and extra text) and send it by email as .pdf when the user clicks on a button inside the fragment (that is the previsualisation of the future PDF) without saving it.
I've read and watched hours of tutorials but none is helping (deprecated, old java or saving the file)
I guess I need a function that converts the desired view to a bitmap image, scales it to A4 size format, sets that scaled image to pdf file and returns it so I can then put it as an attachment to mail Intent,not forgetting I am inside a fragment.
I will be updating the post.
Thank you
EDIT : I already know how to convert a layout to bitmap and put it inside an image view (I can share if someone needs). So I only need a function that takes the bitmap as an argument and returns .pdf (or .jpg) and an other one that intents as attachment that returned pdf to send email
What I gather, you need to create a screenshot of sorts of your view.
This is something I did a while back so I have some java code, not yet converted to Kotlin, but AS can take care of that.
You can utilise a class PixelCopy, unfortunately it is Android O +.
This is a simplified version of what you can do:
int[] viewLocationInWindow = new int[2];
view.getLocationInWindow(viewLocationInWindow);
int x = viewLocationInWindow[0];
int y = viewLocationInWindow[1];
int width = view.getWidth();
int height = view.getHeight();
Rect rectScope = new Rect(x, y, x + width, y + height);
Bitmap screenshotBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Handler handler = new Handler();
PixelCopy.request(getWindow(), rectScope, screenshotBitmap, copyResult -> {
if (copyResult == PixelCopy.SUCCESS) {
listener.onScreenshotSuccess(screenshotBitmap);
} else {
listener.onScreenshotError();
}
handler.removeCallbacksAndMessages(null);
}, handler);
The view that is being referenced here should be your containing view. In my case, I had to take a screenshot of the entire view(the entire screen), so instead I did:
int width = Resources.getSystem().getDisplayMetrics().widthPixels;
int height = Resources.getSystem().getDisplayMetrics().heightPixels;
Then just implement the listener
public interface OnScreenshotTakenListener {
void onScreenshotSuccess(Bitmap bitmap);
void onScreenshotError();
}
Inside onScreenshotSuccess you could modify the bitmap and do all of your other requirements.
fun getDetailImage(){
val image=getBitmapFromView(llParent)
ivShareImage.setImageBitmap(image)
}
private fun getBitmapFromView(view: View): Bitmap? {
//Define a bitmap with the same size as the view
val returnedBitmap=Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888)
//Bind a canvas to it
val canvas=Canvas(returnedBitmap)
//Get the view's background
val bgDrawable=view.background
if (bgDrawable != null) {
//has background drawable, then draw it on the canvas
bgDrawable.draw(canvas)
} else {
//does not have background drawable, then draw white background on the canvas
canvas.drawColor(Color.WHITE)
}
// draw the view on the canvas
view.draw(canvas)
//return the bitmap
return returnedBitmap
}
fun getShareImage(){
getDetailImage()
val mDrawable: Drawable=ivShareImage.getDrawable()
val mBitmap=(mDrawable as BitmapDrawable).bitmap
val path=MediaStore.Images.Media.insertImage(
appCompatActivity.getContentResolver(),
mBitmap,
"image-name",
null
)
val uri: Uri=Uri.parse(path)
val shareIntent=Intent()
shareIntent.action=Intent.ACTION_SEND
shareIntent.putExtra(Intent.EXTRA_STREAM, uri)
shareIntent.type="image/*"
appCompatActivity.startActivity(Intent.createChooser(shareIntent, "Share Image"))
}
I want to be able to get the exact image for analysis step as I get in preview.
I have preview use case:
val metrics = DisplayMetrics().also { binding.codeScannerView.display.getRealMetrics(it) }
val screenAspectRatio = Rational(metrics.widthPixels, metrics.heightPixels)
val previewConfig = PreviewConfig.Builder().apply {
setTargetAspectRatio(screenAspectRatio)
}.build()
And next to it I have analysis use case config:
val analyzerConfig = ImageAnalysisConfig.Builder().apply {
setTargetResolution(Size(metrics.heightPixels, metrics.widthPixels))
setTargetAspectRatio(screenAspectRatio)
val analyzerThread = HandlerThread(
"QrCodeReader").apply { start() }
setCallbackHandler(Handler(analyzerThread.looper))
setImageReaderMode(
ImageAnalysis.ImageReaderMode.ACQUIRE_LATEST_IMAGE)
}.build()
My preview is fullscreen so it's size is 1440x2560. But if I try to get dimensions from ImageProxy in analyzer, I get 1920x1050 which seems to have incorrect dimensions and switched width with height. Why is that and how can I force my analysis step to have same dimensions as full screen?
Intro:
implementation 'androidx.camera:camera-core:1.0.0-alpha10'
implementation 'androidx.camera:camera-camera2:1.0.0-alpha10'
implementation "androidx.camera:camera-lifecycle:1.0.0-alpha10"
implementation "androidx.camera:camera-view:1.0.0-alpha07"
implementation 'com.google.firebase:firebase-ml-vision:24.0.1'
implementation 'com.google.firebase:firebase-ml-vision-barcode-model:16.0.2'
I am solve this issue via the method FirebaseVisionImage.fromBitmap(bitmap)
where bitmap - manual cropped && rotated image according to preview configuration.
The steps are:
when you setup ImageAnalysis.Builder() && Preview.Builder()
obtain the on-screen rendered size for
androidx.camera.view.PreviewView element:
previewView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
val previewSize = Size(previewView.width, previewView.height)
Then pass the size into your own ImageAnalysis.Analyzer
implementation (let's say it will be viewFinderSize variable, usage see below)
when override fun analyze(mediaImage: ImageProxy){ occurs, do the manual crop of received ImageProxy. I am use the snippet from another SO question about distorted YUV_420_888 image: https://stackoverflow.com/a/45926852/2118862
When you do the cropping, keep in mind that ImageAnalysis use case receive image aligned in vertical-middle basis within your preview use case. In other words, received image, after rotation will be vertically centred as if it will be inside your preview area (even if your preview area is smaller than the image passed into analysis). So, crop area should be calculated in both directions from the vertical center: up and down.
The vertical size of the crop (height) should be manually calculated on the horizontal size basis. This means, when you receive image into analysis, it has full horizontal size within your preview area (100% of width inside preview is equal 100% of width inside analysis). So, no hidden zones in horizontal dimension. This open the way to calculate the size for vertical cropping. I am done this with next code:
var bitmap = ... <- obtain the bitmap as suggested in the SO link above
val matrix = Matrix()
matrix.postRotate(90f)
bitmap = Bitmap.createBitmap(bitmap, 0, 0, image.width, image.height, matrix, true)
val cropHeight = if (bitmap.width < viewFinderSize!!.width) {
// if preview area larger than analysing image
val koeff = bitmap.width.toFloat() / viewFinderSize!!.width.toFloat()
viewFinderSize!!.height.toFloat() * koeff
} else {
// if preview area smaller than analysing image
val prc = 100 - (viewFinderSize!!.width.toFloat()/(bitmap.width.toFloat()/100f))
viewFinderSize!!.height + ((viewFinderSize!!.height.toFloat()/100f) * prc)
}
val cropTop = (bitmap.height/2)-((cropHeight)/2)
bitmap = Bitmap.createBitmap(bitmap, 0, cropTop.toInt(), bitmap.width, cropHeight.toInt())
The final value in bitmap variable - is the cropped image ready to pass into FirebaseVisionImage.fromBitmap(bitmap)
PS.
welcome to improve the suggested variant
May be I am late but here is the code working for me
Few times if the the cropTop comes as -ve value so whenever the negative value comes you should process image which comes from ImageProxy in other cases you can process cropped bitmap
val mediaImage = imageProxy.image ?: return
var bitmap = ImageUtils.convertYuv420888ImageToBitmap(mediaImage)
val rotationDegrees = imageProxy.imageInfo.rotationDegrees
val matrix = Matrix()
matrix.postRotate(rotationDegrees.toFloat())
bitmap =
Bitmap.createBitmap(bitmap, 0, 0, mediaImage.width, mediaImage.height, matrix, true)
val cropHeight = if (bitmap.width < previewView.width) {
// if preview area larger than analysing image
val koeff = bitmap.width.toFloat() / previewView.width.toFloat()
previewView.height.toFloat() * koeff
} else {
// if preview area smaller than analysing image
val prc = 100 - (previewView.width.toFloat() / (bitmap.width.toFloat() / 100f))
previewView.height + ((previewView.height.toFloat() / 100f) * prc)
}
val cropTop = (bitmap.height / 2) - ((cropHeight) / 2)
if (cropTop > 0) {
Bitmap.createBitmap(bitmap, 0, cropTop.toInt(), bitmap.width, cropHeight.toInt())
.also { process(it, imageProxy) }
} else {
imageProxy.image?.let { process(it, imageProxy) }
}
I'm having problem with my file browser.
When it reached to any directory : Get folder list to list map, and use onBindCustomView for setting icon for each list items.
If that file format is image, it shows the image preview instead of showing image icon.
But the problem is, one or less than 10 image file is OK. But when the image file count is reached to over 50, it lags very hard.
I think this lag problem is caused by image preview. Because it didn't resize, so I add the code to resize image preview from any x any to 100x100.
But there is another problem.
bitmap.createBitmap(bitmap, 0, 0, 100, 100)
This cut image and make it small. This only resize the image. So the result is the small part of image.
Is there a method to resize the image and keep the image looks original?
You can use canvas:
In your view.
<script>
$('#files')
.bind('change', function(ev) {
message_loading("none");
ev.preventDefault();
ev.stopPropagation();
uploadFiles(this);
message_loading("display");
})
</script>
In your script
function uploadFiles(target) {
var content = target.files;
var img = reduceImgSize(content[0], content[0]["name"]);
}
function reduceImgSize(f, name){
var reader = new FileReader();
reader.onload = function (readerEvent) {
var image = new Image();
image.onload = function (imageEvent) {
var canvas = document.createElement('canvas'),
max_size = image.width/1.1,
width = image.width,
height = image.height;
if (width > height) {
if (width > max_size) {
height *= max_size / width;
width = max_size;
}
} else {
if (height > max_size) {
width *= max_size / height;
height = max_size;
}
}
canvas.width = width; // write your width
canvas.height = height; // write your height
canvas.getContext('2d').drawImage(image, 0, 0, width, height);
var dataUrl = canvas.toDataURL('image/jpeg');
var resizedImage = dataURLToBlob(dataUrl);
var imageFile = new File([resizedImage], name, {type : "image/jpeg"});
return imageFile;
}
image.src = readerEvent.target.result;
}
reader.readAsDataURL(f);
}
I hope it helps
Here's what I need:
I have a Surface view that has a square (image view) on top of it. I need to capture an image, and crop out the area that was visible only within the square.
This code gives me decent results but specific only to some devices:
int width=(int)(bitmap.getWidth()*60/100);
int height=(bitmap.getHeight()*100/100); //dont change
bitmap=Bitmap.createBitmap(bitmap,150,0, width-55, height);
Is there any way I could generalize this code? Is there any other way to get what I need?
EDIT: This is how I got it to work-
Save the image from the surface view as a bitmap (This is very simple. There are many examples available on the internet that show how to do that)
Use this code in a function, and call it after the image is clicked
//bitmap is the object where the image is stored
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int left;
if(width > height){
left = (width - height)/2;
}
else {
left = (height - width)/2;
}
bitmap=Bitmap.createBitmap(bitmap,left,0, height, height);