Hi does anyone know a good way to take a screenshot of a simulation, in such way that you can specify the resolution and get a higher quality image?
the only way i can think of is zooming in and stitch multiple image together, but it takes a long time...
update:
I've managed to successfully export the whole area, the magic parameter is the: .setAnimationParameterEnabled(Panel.ANIM_BOUNDS_CLIPPING_XJAL, false)
it will force Anylogic to draw the whole area, and not just the visible area.
But it doesn't always work. I have to run the code, move around the area, zoom in/out and try again. At some point it gets really glitchy, probably because it starts to draw every thing, and then the code works. The problem is that i can't figure out exactly what to do to make it work...
java.awt.Component alPanel = getExperiment().getPresentation().getPanel();
getExperiment().getPresentation().getPanel().setAnimationParameterEnabled(Panel.ANIM_BOUNDS_CLIPPING_XJAL, false);
getExperiment().getPresentation().setMaximized(false);
getExperiment().getPresentation().setPanelSize(5000, 5000);
java.awt.image.BufferedImage imageExperiment = new java.awt.image.BufferedImage(
alPanel.getWidth(),
alPanel.getHeight(),
java.awt.image.BufferedImage.TYPE_INT_RGB
);
getExperiment().drawPresentation(getExperiment().getPresentation().getPanel(), imageExperiment.createGraphics(), false);
java.awt.Component component = getExperiment().getPresentation().getPanel();
// call the Component's paint method, using
// the Graphics object of the image.
component.paintAll( imageExperiment.getGraphics() ); // alternately use .printAll(..)
try {
// write the image as a PNG
javax.imageio.ImageIO.write(
imageExperiment,
"png",
new File("screenshotAnylogic.png"));
} catch(Exception e) {
e.printStackTrace();
}
Okay... so after a lot of experimentation, i found that the "magic parameter" wasn't as magic as i thought.
but this piece of code should be able to create a screenshot that extends the visible area:
public void capturePanel (ShapeGroup p, String fileName) {
Panel argPanel = p.getPresentable().getPresentation().getPanel();
BufferedImage capture = new BufferedImage(4000, 4000, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = capture.createGraphics();
g.setClip( -200, -200, 4000, 4000 );
p.draw( argPanel, g, null, true );
g.dispose();
try {
ImageIO.write(capture, "png", new File(fileName));
} catch (IOException ioe) {
System.out.println(ioe);
}
}
Well, afaik there is no built in method in Anylogic for that.You could try to use Java to realize that though. It is possible to get the Panel that contains the simulation via getExperiment().getPresentation().getPanel() and you can create an image from that. This is explained here for example and the code would look like this:
public static BufferedImage getScreenShot(Component component)
{
BufferedImage image = new BufferedImage(
component.getWidth(),
component.getHeight(),
BufferedImage.TYPE_INT_RGB
);
// call the Component's paint method, using
// the Graphics object of the image.
component.paint( image.getGraphics() ); // alternately use .printAll(..)
return image;
}
public static void saveComponentScreenshot(Component component)
{
try {
// write the image as a PNG
ImageIO.write(
getScreenShot(component),
"png",
new File("screenshot.png"));
} catch(Exception e) {
e.printStackTrace();
}
}
Unfortunately this does not give you the bigger viewport you probably want to have. Maybe the method public final void drawPresentation(Panel panel, java.awt.Graphics2D g, boolean publicOnly) that is available from the Experiment object returned from getExperiment() could help you to draw the simulation on a custom Panel with the wanted dimensions. Pretty hacky but it's all that I can come up with ^^
Related
I am using ImageAnalysis library to extract live previews to then barcode scanning and OCR on.
I'm not having any issues with barcode scanning at all, but OCR is resulting in some weak results. I'm sure this could be from a few reasons. My current attempt at working on the solution is to send the frames to GCP - Storage before I run OCR (or barcode) on the frames in order to look at them in bulk. All of them look very similar:
My best guess is the way i'm processing the frames could be causing the pixels to be organized in the buffer incorrectly (i'm inexperienced to Android - sorry). Meaning rather than organizing 0,0 then 0,1.....it's randomly taking pixels and putting them in random areas. I can't figure out where this is happening though. Once I can look at the image quality, then i'll be able to analyze what the issue is with OCR but this is my current blocker unfortunately.
Extra note: I am uploading the image to GCP - Storage prior to even running OCR, so for the sake of looking at this, we can ignore the OCR statement I made - I just wanted to give some background.
Below is the code where I initiate the camera and analyzer then observe the frames
private void startCamera() {
//make sure there isn't another camera instance running before starting
CameraX.unbindAll();
/* start preview */
int aspRatioW = txView.getWidth(); //get width of screen
int aspRatioH = txView.getHeight(); //get height
Rational asp = new Rational (aspRatioW, aspRatioH); //aspect ratio
Size screen = new Size(aspRatioW, aspRatioH); //size of the screen
//config obj for preview/viewfinder thingy.
PreviewConfig pConfig = new PreviewConfig.Builder().setTargetResolution(screen).build();
Preview preview = new Preview(pConfig); //lets build it
preview.setOnPreviewOutputUpdateListener(
new Preview.OnPreviewOutputUpdateListener() {
//to update the surface texture we have to destroy it first, then re-add it
#Override
public void onUpdated(Preview.PreviewOutput output){
ViewGroup parent = (ViewGroup) txView.getParent();
parent.removeView(txView);
parent.addView(txView, 0);
txView.setSurfaceTexture(output.getSurfaceTexture());
updateTransform();
}
});
/* image capture */
//config obj, selected capture mode
ImageCaptureConfig imgCapConfig = new ImageCaptureConfig.Builder().setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
.setTargetRotation(getWindowManager().getDefaultDisplay().getRotation()).build();
final ImageCapture imgCap = new ImageCapture(imgCapConfig);
findViewById(R.id.imgCapture).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("image taken", "image taken");
}
});
/* image analyser */
ImageAnalysisConfig imgAConfig = new ImageAnalysisConfig.Builder().setImageReaderMode(ImageAnalysis.ImageReaderMode.ACQUIRE_LATEST_IMAGE).build();
ImageAnalysis analysis = new ImageAnalysis(imgAConfig);
analysis.setAnalyzer(
Executors.newSingleThreadExecutor(), new ImageAnalysis.Analyzer(){
#Override
public void analyze(ImageProxy imageProxy, int degrees){
Log.d("analyze", "just analyzing");
if (imageProxy == null || imageProxy.getImage() == null) {
return;
}
Image mediaImage = imageProxy.getImage();
int rotation = degreesToFirebaseRotation(degrees);
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(toBitmap(mediaImage));
if (!isMachineLearning){
Log.d("analyze", "isMachineLearning is about to be true");
isMachineLearning = true;
String haha = MediaStore.Images.Media.insertImage(getContentResolver(), toBitmap(mediaImage), "image" , "theImageDescription");
Log.d("uploadingimage: ", haha);
extractBarcode(image, toBitmap(mediaImage));
}
}
});
//bind to lifecycle:
CameraX.bindToLifecycle(this, analysis, imgCap, preview);
}
Below is how I structure my detection (pretty straightforward and simple):
FirebaseVisionBarcodeDetectorOptions options = new FirebaseVisionBarcodeDetectorOptions.Builder()
.setBarcodeFormats(FirebaseVisionBarcode.FORMAT_ALL_FORMATS)
.build();
FirebaseVisionBarcodeDetector detector = FirebaseVision.getInstance().getVisionBarcodeDetector(options);
detector.detectInImage(firebaseVisionImage)
Finally, when I'm uploading the image to GCP - Storage, this is what it looks like:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.JPEG, 100, baos); //bmp being the image that I ran barcode scanning on - as well as OCR
byte[] data = baos.toByteArray();
UploadTask uploadTask = storageRef.putBytes(data);
Thank you all for your kind help (:
My problem was that I was trying to convert to a bitmap AFTER barcode scanning. The conversion wasn't properly written but I found a way around without having to write my own bitmap conversion function (though I plan on going back to it as I see myself needing it, and genuine curiosity wants me to figure it out)
In my project, I want to find co-ordinates of image in pdf. I tried searching itext and pdfbox, but I was not succesful. Using these co-ordinates and extracted image, I want to verify whether the extracted image is same as image present in database, and co-ordinates of image are same as present in database.
When you say that you've tried with iText, I assume that you've used the ExtractImages example as the starting point for your code. This example uses the helper class MyImageRenderListener, which implements the RenderListener interface.
In that helper class the renderImage() method is implemented like this:
public void renderImage(ImageRenderInfo renderInfo) {
try {
String filename;
FileOutputStream os;
PdfImageObject image = renderInfo.getImage();
if (image == null) return;
filename = String.format(path, renderInfo.getRef().getNumber(), image.getFileType());
os = new FileOutputStream(filename);
os.write(image.getImageAsBytes());
os.flush();
os.close();
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
It uses the ImageRenderInfo object to obtain a PdfImageObject instance and it creates an image file using that object.
If you inspect the ImageRenderInfo class, you'll discover that you can also ask for other info about the image. What you need, is the getImageCTM() method. This method returns a Matrix object. This matrix can be interpreted using ordinary high-school algebra. The values I31 and I32 give you the X and Y position. In most cases I11 and I22 will give you the width and the height (unless the image is rotated).
If the image is rotated, you'll have to consult your high-school schoolbooks, more specifically the ones discussing analytic geometry.
Is there a way to make a snapshot of entire Stage (or Window in general) with decoration (titlebar, border, etc.) in JavaFX? I know that I can make a snapshot of a Scene, but it would not contain window decotation.
[EDIT]
I need to take a snapshot of stage even if it is not visible (is hidden behind another window). So using java.awt.Robot.createScreenCapture(..) is not suitable.
You could use the Robot createScreenCapture class to do it als Scene.snapshot only captures the scene itself.
Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
BufferedImage capture = new Robot().createScreenCapture(screenRect);
ImageIO.write(capture, "bmp", new File(args[0]));
It's a bit of code, you have to make a BufferedImage and then convert it to a WriteableImage. There may be an easier way to do this, but to get the window, this is the way I do it:
NOTE: To get the stage, use the following code (you can use any fx:id you have defined; doesn't have to be the AnchorPane).
#FXML private AnchorPane ap;
Stage stage = (Stage) ap.getScene().getWindow();
File file = new File("snapshot.png");
try {
Rectangle rectangle = new Rectangle((int)stage.getX(), (int)stage.getY(),
(int)stage.getWidth(), (int)stage.getHeight());
BufferedImage bufferedImage = new Robot().createScreenCapture(rectangle);
ImageIO.write(bufferedImage, "png", file);
} catch (IOException ex) {
//IOException
} catch (AWTException ex) {
//AWTException
}
Also, be sure to be using the java.awt.Rectangle and not the javafx one.
I use an Image object to load a png image as a thumbnail by calling its setPixelSize() method to resize the image. I also need to retrieve the original size of the image as integers at some point. How can I get the original sizes (width, height) of the image?
ok i found a workaround: I use a dummy container (SimplePanel) and load the image without scaling save its real dimensions and then remove the container from the parent and discard the new Image object. I don't know if this a good workaround, but it works. Although i would like to know if there is another way...
problem of the workaround: I have a droplist from which i can select logical folders (which contain images). When i select a new folder, and the new set of images is loaded on display, then i get 0 for width and 0 for height.
private void getTrueSize(String fullUrl) {
Image trueImage = new Image();
this.tstCon.add(trueImage);
trueImage.setUrl(fullUrl);
this.trueHeight = trueImage.getHeight();
this.trueWidth = trueImage.getWidth();
//this.tstCon.remove(trueImage);
//trueImage = null;
GWT.log("Image [" + this.imgTitle + "] -> height=" + this.trueHeight + " -> width=" + this.trueWidth);//
}
Extend the Image class and implement onAttach() method. This method is called when a widget is attached to the browser's document.
public class Thumb extends Image {
public Thumb(){
super();
}
protected void onAttach(){
Window.alert(getOffsetHeight()+" "+getOffsetWidth()); //this should give you the original value
setPixelSize(10,10); // this should be the visible value
super.onAttach();
}
}
if this doesn't work, try implementing onLoad() instead of onAttach(), since onLoad() will be called after the image is added to DOM so that it definately should work.
Its the easiest way to create a new hidden Image (placed absolute outside the viewport) and read the size. There is a JavaScript lib that can read the exif data of the image but this would be overkill in this case.
Read naturalHeight and naturalWidth of the image element after image load.
public Panel() {
image = new Image();
image.addLoadHandler(this::onLoad);
}
private void onLoad(#SuppressWarnings("unused") LoadEvent event) {
origImageWidth = getNaturalWidth(image);
origImageHeight = getNaturalHeight(image);
}
private static int getNaturalHeight(Image img) {
return img.getElement().getPropertyInt("naturalHeight"); //$NON-NLS-1$
}
private static int getNaturalWidth(Image img) {
return img.getElement().getPropertyInt("naturalWidth"); //$NON-NLS-1$
}
I have a webview and I capture the view like this
Picture picture = m_browser.capturePicture();
Bitmap b = Bitmap.createBitmap( picture.getWidth(),
picture.getHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas( b );
picture.draw( c );
FileOutputStream fos = null;
try {
fos = new FileOutputStream("/sdcard/temp_1.jpg");
//fos = openFileOutput("samsp_1.jpg", MODE_WORLD_WRITEABLE);
if ( fos != null )
{
b.compress(Bitmap.CompressFormat.JPEG,90, fos);
fos.close();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Now if the loaded web site is long, for eg. times.com then this image is also too big.
I want to split this image in multiple images and with out reducing the quality.
I would like to get these images in the highest quality possible.
Pls. help
Thanks
It's a bit of a hack, but this will work on VERY long webpages without running out of memory. First, put your webview inside another layout (RelativeLayout rl). Size the RelativeLayout for the image size you want. Then call:
rl.draw(canvas);
// do something here to save your bitmap
webview.scrollby(0, rl.getHeight());
and repeat that till you're at the bottom of the page!
Bitmap.createBitmap(source, x, y, width, height)
I allways use this code to cut the a large image to multiple images.
I can use it easy