Java-Selenium : TakesScreenshot size issue - java

I have created 'takescreenshot' reusable method to capture screenshot and have been calling wherever I need it.
however I am facing one strange issue here. Every time this function is called the captured image size keeps increasing
e.g 252K -> 278K -> 310K -> 400K ...
These captured images I am using in ExtentReport. Also apart from selenium session image, I do see a black background image being captured not sure where it is coming from.
method code is as below:
public static void takescreenshot(ExtentTest Test,String Status){
Date d=new Date();
String CurrentTimeStamp=d.toString().replace(":", "_").replace(" ", "_");
File scrFile =((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(scrFile, new File(CurrentTimeStamp+".png"));
if(Status.equals("pass")){
Test.log(LogStatus.PASS, "snapshot below:-"+CurrentTimeStamp+".png"));
}else if(Status.equals("fail")){
Test.log(LogStatus.FAIL, "snapshot below:-"+CurrentTimeStamp+".png"));
}
}
if I hardcode some existing image in extentreport code then everything works fine.
Has anyone come across this issue ever.

I had written a code to capture screenshot of elements which works fine. May be this will help you. I don't know what Extendreport is, so can't help you there.
public static void takeElementScreenshot(WebDriver driver, WebElement element){
try{
// Get entire page screenshot
File screenshot = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
BufferedImage fullImg = ImageIO.read(screenshot);
// Get the location of element on the page
Point point = element.getLocation();
// Get width and height of the element
int eleWidth = element.getSize().getWidth();
int eleHeight = element.getSize().getHeight();
// Crop the entire page screenshot to get only element screenshot
BufferedImage eleScreenshot= fullImg.getSubimage(point.getX(), point.getY(),
eleWidth, eleHeight);
ImageIO.write(eleScreenshot, "png", screenshot);
// Copy the element screenshot to disk
File screenshotLocation = new File("D:\\Screenshot.png");
FileUtils.copyFile(screenshot, screenshotLocation);
}
catch(Exception e){
}
}

Related

Display base64-encoded image

