I'm using MediaMetadataRetriever to retrieve thumbnails at a specific time in video. This is how I achieve this:
MediaMetadataRetriever metadataRetriever = new MediaMetadataRetriever();
try {
metadataRetriever.setDataSource(MainActivity.this, Uri.parse("android.resource://packageName/raw/"+"test"));
String duration=metadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
long time = Long.valueOf(duration)/3;
Bitmap bitmap1 = metadataRetriever.getFrameAtTime(time,MediaMetadataRetriever.OPTION_CLOSEST_SYNC);
imgone.setImageBitmap(bitmap1);
}catch (Exception ex) {
Toast.makeText(MainActivity.this, String.valueOf(ex), Toast.LENGTH_SHORT).show();
}
This returns a bitmap/thumbnail as expected, the problem is that if I want to get multiple thumbnails at different times in the video like this:
MediaMetadataRetriever metadataRetriever = new MediaMetadataRetriever();
try {
metadataRetriever.setDataSource(MainActivity.this, Uri.parse("android.resource://packageName/raw/"+"test"));
String duration=metadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
long time = Long.valueOf(duration)/3;
long time2 = time+time;
long time3 = time+time+time;
Bitmap bitmap1 = metadataRetriever.getFrameAtTime(time,MediaMetadataRetriever.OPTION_CLOSEST_SYNC);
Bitmap bitmap2 = metadataRetriever.getFrameAtTime(time2,MediaMetadataRetriever.OPTION_CLOSEST_SYNC);
Bitmap bitmap3 = metadataRetriever.getFrameAtTime(time3,MediaMetadataRetriever.OPTION_CLOSEST_SYNC);
imgone.setImageBitmap(bitmap1);
imgtwo.setImageBitmap(bitmap2);
imgthree.setImageBitmap(bitmap3);
}catch (Exception ex) {
Toast.makeText(MainActivity.this, String.valueOf(ex), Toast.LENGTH_SHORT).show();
}
Then it still only returns the same thumbnail, I'm not sure if it is because there is only one thumbnail available for the video or what, but I've tried different video files with the same result.
I've tried changing MediaMetadataRetriever.OPTION_CLOSEST_SYNC to all the available options but still the same result.
Im not sure if FFMPEG would be a better option for this?
Exactly a year later, I noticed that I never provided an answer.
In the original question I wanted to retrieve 3 thumbnails, I ended up retrieving 5. I also mentioned that I'm not sure if FFmpeg will be a suitable option, that's exactly what I used.
So, in OnCreate, I make sure that FFmpeg is supported and then I do the following:
if (FFmpeg.getInstance(getApplication()).isSupported()) {
#SuppressLint("SimpleDateFormat")
//ffmpeg expects the time format to be "00:00:00"
Format formatter = new SimpleDateFormat("00:" + "mm:ss.SS");
//Get the duration of the video
long duration = player.getDuration();
//Since I want 5 thumbnails, I divide the duration by 6 to get the first thumbnail position
long img1 = duration / 6;
//I format the first thumbnail time since ffmpeg expects "00:00:00" format
String firstTumbTime = formatter.format(img1);
//Scale the size of the thumbnail output (this can be improved/changed to your liking)
String scaledSize = displayMetrics.widthPixels / 7 + ":" + displayMetrics.heightPixels / 7;
//Set ffmpeg command (notice that I set vframes to one, since I only want 1 thumbnail/image)
String[] a = {"-ss", firstTumbTime, "-i", mStringFilePath, "-vframes", "1", "-s", scaledSize, imageThumbsDirectory + "/" + "thumb1.bmp"};
//start ffmpeg asynctask for the first thumbnail
ExecuteThumbFFMPEG(a);
} else {
Toast.makeText(TestNewPlayer.this, "Your device doesn't support FFMPEG...", Toast.LENGTH_SHORT).show();
}
The comments in the code above explains everything, now here is my ExecuteThumbFFMPEG method.
public void ExecuteThumbFFMPEG(String[] command) {
ffmpegImages = FFmpeg.getInstance(this).execute(command, new ExecuteBinaryResponseHandler() {
#Override
public void onStart() {
//ffmpeg started
}
#Override
public void onProgress(String message) {
//get ffmpeg progress
}
#Override
public void onFailure(String message) {
//ffmpeg failed
}
#Override
public void onSuccess(String message) {
//first thumbnail saved successfully, now to get the other 4
//Scale the thumbnail output (Same as above)
String scaledSize = displayMetrics.widthPixels / 7 + ":" + displayMetrics.heightPixels / 7;
try {
//I first set the path/name for each thumbnail, this will also be used to check if the thumbnail is available or if we should get it
String imgPath1 = imageThumbsDirectory + "/" + "thumb1.bmp";
String imgPath2 = imageThumbsDirectory + "/" + "thumb2.bmp";
String imgPath3 = imageThumbsDirectory + "/" + "thumb3.bmp";
String imgPath4 = imageThumbsDirectory + "/" + "thumb4.bmp";
String imgPath5 = imageThumbsDirectory + "/" + "thumb5.bmp";
//Set the format again (same as above)
#SuppressLint("SimpleDateFormat")
Format formatter = new SimpleDateFormat("00:" + "mm:ss.SS");
//Get the length of the video
long duration = Player.getDuration();
//Divide the length of the video by 6 (same as above)
long time = duration / 6;
//Since I want 5 thumbnails evenly distributed throughout the video
//I use the video length divided by 6 to accomplish that
long img2 = time + time;
long img3 = time + time + time;
long img4 = time + time + time + time;
long img5 = time + time + time + time + time;
//Format the time (calculated above) for each thumbnail I want to retrieve
String Img2Timeformat = formatter.format(img2);
String Img3Timeformat = formatter.format(img3);
String Img4Timeformat = formatter.format(img4);
String Img5Timeformat = formatter.format(img5);
//Get reference to the thumbnails (to see if they have been created before)
File fileimgPath1 = new File(imgPath1);
File fileimgPath2 = new File(imgPath2);
File fileimgPath3 = new File(imgPath3);
File fileimgPath4 = new File(imgPath4);
File fileimgPath5 = new File(imgPath5);
//If thumbnail 1 exist and thumbnail 2 doesn't then we need to get thumbnail 2
if (fileimgPath1.exists() && !fileimgPath2.exists()) {
//Get/decode bitmap from the first thumbnail path to be able to set it to our ImageView that should hold the first thumbnail
Bitmap bmp1 = BitmapFactory.decodeFile(imgPath1);
//Set the first thumbnail to our first ImageView
imgone.setImageBitmap(bmp1);
//Set the ffmpeg command to retrieve the second thumbnail
String[] ffmpegCommandForThumb2 = {"-ss", Img2Timeformat, "-i", mStringFilePath, "-vframes", "1", "-s", scaledSize, imageThumbsDirectory + "/" + "thumb2.bmp"};
//Start ffmpeg again, this time we will be getting thumbnail 2
ExecuteThumbFFMPEG(ffmpegCommandForThumb2);
}
//If thumbnail 2 exist and thumbnail 3 doesn't then we need to get thumbnail 3
if (fileimgPath2.exists() && !fileimgPath3.exists()) {
//Get/decode bitmap from the second thumbnail path to be able to set it to our ImageView that should hold the second thumbnail
Bitmap bmp2 = BitmapFactory.decodeFile(imgPath2);
//Set the second thumbnail to our second ImageView
imgTwo.setImageBitmap(bmp2);
//Set the ffmpeg command to retrieve the third thumbnail
String[] ffmpegCommandForThumb3 = {"-ss", Img3Timeformat, "-i", mStringFilePath, "-vframes", "1", "-s", scaledSize, imageThumbsDirectory + "/" + "thumb3.bmp"};
//Start ffmpeg again, this time we will be getting thumbnail 3
ExecuteThumbFFMPEG(ffmpegCommandForThumb3);
}
////If thumbnail 3 exist and thumbnail 4 doesn't then we need to get thumbnail 4
if (fileimgPath3.exists() && !fileimgPath4.exists()) {
//Get/decode bitmap from the third thumbnail path to be able to set it to our ImageView that should hold the third thumbnail
Bitmap bmp3 = BitmapFactory.decodeFile(imgPath3);
//Set the third thumbnail to our third ImageView
imgThree.setImageBitmap(bmp3);
//Set the ffmpeg command to retrieve the fourth thumbnail
String[] ffmpegCommandForThumb4 = {"-ss", Img4Timeformat, "-i", mStringFilePath, "-vframes", "1", "-s", scaledSize, imageThumbsDirectory + "/" + "thumb4.bmp"};
//Start ffmpeg again, this time we will be getting thumbnail 4
ExecuteThumbFFMPEG(ffmpegCommandForThumb4);
}
////If thumbnail 4 exist and thumbnail 5 doesn't then we need to get thumbnail 5
if (fileimgPath4.exists() && !fileimgPath5.exists()) {
//Get/decode bitmap from the first fourth path to be able to set it to our ImageView that should hold the fourth thumbnail
Bitmap bmp4 = BitmapFactory.decodeFile(imgPath4);
//Set the fourth thumbnail to our fourth ImageView
imgFour.setImageBitmap(bmp4);
//Set the ffmpeg command to retrieve the last thumbnail
String[] ffmpegCommandForThumb5 = {"-ss", Img5Timeformat, "-i", mStringFilePath, "-vframes", "1", "-s", scaledSize, imageThumbsDirectory + "/" + "thumb5.bmp"};
//Start ffmpeg again, this time we will be getting thumbnail 5
ExecuteThumbFFMPEG(ffmpegCommandForThumb5);
}
//If thumbnail 5 exist, then we are done and we need to set it to our ImageView
if (fileimgPath5.exists()) {
Bitmap bmp5 = BitmapFactory.decodeFile(imgPath5);
imgFive.setImageBitmap(bmp5);
}
} catch (Exception ex) {
Toast.makeText(Player.this, String.valueOf(ex), Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFinish() {
//ffmpeg is done
}
});
}
When the user back out of the Activity or OnDestroy gets called, all the thumbnails should be deleted, I do this by calling the following method:
DeleteThumbs.deleteAllThumbnails(getBaseContext());
Here is the DeleteThumbs class for deleting all the thumbnails/images
class DeleteThumbs {
#SuppressWarnings("unused")
static void deleteAllThumbnails(Context baseContext){
//Directory where all the thumbnails are stored
File imageThumbsDirectory = baseContext.getExternalFilesDir("ThumbTemp");
//Path to each thumbnail
File f1 = new File(imageThumbsDirectory + "/" + "thumb1.bmp");
File f2 = new File(imageThumbsDirectory + "/" + "thumb2.bmp");
File f3 = new File(imageThumbsDirectory + "/" + "thumb3.bmp");
File f4 = new File(imageThumbsDirectory + "/" + "thumb4.bmp");
File f5 = new File(imageThumbsDirectory + "/" + "thumb5.bmp");
boolean d1 = f1.delete();
boolean d2 = f2.delete();
boolean d3 = f3.delete();
boolean d4 = f4.delete();
boolean d5 = f5.delete();
}
}
Since we know the name of each thumbnail, it's easy to delete them all at once.
This provides me with 5 thumbnail images that are scaled to reduce loading time into the ImageView's. Because I divided the duration of the video by 6, I get 5 images that are evenly "distributed" throughout the video.
NOTE:
This can be improved by caching the images into memory or using a library like picasso or glide to handle the image loading for us.
Try this one
public void detectBitmapFromVideo(int secondcount, int framecount, String videoPath) {
//int fps = 800000 / framecount;
int delta_time = secondcount * 1000000; //in microsecs
//FFmpegMediaMetadataRetriever mmr = new FFmpegMediaMetadataRetriever();
//mmr.setDataSource(videoPath);
//String s_duration = mmr.extractMetadata(FFmpegMediaMetadataRetriever.METADATA_KEY_DURATION);
MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();
mediaMetadataRetriever.setDataSource(videoPath);
int duration = getVideoDuration(mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION));
//int duration = getVideoDuration(s_duration);
ArrayList<Frame> frames = new ArrayList<Frame>();
//Log.e("Duration ", "Duration = " + duration + " Delta time = " + delta_time);
for (int i = 0; i <= duration; i += delta_time) {
Bitmap bmFrame = mediaMetadataRetriever.getFrameAtTime(i);
//unit in microsecond
if (bmFrame == null) {
//Log.e(TAG, "frame image " + bmFrame.toString());
continue;
}
//saveBitmapImage(bmFrame,i+"");
frames.add(new Frame.Builder().setBitmap(bmFrame).build());
/*Bitmap frame_orig = mmr.getFrameAtTime(i, FFmpegMediaMetadataRetriever.OPTION_CLOSEST);
if (frame_orig == null) {
continue;
}
frames.add(new Frame.Builder().setBitmap(rotateBitmap(frame_orig, 90f)).build());
//Log.e("Faces Detected", "Face detection on going duration = " + duration + " Deleta time = " + i);
}
}
Related
I'm trying to load an unspecified number of images and display them in the order they were taken however the method I'm using to loop through and download the images results in a random image order displayed even though it should be in order.
I did a simple test to see if the loop was initiating the next loop before completing the tasks and it seems like that is the case.
I've tried using the .addView method with index specification but that gives me an IndexOutOfBoundsException: index=1 count=0
for (int i = 1; i <= photoTakenAmount; i++) {
String photoName = "Photo_" + String.valueOf((i)) + ".jpg";
photoRef = firebaseStorage.getReference("users/" + mAuth.getUid() + "/Images/" + photoName);
photoRef.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
View photo_imageView = getLayoutInflater().inflate(R.layout.photo_imageview, mViewPhotoLayout, false);
mViewPhotoLayout.addView(photo_imageView);
ImageView imageView = photo_imageView.findViewById(R.id.photo_imageview);
Glide.with(mViewPhotoLayout).load(uri).into(imageView);
}
});
}
How can I get the images to load in order?
instead of using loops you can donwload the next image in onSuccess and make condition to stop the recursion.
this way ensures that each image will be loaded and showed in order
donwloadImage(0);
private downloadImage(int index){
String photoName = "Photo_" + String.valueOf((index)) + ".jpg";
photoRef = firebaseStorage.getReference("users/" + mAuth.getUid() + "/Images/" + photoName);
photoRef.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
View photo_imageView = getLayoutInflater().inflate(R.layout.photo_imageview, mViewPhotoLayout, false);
mViewPhotoLayout.addView(photo_imageView);
ImageView imageView = photo_imageView.findViewById(R.id.photo_imageview);
Glide.with(mViewPhotoLayout).load(uri).into(imageView);
index++;
if(index>photoTakenAmount)return;
else downloadImage(index);
}
});
}
I am trying to create a backup photos app.
The app should upload all images into Firebase. When I start it the app uploads several photos perfectly but then crashes with this report.
java.util.concurrent.RejectedExecutionException: Task com.google.firebase.storage.StorageTask$8#e245bda rejected from java.util.concurrent.ThreadPoolExecutor#e13b80b[Running, pool size = 2, active threads = 2, queued tasks = 128, completed tasks = 0]
The code:
StorageReference storage_photos=FirebaseStorage.getInstance().getReference();
private void tryToTakePhotos() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
try {
final String[] columns = {MediaStore.Images.Media.DATA, MediaStore.Images.Media._ID};
final String orderBy = MediaStore.Images.Media._ID;
//Stores all the images from the gallery in Cursor
Cursor cursor = getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns, null,
null, orderBy);
int count = cursor.getCount();
int dataColumnIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
Toast.makeText(this, "dd" + count, Toast.LENGTH_SHORT).show();
storage_photos = storage_photos.child(name + "---" + count + "photos");
for (int i = 0; i < count; i++) {
cursor.moveToPosition(i);
String filePath = cursor.getString(dataColumnIndex);
//Bitmap bitmap = BitmapFactory.decodeFile(filePath);
File file = new File(filePath);
Uri uri = Uri.fromFile(file);
StorageReference riversRef = storage_photos.child(uri.getLastPathSegment());
riversRef.putFile(uri);
}
cursor.close();
Calendar calendar = Calendar.getInstance();
firebase_takePhotos.setValue("taken at: " + calendar.get(Calendar.DAY_OF_MONTH) + "-"
+ (calendar.get(Calendar.MONTH) + 1) + "-"
+ calendar.get(Calendar.YEAR));
}catch (Exception e){
firebase_takePhotos.setValue(""+e);
}
}
}
}
I think the problem is with this line in loop
StorageReference riversRef = storage_photos.child(uri.getLastPathSegment());
Because for every item in loop you are making a whole new reference , resulting a queue of 128 tasks. And when you put file it asynchronously uploads the file so you are making alot of async tasks.
queued tasks = 128 indicates that you have reached maximum count of tasks
implementation before kitkat can queue only 128 tasks. Above which it will issue RejectedExecutionException. So I would suggest you reduce the number of task created.
The easiest and most efficient way to overcome this situation is by using Thread.sleep(SLEEP_TIME); after the putFile call along with a counter variable.
Example:
private int fileCounter = 0;
private final int FILE_BATCH_COUNT = 50; //50 files
private final int TIME_REQUIRED_FOR_BATCH_UPLOAD = 5*60000; //5 min, varies according to your internet speed
//...
private void yourFunction(){
//...
fileCounter = fileCounter + 1;
mStorageRef.putFile(fileUri).addOnSuccessListener(...).addOnFailiureListener(...);
if(fileCounter >= FILE_BATCH_COUNT){
Thread.sleep(TIME_REQUIRED_FOR_BATCH_UPLOAD);
fileCounter = 0;
}
}
FILE_BATCH_COUNT : The number of files after which you have to pause the thread to wait for the upload to complete.
TIME_REQUIRED_FOR_BATCH_UPLOAD : You have to find out your upload time in milliseconds for the said amount of files. (considering all are of similar size. other improvise.)
String albumName = albumTitle;
String ExternalStorageDirectory = Environment.getExternalStorageDirectory().getAbsolutePath()
+ "/My_Albums/" + albumName;
File targetDirectory = new File(ExternalStorageDirectory);
if (targetDirectory != null) {
File[] files = targetDirectory.listFiles();
if (files != null) {
filePathString = new String[files.length];
fileNameString = new String[files.length];
for (int i = 0; i < files.length; i++) {
filePathString[i] = files[i].getAbsolutePath();
System.out.println("filePAthStr: " + filePathString[i]);
fileNameString[i] = files[i].getName();
System.out.println("fileNameStr: " + fileNameString[i]);
customGridAdapter.add(filePathString[i]);
}
}
}
How do I get all folders with photo.
How do I get media from mediastore efficiently
Intially , album name will be empty
String albumName = albumTitle;
So if you aint enter the album name, the path would be like
String ExternalStorageDirectory = Environment.getExternalStorageDirectory().getAbsolutePath()
+ "/My_Albums/";
it will go the parent path ,get all the albums under that node and display the number of images under it.
when once you provide albumname,it will get all images inside it and displays.In this scenario you need to loop inside album to cover each and every album under it and get the image paths from them.
UPDATE
For implementing this Logic refer link : Get All Folders With Photos
I got the solution, which was quite simple.
if(albumName != null && !albumName.equals("")){
// Only then set the adapter
}
I'm using the code below to print a bitmap with the Android SDK which can be found at this link:
https://www.zebra.com/us/en/products/software/barcode-printers/link-os/link-os-sdk.html#mainpartabscontainer_794f=downloads
//variables
int printQty= 3;
String printerAddress= ...;
Connection connection = new BluetoothConnection(printerAddress);
connection.open();
//for removing the useless margin printed
connection.write("! U1 JOURNAL\r\n! U1 SETFF 100 2\r\n".getBytes());
ZebraPrinter printer = ZebraPrinterFactory.getInstance(connection);
Bitmap bitmapToPrint = large bitmap here;
ZebraImageAndroid zebraImageToPrint = new ZebraImageAndroid(bitmapToPrint);
for (int i = 0; i < printQty; i++){
printer.printImage(zebraImageToPrint, 0, 0, -1, -1, false);
}
bitmapToPrint.recycle();
connection.close();
The problem is:
the printing process is taking a lot of time because the bitmap is large.
Is there a way to avoid a loop and tell to the printer how many quantity to print without calling printImage multiple times?
i've searched a lot in the documentation but i've not found something usefull, is there a way to achieve this? With CPCL can i achieve the same effect?
Thanks
Mat
use storeimage to store the image on the printer. Then send pritner commands to print the image with a print quantitiy of three. It your printer is using zpl it would look something like "^xa^xgR:image.grf^fs^pq3^xz"
You will want to look at the ZPL guide to be sure but that is the general solution. Store the image and then recall it. In the end delete the image or just always use the same file name and the image will just write over the last image.
This how i solved it at the end
int printQty = 5; //or whatever number you want
Coonection connection = new BluetoothConnection(deviceAddress);
connection.open();
//with SETFF command we add 50 millimiters of margin at the end of the the print (without this the print is wasting a lot of paper)
//ref https://km.zebra.com/kb/index?page=forums&topic=021407fb4efb3012e55595f77007e8a
connection.write("! U1 setvar \"device.languages\" \"CPCL\"\r\n".getBytes());
connection.write("! U1 JOURNAL\r\n! U1 SETFF 50 2\r\n".getBytes());
ZebraPrinter printer = ZebraPrinterFactory.getInstance(PrinterLanguage.CPCL, connection);
//get the bitmap to print
bitmapToPrint = PdfUtils.pdfToBitmap(getApplicationContext(), pdfStamped, 0);
int width = bitmapToPrint.getWidth();
int height = bitmapToPrint.getHeight();
float aspectRatio = width / ZEBRA_RW420_WIDTH; //ZEBRA_RW420_WIDTH = 800f
float multiplier = 1 / aspectRatio;
//scale the bitmap to fit the ZEBRA_RW_420_WIDTH print
bitmapToPrint = Bitmap.createScaledBitmap(bitmapToPrint, (int)(width * multiplier), (int)(height * multiplier), false);
//get the new bitmap and add 20 pixel more of margin
int newBitmapHeight = bitmapToPrint.getHeight() + 20;
//create the Zebra object with the new Bitmap
ZebraImageAndroid zebraImageToPrint = new ZebraImageAndroid(bitmapToPrint);
//the image is sent to the printer and stored in R: folder
printer.storeImage("R:TEMP.PCX", zebraImageToPrint, -1, -1);
//create the print commands string
String printString =
"! 0 200 200 " + newBitmapHeight + " " + printQty + "\r\n"//set the height of the bitmap and the quantity to print
+ "PW 831" + "\r\n"//MAX_PRINT_WIDTH
+ "TONE 50" + "\r\n"//print intensity tone 0-200
+ "SPEED 2" + "\r\n"//print speed (less = more accurate) 1 2.5cm/s | 2 - 5cm/s | 3 - 7.6cm/s
+ "ON-FEED REPRINT" + "\r\n"//enable reprint on FEED button press
+ "NO-PACE" + "\r\n"
+ "BAR-SENSE" + "\r\n"
+ "PCX 20 20 !<TEMP.PCX" + "\r\n"//get the image we stored before in the printer
+ "FORM" + "\r\n"
+ "PRINT" + "\r\n";//print
//send the commands to the printer, the image will be printed now
connection.write(printString.getBytes());
//delete the image at the end to prevent printer memory sutaration
connection.write("! U1 do \"file.delete\" \"R:TEMP.PCX\"\r\n".getBytes());
//close the connection with the printer
connection.close();
//recycle the bitmap
bitmapToPrint.recycle();
I have Modified #MatPag answer and added support for multiple printers of zebra.
Follow these steps:
Turn Off Zebra printer
press feed + power button (release power button when power bars appear but release feed button only when printer prints something)
You will receive a print after sometime which have feild like this:
Label:
Width: 576 dots <------- this is width in px
Now Use Below Function to print out your zebra print without extra spaces:
private void printPhotoFromExternalManual(final Bitmap bitmapToPrint,final int printingQty, final int widthSupported) {
new Thread(new Runnable() {
public void run() {
try {
getAndSaveSettings();
Looper.prepare();
helper.showLoadingDialog("Sending image to printer");
Connection connection = getZebraPrinterConn();
int printQty = printingQty; //or whatever number you want
connection.open();
//with SETFF command we add 50 millimiters of margin at the end of the the print (without this the print is wasting a lot of paper)
//ref https://km.zebra.com/kb/index?page=forums&topic=021407fb4efb3012e55595f77007e8a
// connection.write("! U1 setvar \"device.languages\" \"CPCL\"\r\n".getBytes());
connection.write("! U1 JOURNAL\r\n! U1 SETFF 50 2\r\n".getBytes());
ZebraPrinter printer = ZebraPrinterFactory.getInstance(PrinterLanguage.CPCL, connection);
float ZEBRA_WIDTH = widthSupported;
int width = bitmapToPrint.getWidth();
int height = bitmapToPrint.getHeight();
float aspectRatio = width / ZEBRA_WIDTH; //ZEBRA_RW420_WIDTH = 800f
float multiplier = 1 / aspectRatio;
//scale the bitmap to fit the ZEBRA_RW_420_WIDTH print
Bitmap bitmapToPrint1 = Bitmap.createScaledBitmap(bitmapToPrint, (int) (width * multiplier), (int) (height * multiplier), false);
bitmapToPrint.recycle();
//get the new bitmap and add 20 pixel more of margin
int newBitmapHeight = bitmapToPrint1.getHeight() + 20;
//create the Zebra object with the new Bitmap
ZebraImageAndroid zebraImageToPrint = new ZebraImageAndroid(bitmapToPrint1);
//the image is sent to the printer and stored in R: folder
printer.storeImage("R:TEMP.PCX", zebraImageToPrint, -1, -1);
//create the print commands string
String printString =
"! 0 200 200 " + newBitmapHeight + " " + printQty + "\r\n"//set the height of the bitmap and the quantity to print
+ "PW " + ((int) ZEBRA_WIDTH) + "\r\n"//MAX_PRINT_WIDTH
+ "TONE 50" + "\r\n"//print intensity tone 0-200
+ "SPEED 2" + "\r\n"//print speed (less = more accurate) 1 2.5cm/s | 2 - 5cm/s | 3 - 7.6cm/s
+ "ON-FEED REPRINT" + "\r\n"//enable reprint on FEED button press
+ "NO-PACE" + "\r\n"
+ "BAR-SENSE" + "\r\n"
+ "PCX 20 20 !<TEMP.PCX" + "\r\n"//get the image we stored before in the printer
+ "FORM" + "\r\n"
+ "PRINT" + "\r\n";//print
//send the commands to the printer, the image will be printed now
connection.write(printString.getBytes());
//delete the image at the end to prevent printer memory sutaration
connection.write(("! U1 do \"file.delete\" \"R:TEMP.PCX\"\r\n").getBytes());
//close the connection with the printer
connection.close();
//recycle the bitmap
bitmapToPrint1.recycle();
if (file != null) {
file.delete();
file = null;
}
} catch (ConnectionException e) {
helper.showErrorDialogOnGuiThread(e.getMessage());
} catch (ZebraIllegalArgumentException e) {
helper.showErrorDialogOnGuiThread(e.getMessage());
} finally {
helper.dismissLoadingDialog();
Looper.myLooper().quit();
}
}
}).start();
}
Above function is used like this in my case: printPhotoFromExternalManual(bitmap,1,576);
Enjoy happing coding
I'm following javacv Face Detection/Recognition code, there is confusion regarding face recognition.. What I'm doing is (Sorry if it sounds stupid but I'm stuck)
1) Detect Face crop it and save it to sdcard and place path in learn.txt file (Learning part)
2) Detect Face crop it and find it in existing faces whether it exists or not, but it always return nearest position even if the face doesn't exist in sample faces..
what I'm doing wrong?
// Method, I'm using to recognize face
public Integer recognizeFace(Bitmap face, Context context) {
Log.i(TAG, "===========================================");
Log.i(TAG, "recognizeFace (single face)");
float[] projectedTestFace;
float confidence = 0.0f;
int nearest = -1; // closest match -- -1 for nothing.
int iNearest;
if (trainPersonNumMat == null) {
return null;
}
Log.i(TAG, "NUMBER OF EIGENS: " + nEigens);
// project the test images onto the PCA subspace
projectedTestFace = new float[nEigens];
// Start timing recognition
long startTime = System.nanoTime();
testFaceImg = bmpToIpl(face);
// saveBmp(face, "blah");
// convert Bitmap it IplImage
//testFaceImg = IplImage.create(face.getWidth(), face.getHeight(),
// IPL_DEPTH_8U, 4);
//face.copyPixelsToBuffer(testFaceImg.getByteBuffer());
// project the test image onto the PCA subspace
cvEigenDecomposite(testFaceImg, // obj
nEigens, // nEigObjs
new PointerPointer(eigenVectArr), // eigInput (Pointer)
0, // ioFlags
null, // userData
pAvgTrainImg, // avg
projectedTestFace); // coeffs
// LOGGER.info("projectedTestFace\n" +
// floatArrayToString(projectedTestFace));
Log.i(TAG, "projectedTestFace\n" + floatArrayToString(projectedTestFace));
final FloatPointer pConfidence = new FloatPointer(confidence);
iNearest = findNearestNeighbor(projectedTestFace, new FloatPointer(pConfidence));
confidence = pConfidence.get();
// truth = personNumTruthMat.data_i().get(i);
nearest = trainPersonNumMat.data_i().get(iNearest); // result
// get endtime and calculate time recognition process takes
long endTime = System.nanoTime();
long duration = endTime - startTime;
double seconds = (double) duration / 1000000000.0;
Log.i(TAG, "recognition took: " + String.valueOf(seconds));
Log.i(TAG, "nearest = " + nearest + ". Confidence = " + confidence);
Toast.makeText(context, "Nearest: "+nearest+" Confidence: "+confidence, Toast.LENGTH_LONG).show();
//Save the IplImage so we can see what it looks like
Random generator = new Random();
int n = 10000;
n = generator.nextInt(n);
String fname = "/sdcard/saved_images/" + nearest + " " + String.valueOf(seconds) + " " + String.valueOf(confidence) + " " + n + ".jpg";
Log.i(TAG, "Saving image as: " + fname);
cvSaveImage(fname, testFaceImg);
return nearest;
} // end of recognizeFace
EDIT The confidence is always negative!
Thanks in advance