I have a problem with the integration of an image in a text/html JTextPane.
The JTextPane is initialized with the following text:
<html>
<head>
<style type="text/css">
</style>
</head>
<body>
</body>
</html>
I insert text with:
kit.insertHTML(doc, doc.getLength(), "<b>" + string + "</b><br>" , 0, 0, HTML.Tag.B);
All the text inserted this way is displayed correctly, but when I tried inserting a base64-encoded image with:
kit.insertHTML(doc,doc.getLength(), "<img src=\"data:image/jpeg;base64," + base64Code + "\"/>", 0, 0, HTML.Tag.IMG);
I only got a placeholder image. When trying with a normal source path, it worked. However, getting the base64 code online and using that got me a placeholder image too, while the exact same code worked on w3school.com's HTML tryit editor.
When a JTextPane sees an <img> tag, it will check if the image exists in a cache, and if not, it will try to read the image from the url. The html library used by JTextPane does not support base64 encoded image data in the <img> tag, so we will need to do it in a different way.
It turns out that we can manually add images to the image cache. This can be utilized to pick some otherwise invalid url and assign it an image.
Let's add the image to the cache and show it in a JTextPane!
First you want to convert the image into a BufferedImage. This can be done using the ImageIO class.
byte[] imgBytes = decodeBase64(base64Code);
BufferedImage img = ImageIO.read(new ByteArrayInputStream(imgBytes));
Note that here we need the raw image bytes, not the base64 encoding. If you are reading the image from a file, you can pass a File to the read function instead of the input stream.
Now that we have the image as a BufferedImage, we can write a function that adds it to the cache.
#SuppressWarnings({ "rawtypes", "unchecked" })
public static String saveImageToCache(JTextPane pane, BufferedImage img, String name) throws MalformedURLException {
Dictionary cache = (Dictionary) pane.getDocument().getProperty("imageCache");
if (cache == null) {
// No cache exists, so create a new one.
cache = new Hashtable();
pane.getDocument().putProperty("imageCache", cache);
}
String url = "http:\\buffered/" + name;
cache.put(new URL(url), img);
return url;
}
Note that I suppress some warnings about type parameters on Dictionary and Hashtable. Normally this should be avoided, but in this case we are dealing with Swing nonsense in a way where it's ok to suppress the warnings.
This method essentially picks some invalid url and stores the image at that url.
Notice the name argument. This will be part of the url, and if you try to store an image to the cache with the same name as a previous image, this will replace that previous image. Avoid using crazy characters in this name, as new Url(url) may throw a MalformedURLException if it is not a valid url.
We can now use it with JTextPane.
BufferedImage img = ...;
JTextPane pane = new JTextPane();
pane.setContentType("text/html");
String url = saveImageToCache(pane, img, "image1");
pane.setText("<html><body><img src=\"" + url + "\"></body></html>");
JFrame frame = new JFrame("image test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(pane);
frame.setSize(img.getWidth(), img.getHeight());
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Note that you must call setContentType before adding the image to the cache, as the method clears the cache. Furthermore it is important that an image is added to the cache before setText is called, to ensure that images are added before swing needs it.
If the image in the cache is changed by using saveImageToCache with a previously known name, you will need to update the JTextPane in some way, such as calling setText.
If you have a lot of images, you might want to remove them from the cache when they are no longer needed, in order to avoid excessive memory usage. One way to do this would be to define a function as the one below, which removes the image from the cache.
#SuppressWarnings({ "rawtypes" })
public static void removeImageFromCache(JTextPane pane, String name) throws MalformedURLException {
Dictionary cache = (Dictionary) pane.getDocument().getProperty("imageCache");
if (cache == null) {
// There is no cache, so the image is not in the cache.
return;
}
String url = "http:\\buffered/" + name;
cache.remove(new URL(url));
}
You can also clear the cache by calling setContentType or by replacing the JTextPane with a new object. This works as the cache is stored in the JTextPane.

Selenide and Firefox record faulty screenshot

I'm using Selenide and Phantomjs to test a Webapplication.
Im taking the Screenshot as follows:
byte[] bytes = ((TakesScreenshot)webDriver).getScreenshotAs(OutputType.BYTES);
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
returnImage = ImageIO.read(bis);
For input Elements, however, the screenshot looks like this:faulty screenshot
It actually looks like this (when using chrome/firefox)
how it's supposed to look
The interesting thing is, that when I set Selenide to use phantomjs (Configuration.Browser = "phantomjs") it takes the screenshots correctly.
It only occurs on that kind of element, too. Buttons etc are being recorded fine. Any ideas?
PS: The screenshots attached to this post are cropped, the code here takes screenshots of the entire page. In my code, I crop the screenshot only to the desired element but even on the screenshot displaying the entire screen the element is not recorded correctly.
You can take screenshot a element using below code:-
WebElement ele = driver.findElement(By.id("hplogo"));
// Get entire page screenshot
File screenshot = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
BufferedImage fullImg = ImageIO.read(screenshot);
// Get the location of element on the page
Point point = ele.getLocation();
// Get width and height of the element
int eleWidth = ele.getSize().getWidth();
int eleHeight = ele.getSize().getHeight();
// Crop the entire page screenshot to get only element screenshot
BufferedImage eleScreenshot= fullImg.getSubimage(point.getX(), point.getY(),
eleWidth, eleHeight);
ImageIO.write(eleScreenshot, "png", screenshot);
// Copy the element screenshot to disk
File screenshotLocation = new File("C:\\images\\GoogleLogo_screenshot.png");
FileUtils.copyFile(screenshot, screenshotLocation);
Now in above code you are getting the getWidth() and getHeight(). You can try to adjust it by adding or subtracting the value.

Screenshot specific element with Selenium

NOTE: I am aware this question has been asked before a few times however I am having a problem that others seem to not be having.
Even though I appear to be getting the point of the element along with its width and height correctly, the final crop is incorrect. It is like the screenshot I am taking has different dimensions to the webpage. I am using the Chrome Driver.
This is my code for attempting to get a screenshot of the google logo image:
WebDriver driver = new ChromeDriver();
driver.get("http://www.google.com");
WebElement ele = driver.findElement(By.id("hplogo"));
//Get entire page screenshot
File screenshot = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
BufferedImage fullImg = null;
try {
fullImg = ImageIO.read(screenshot);
} catch (IOException e) {
}
//Get the location of element on the page
Point point = ele.getLocation();
//Get width and height of the element
int eleWidth = ele.getSize().getWidth();
int eleHeight = ele.getSize().getHeight();
//Crop the entire page screenshot to get only element screenshot
BufferedImage eleScreenshot = fullImg.getSubimage(point.getX(), point.getY(), eleWidth,
eleHeight);
try {
ImageIO.write(eleScreenshot, "png", screenshot);
} catch (IOException e) {
}
//Copy the element screenshot to disk
File screenshotLocation = new File("/Users/M/Desktop/stuff/logo.png");
try{
FileUtils.copyFile(screenshot, screenshotLocation);
}catch(IOException e){
}
Here is my final logo image:
Here is what it should be getting (just as a png not as gif):
Does anyone have any idea what might be going on?
Check if you have custom scaling on your operating system. I had the same problem using 125% scaling on windows.
Refer to the below screenshot for more details.
Go to your system settings > Search for the display > change the value of "Make Everything Bigger" dropdown to 100%. Then run the code again this will work fine for you.

PDFBox draw black image from BufferedImage

I try to draw an image from a bufferedImage into a PDF using PDFBox but fails, and I get black images and Acrobat Reader warns whith errors like "Out of memory" (but PDF is display).
I use a bufferedImage because I need to draw a JavaFX Image object (with came from call to Funciones.crearImagenDesdeTexto(), is a function which converts a text into an Image) into PDF. Rest of images works well without using bufferedimage.
PDPixelMap img = null;
BufferedImage bi;
try {
//If item has id, I try to get image with that id (image it's shows OK on PDF)
img = new PDPixelMap(documento, read(getClass().getResourceAsStream("/com/img/" + item.getId() + ".png")));
}
catch (Exception e) {
//If item has not id or fails load image, I create image on the fly (which contains item name. This not work on PDF, shows black images)
bi = new BufferedImage(alto, ancho, BufferedImage.TYPE_INT_ARGB);
bi.createGraphics().drawImage(SwingFXUtils.fromFXImage(Funciones.crearImagenDesdeTexto(item.getNombre()), null), ancho, alto, null);
img = new PDPixelMap(documento, bi);
}
finally {
contenedor.drawXObject(img, x, y, alto, ancho);
}
NOTE: crearImagenDesdeTexto() returns a JavaFX Image Object that is create on the fly (I try this function in other parts of the program and works well, function is take from other stackOverflow response).
Your code is confusing, you have three "new PDJpeg" and one of them is in a catch (which should just handle the error). And what does "read()" do? Does it pass a stream or a BufferedImage? If it is a stream, then it is wrong, because PDJpeg is for JPEGs, not for PNG.
The second one
img = new PDJpeg(documento, (getClass().getResourceAsStream("/com/img/" + Byte.toString(item.getId()) + ".png")));
is definitively wrong for the same reason: PDJPeg is not for PNG files / streams.
If you want to create an image from a PNG file / stream, use PDPixelMap.
It is possible to create a PDJpeg object from a BufferedImage, but this is recommended only if the image wasn't encoded before. Because if you would read a BufferedImage from a JPEG, and then use PDJPeg for this, you'll have a slight loss of quality as the image is decoded and encoded again (JPEG is a "lossy" compression format).
If my advice doesn't help, please upload the JPEG file and the PDF somewhere.
Also make sure that you're using the latest version, which is 1.8.7.
Update after comments:
the parameters to createGraphics.drawImage() should be 0, 0 and not width, height. The two parameters are a location, not a size.
Finally, I find a solution (thanks also to Tilman Hausherr):
private void dibujarImagen(Item i, int x, int y, int alto, int ancho) throws IOException {
PDPixelMap img = null;
try {
img = new PDPixelMap(documento, read(getClass().getResourceAsStream("/com/img/" + i.getId() + ".png")));
}
catch (IllegalArgumentException e) {
img = new PDPixelMap(documento, SwingFXUtils.fromFXImage(Funciones.crearImagenDesdeTexto(i.getNombre()),null));
}
finally {
contenedor.drawXObject(img, x, y, alto, ancho);
}
}

ImageIO saves back to original size

I've been searching for some solutions from the internet yet I still haven't found an answer to my problem.
I've been working or doing a program that would get an image file from my PC then will be edited using Java Graphics to add some text/object/etc. After that, Java ImageIO will save the newly modified image.
So far, I was able to do it nicely but I got a problem about the size of the image. The original image and the modified image didn't have the same size.
The original is a 2x3inches-image while the modified one which supposedly have 2x3inches too sadly got 8x14inches. So, it has gone BIGGER than the original one.
What is the solution/code that would give me an output of 2x3inches-image which will still have a 'nice quality'?
UPDATE:
So, here's the code I used.
public Picture(String filename) {
try {
File file = new File("originalpic.jpg");
image = ImageIO.read(file);
width = image.getWidth();
}
catch (IOException e) {
throw new RuntimeException("Could not open file: " + filename);
}
}
private void write(int id) {
try {
ImageIO.write(image, "jpg", new File("newpic.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
}
2nd UPDATE:
I now know what's the problem of the new image. As I check it from Photoshop, It has a different image resolution compared to the original one. The original has a 300 pixels/inch while the new image has a 72 pixels/inch resolution.
How will I be able to change the resolution using Java?
To set the image resolution (of the JFIF segment), you can probably use the IIOMetatada for JPEG.
Something along the lines of:
public class MetadataTest {
public static void main(String[] args) throws IOException {
BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_3BYTE_BGR);
ImageWriter writer = ImageIO.getImageWritersByFormatName("jpeg").next();
writer.setOutput(ImageIO.createImageOutputStream(new File("foo.jpg")));
ImageWriteParam param = writer.getDefaultWriteParam();
IIOMetadata metadata = writer.getDefaultImageMetadata(ImageTypeSpecifier.createFromRenderedImage(image), param);
IIOMetadataNode root = (IIOMetadataNode) metadata.getAsTree(metadata.getNativeMetadataFormatName());
IIOMetadataNode jfif = (IIOMetadataNode) root.getElementsByTagName("app0JFIF").item(0);
jfif.setAttribute("resUnits", "1");
jfif.setAttribute("Xdensity", "300");
jfif.setAttribute("Ydensity", "300");
metadata.mergeTree(metadata.getNativeMetadataFormatName(), root);
writer.write(null, new IIOImage(image, null, metadata), param);
}
}
Note: this code should not be used verbatim, but adding iteration, error handling, stream closing etc, clutters the example too much.
See JPEG Image Metadata DTD for documentation on the metadata format, and what options you can control.

Categories

Resources