i'm triying to paint a geographical chart using the info from this answer: https://stackoverflow.com/a/26868280/518 to "colore" an SVG graphic and
from this answer: https://stackoverflow.com/a/11436655/518 to transform it in a BufferedImage. I have done it but every time i want to refresh the chart i have reload the SVG.
My question is: It's posible to not reload the SVG file every time i want to refresh the chart?
I paste my working code, i think that commenting the first line and uncommenting the node-replacing code may work, but instead it produce an unaltered BufferedImage
protected void refreshImage(List<GeographicChartData>geoDataList)throws Exception{
loadWorldMap(); // reads the SVG file into svgDoc property
SVGStyleElement newColorNode=(SVGStyleElement)svgDoc.createElementNS(SVGConstants.SVG_NAMESPACE_URI, "style");
newColorNode.setAttributeNS(null, "type", "text/css");
if(geoDataList!=null && geoDataList.size()>0){
for(GeographicChartData geoData:geoDataList){
double ppto=geoData.getPptoAmount();
if(ppto!=0){
Color pctColor=pct2Color.interpolateColor((geoData.getRealAmount()-ppto)/ppto);
String colorString="."+geoData.getCountryIso()+" {fill: #"+getColorString(pctColor)+";}";
newColorNode.appendChild(svgDoc.createCDATASection(colorString));
}
}
}
/*****
* I think that this has to replace the color node and refresh the BufferedImage produced, but it doesn't.
styleNode is a property setted on loadWorldMap Method
*/
/*if(oldColorNode==null){
styleNode.getParentNode().appendChild(newColorNode);
}else{
styleNode.getParentNode().replaceChild(newColorNode, oldColorNode);
}
oldColorNode=newColorNode;*/
styleNode.getParentNode().appendChild(newColorNode); // the code above don't work, so i need this
TranscoderInput transcoderInput = new TranscoderInput(svgDoc);
ImageTranscoder imageTranscoder=new BufferedImageTranscoder();
imageTranscoder.transcode(transcoderInput, null);
labelMap.setIcon(new ImageIcon(worldMapImage[0]));
}
This is the code of BufferedImageTranscoder:
class BufferedImageTranscoder extends ImageTranscoder{
public BufferedImage createImage(int w, int h) {
return new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
}
public void writeImage(BufferedImage image, TranscoderOutput out) throws TranscoderException {
worldMapImage[0] = image;
}
}
Related
I am trying to compare the page logo by downloading it first and after taking its screenshot. Below is the LUMA logo that I am trying to verify via Selenium WebDriver Java with Cucumber:
I am using AShot API to compare the logo.
I tried below code in Selenium:
My PageObject function:
public class HomePage extends BasePage {
public HomePage(WebDriver driver) {
super(driver);
}
// Declaring global parameters
WebDriverWait wait = new WebDriverWait(driver,Duration.ofSeconds(10));
//Elements for page details
#FindBy(xpath = "//a[#aria-label='store logo']//img")
WebElement logoLuma;
public boolean compareHomePageLogo() throws IOException {
boolean results = false;
WebElement imgLuma = wait.until(ExpectedConditions.elementToBeClickable(logoLuma));
// First downloading the logo image and storing it in local machine
String webImageLoc = imgLuma.getAttribute("src");
//System.out.println("URL is: " + new URL(webImageLoc));
BufferedImage buffimg =ImageIO.read(new URL(webImageLoc));
System.out.println(buffimg);
File outputFile = new File(System.getProperty("user.dir")+"\\Screenshots\\expected.png");
ImageIO.write(buffimg, "png", outputFile);
// Taking screenshot of image element from search results
Screenshot shot = new AShot().takeScreenshot(driver, imgLuma);
File screenshotFile = new File(System.getProperty("user.dir") + "\\Screenshots\\actual.png");
ImageIO.write(shot.getImage(), "png", screenshotFile);
// Comparing both images
BufferedImage expectedImage = ImageIO.read(outputFile); // Getting expected image
BufferedImage actualImage = shot.getImage(); // Getting actual image
ImageDiffer imgDiff = new ImageDiffer();
ImageDiff diff = imgDiff.makeDiff(expectedImage, actualImage); // Storing diff result
if(diff.hasDiff()) {
System.out.println("Images are not same.");
results = false;
}
else {
System.out.println("Images are same.");
results = true;
}
return results;
}
}
My Step definition which is calling above function:
#Then("user can see the LUMA image on page")
public void user_can_see_the_luma_image_on_page() {
hp = new HomePage(driver);
try {
Assert.assertTrue("Images are not same.", hp.compareHomePageLogo());
}
catch(Exception e) {
logger.info(e.getMessage());
Assert.fail();
}
}
Here is the TestRunner:
package testRunner;
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
import org.junit.runner.RunWith;
#RunWith(Cucumber.class)
#CucumberOptions
(
features = { ".//src/test/resources/Features/LandingPage.feature" },
glue = "stepDefinitions",
plugin =
{
"pretty",
"html:reports/myreport.html",
"json:reports/myreport.json",
"rerun:target/rerun.txt", // Mandatory to capture failures
"html:target/cucumber-html-report",
"json:target/cucumber-reports/cucumber.json",
"junit:target/cucumber-reports/cucumber.xml",
"com.aventstack.extentreports.cucumber.adapter.ExtentCucumberAdapter:"
},
dryRun = false,
monochrome = true,
tags = "#temp"
)
public class TestRunner {
}
Running the above TestRunner with JUnit, getting below error in console:
Given user navigates to "https://magento.softwaretestingboard.com/" # stepDefinitions.HomePageSteps.user_navigates_to(java.lang.String)
When user can see the "Default welcome msg!" on page # stepDefinitions.HomePageSteps.user_can_see_the_on_page(java.lang.String)
**null**
15:01:19.989 [main] INFO stepDefinitions.HomePageSteps - **image == null!**
Then user can see the LUMA image on page # stepDefinitions.HomePageSteps.user_can_see_the_luma_image_on_page()
java.lang.AssertionError
at org.junit.Assert.fail(Assert.java:87)
at org.junit.Assert.fail(Assert.java:96)
at stepDefinitions.HomePageSteps.user_can_see_the_luma_image_on_page(HomePageSteps.java:109)
at ✽.user can see the LUMA image on page(file:///C:/Users/priyank.shah3/eclipse-workspace/Luma_eCommerce/./src/test/resources/Features/LandingPage.feature:17)
Scenario status ======>FAILED
As shown above, I am getting "image == null" (highlighted in bold). I tried troubleshooting by printing logs and came to know that it's not reading the file on below line on my PageObject class:
BufferedImage buffimg =ImageIO.read(new URL(webImageLoc));
Tried searching the possible solutions but nothing works till date. Need help on how to get the image here.
Your logo is in svg format. While ImageIO does not support a lot of formats (svg is one of the formats which are not supported out of the box) there are the opprotunities to add support for particular image format.
Check the solution from this post: https://wcm.io/testing/aem-mock/usage-imageio.html
I convert HTML to PDF using iText7 with the convertToPDF() method of pdfHTML. I would like to change the page orientation for a few specific pages in my PDF document. The content of these pages is dynamic, and we cannot guess how many pages that should be in landscape (i.e. content of dynamic table could take more than one page)
Current situation: I create a custom worker (implements ITagWorker) which landscape the page that following the tag <landscape/>
public byte[] generatePDF(String html) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
PdfWriter pdfWriter = new PdfWriter(byteArrayOutputStream);
PdfDocument pdfDocument = new PdfDocument(pdfWriter);
try {
ConverterProperties properties = new ConverterProperties();
properties.setTagWorkerFactory(
new DefaultTagWorkerFactory() {
#Override
public ITagWorker getCustomTagWorker(
IElementNode tag, ProcessorContext context) {
if ("landscape".equalsIgnoreCase(tag.name())) {
return new LandscapeDivTagWorker();
}
return null;
}
} );
MediaDeviceDescription mediaDeviceDescription = new MediaDeviceDescription(MediaType.PRINT);
properties.setMediaDeviceDescription(mediaDeviceDescription);
HtmlConverter.convertToPdf(html, pdfDocument, properties);
} catch (IOException e) {
e.printStackTrace();
}
pdfDocument.close();
return byteArrayOutputStream.toByteArray();
}
The custom worker :
public class LandscapeDivTagWorker implements ITagWorker {
#Override
public void processEnd(IElementNode element, ProcessorContext context) {
}
#Override
public boolean processContent(String content, ProcessorContext context) {
return false;
}
#Override
public boolean processTagChild(ITagWorker childTagWorker, ProcessorContext context) {
return false;
}
#Override
public IPropertyContainer getElementResult() {
return new AreaBreak(new PageSize(PageSize.A4).rotate());
}
}
Is there a way to define all the content that should be displayed in landscape?
Something like:
<p>Display in portrait</p>
<landscape>
<div>
<p>display in landscape</p>
…
<table>
..
</table>
</div>
</landscape>
or with a CSS class :
<p>Display in portrait</p>
<div class="landscape">
<p>display in landscape</p>
…
<table>
..
</table>
</div>
Result => 1 page in portrait and other pages in landscape (All the div content should be in landscape)
PS: I follow this hint Change page orientation for only some pages in the resulting PDF (created out of html) by using a custom CssApplierFactory but the result was the same => just the first page where the landscape class is used was in landscape and the other content of the table was in portrait
Doing it is actually quite tricky, but the whole mechanism is still flexible enough to accommodate this requirement.
We will be working on supporting the following syntax:
<p>Display in portrait</p>
<landscape>
<div>
<p>display in landscape</p>
<p>content</p>
.....
<p>content</p>
</div>
</landscape>
<p> After portrait </p>
First off, we will need to convert the HTML content into elements first and then add those elements into a document instead direct HTML -> PDF conversion. This is needed because in case of HTML there is a separate mechanism for page size handling as dictated by CSS specification and it's not flexible enough to accommodate your requirement so we will be using native iText Layout mechanism for that.
The idea is that apart from customizing the new page size by passing an argument to AreaBreak we will also change the default page size for PdfDocument so that all the consequent pages are created with that custom new page size. For that we will need to pass PdfDocument all along. The high-level code looks as follows:
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(outFilePath));
ConverterProperties properties = new ConverterProperties();
properties.setTagWorkerFactory(new CustomTagWorkerFactory(pdfDocument));
Document document = new Document(pdfDocument);
List<IElement> elements = HtmlConverter.convertToElements(new FileInputStream(inputHtmlPath), properties);
for (IElement element : elements) {
if (element instanceof IBlockElement) {
document.add((IBlockElement) element);
}
}
pdfDocument.close();
The custom tag worker factory is also almost unchanged - it just passes PdfDocument along to the tag worker:
private static class CustomTagWorkerFactory extends DefaultTagWorkerFactory {
PdfDocument pdfDocument;
public CustomTagWorkerFactory(PdfDocument pdfDocument) {
this.pdfDocument = pdfDocument;
}
#Override
public ITagWorker getCustomTagWorker(IElementNode tag, ProcessorContext context) {
if ("landscape".equalsIgnoreCase(tag.name())) {
return new LandscapeDivTagWorker(tag, context, pdfDocument);
}
return null;
}
}
The idea of LandscapeDivTagWorker is to create a Div wrapper and put there the inner content of <landscape> tag but also surround it with AreaBreak elements - the preceding one will force the new page break with landscape orientation and change the default page size for the whole document while the succeeding one will revert everything back - force the split to portrait page size and set default page size to portrait as well. Note that we are also setting a custom renderer for AreaBreak with setNextRenderer to actually set the default page size when it comes to that break:
private static class LandscapeDivTagWorker extends DivTagWorker {
private PdfDocument pdfDocument;
public LandscapeDivTagWorker(IElementNode element, ProcessorContext context, PdfDocument pdfDocument) {
super(element, context);
this.pdfDocument = pdfDocument;
}
#Override
public IPropertyContainer getElementResult() {
IPropertyContainer baseElementResult = super.getElementResult();
if (baseElementResult instanceof Div) {
Div div = new Div();
AreaBreak landscapeAreaBreak = new AreaBreak(new PageSize(PageSize.A4).rotate());
landscapeAreaBreak.setNextRenderer(new DefaultPageSizeChangingAreaBreakRenderer(landscapeAreaBreak, pdfDocument));
div.add(landscapeAreaBreak);
div.add((IBlockElement) baseElementResult);
AreaBreak portraitAreaBreak = new AreaBreak(new PageSize(PageSize.A4));
portraitAreaBreak.setNextRenderer(new DefaultPageSizeChangingAreaBreakRenderer(portraitAreaBreak, pdfDocument));
div.add(portraitAreaBreak);
baseElementResult = div;
}
return baseElementResult;
}
}
The implementation of the custom area break renderer is quite straightforward - we only set the default page size to PdfDocument - the rest is done under the hood by default implementations which we extend from:
private static class DefaultPageSizeChangingAreaBreakRenderer extends AreaBreakRenderer {
private PdfDocument pdfDocument;
private AreaBreak areaBreak;
public DefaultPageSizeChangingAreaBreakRenderer(AreaBreak areaBreak, PdfDocument pdfDocument) {
super(areaBreak);
this.pdfDocument = pdfDocument;
this.areaBreak = areaBreak;
}
#Override
public LayoutResult layout(LayoutContext layoutContext) {
pdfDocument.setDefaultPageSize(areaBreak.getPageSize());
return super.layout(layoutContext);
}
}
As a result you will get the page set up similar to the one on the screenshot:
I am visualizing some data with vaadin-charts:3.2.0, and I am trying to export a SVG out from the chart. I get some results but it is not satisfying. I can only share the screenshosts instead of the SVG itself. I also had to pixelate the labels to mask private data.
Original vaadin-charts seen on screen:
Exported SVG:
One problem is that the labels overflow the svg boundaries. And the chart drawings also overflow the boundaries making it seem like an incomplete drawing. Any idea what is wrong with this structure?
public class SvgStreamResource extends StreamResource {
public SvgStreamResource(String svgText, String filename) {
super(new StreamSource() {
#Override
public InputStream getStream() {
InputStream s = new BufferedInputStream( new ReaderInputStream(new StringReader(svgText)));
return s;
}
}, filename + ".svg");
}
#Override
public String getMIMEType() {
return "image/svg+xml";
}
}
Within a component:
Button exportButton = createExportButton("SVG", createSVGStreamSource(conf));
private SvgStreamResource createSVGStreamSource(Configuration conf) {
String svg = SVGGenerator.getInstance().generate(conf);
return new SvgStreamResource(svg, fileBaseName);
}
private Button createExportButton(String caption, SvgStreamResource svgStreamResource) {
Button b = new Button(caption);
FileDownloader downloader = new FileDownloader(svgStreamResource);
downloader.extend(b);
return b;
}
I created a pdf using the following example:
https://developers.itextpdf.com/examples/actions-and-annotations/clone-creating-and-adding-annotations#2260-addstamp.java
#Category(SampleTest.class)
public class AddStamp extends GenericTest {
public static final String DEST = "./target/test/resources/sandbox/annotations/add_stamp.pdf";
public static final String IMG = "./src/test/resources/img/itext.png";
public static final String SRC = "./src/test/resources/pdfs/hello.pdf";
public static void main(String[] args) throws Exception {
File file = new File(DEST);
file.getParentFile().mkdirs();
new AddStamp().manipulatePdf(DEST);
}
#Override
protected void manipulatePdf(String dest) throws Exception {
PdfDocument pdfDoc = new PdfDocument(new PdfReader(SRC), new PdfWriter(DEST));
ImageData img = ImageDataFactory.create(IMG);
float w = img.getWidth();
float h = img.getHeight();
Rectangle location = new Rectangle(36, 770 - h, w, h);
PdfStampAnnotation stamp = new PdfStampAnnotation(location)
.setStampName(new PdfName("ITEXT"));
PdfFormXObject xObj = new PdfFormXObject(new Rectangle(w, h));
PdfCanvas canvas = new PdfCanvas(xObj, pdfDoc);
canvas.addImage(img, 0, 0, false);
stamp.setNormalAppearance(xObj.getPdfObject());
stamp.setFlags(PdfAnnotation.PRINT);
pdfDoc.getFirstPage().addAnnotation(stamp);
pdfDoc.close();
}
}
The pdf is properly created and contains the stamp annotation
I can get the annotation using:
...
PdfStampAnnotation s = (PdfStampAnnotation) pdfDoc.getFirstPage().getAnnotations().get(0);
s.?????
How can I get back the image (itext.png) of the stamp (eg: byte[]) ?
I'm really new to itext and after hours of research I'm stuck at this point...
First of all, you won't get the original image back. PDF support only very few bitmap image formats as they are: JPEG, JPEG2000, certain fax formats, but definitively not PNG. PNGs are converted into the PDF internal bitmap format, and upon extraction can best be converted back to a PNG.
Furthermore, the reason why there is no simple getImage method in the PdfStampAnnotation class is that the appearance of a stamp may be constructed like the contents of a regular page, it may contain text, it may contain vector graphics, it may contain bitmap images, it may contain an arbitrary mixture of those elements. Thus, all you can retrieve from an annotation is its appearance.
If you are sure an annotation contains only an image (or you at least are not interested in anything but the image), you can extract that image using the iText parser framework, e.g. like this:
Map<byte[], String> extractAnnotationImages(PdfStream xObject) {
final Map<byte[], String> result = new HashMap<>();
IEventListener renderListener = new IEventListener() {
#Override
public Set<EventType> getSupportedEvents() {
return Collections.singleton(RENDER_IMAGE);
}
#Override
public void eventOccurred(IEventData data, EventType type) {
if (data instanceof ImageRenderInfo) {
ImageRenderInfo imageRenderInfo = (ImageRenderInfo) data;
byte[] bytes = imageRenderInfo.getImage().getImageBytes();
String extension = imageRenderInfo.getImage().identifyImageFileExtension();
result.put(bytes, extension);
}
}
};
PdfCanvasProcessor processor = new PdfCanvasProcessor(renderListener, Collections.emptyMap());
processor.processContent(xObject.getBytes(), new PdfResources(xObject.getAsDictionary(PdfName.Resources)));
return result;
}
(ExtractAnnotationImage method)
which returns a mapping from image byte arrays to file extension to use.
I used it in this helper method:
void saveAnnotationImages(PdfDocument pdfDocument, String prefix) throws IOException {
for (int pageNumber = 1; pageNumber <= pdfDocument.getNumberOfPages(); pageNumber++) {
PdfPage page = pdfDocument.getPage(pageNumber);
int index = 0;
for (PdfAnnotation annotation : page.getAnnotations()) {
PdfDictionary normal = annotation.getAppearanceObject(PdfName.N);
if (normal instanceof PdfStream) {
Map<byte[], String> images = extractAnnotationImages((PdfStream)normal);
for (Map.Entry<byte[], String> entry : images.entrySet()) {
Files.write(new File(String.format("%s-%s-%s.%s", prefix, pageNumber, index++, entry.getValue())).toPath(), entry.getKey());
}
}
}
}
}
(ExtractAnnotationImage helper method)
to extract all images from annotations from the output of the iText example AddStamp you reference and got one image:
By the way, you'll recognize here that transparency is missing. Transparency in the PDF is modeled via a second image, a mask image, which effectively represents something like an alpha channel. One can retrieve this mask from the ImageRenderInfo.getImage() object.
I have a requirement to display the image as part of the FieldGroup. This is for the functionality where the Image appears as normal on a web page, when in edit mode I need to edit this image value by providing an 'upload' option.
I have a Pojo with a property of type com.vaadin.ui.Image along with the other String and Integer values.
public Image getImage() {
return image;
}
public void setImage(Image image) {
this.image = image;
}
I need to work this Image as a normal form element, for example when I edit a form, I have an editable TextField to type in the String value and change it, the same way I intend to display an upload button where I would have an option to replace the existing image.
I have tried using EasyUploads addon for this purpose by intercepting the build method of FieldGroup and specifying the Image field as of type org.vaadin.easyuploads.UploadField
Like this;
#Override
#SuppressWarnings({ "rawtypes", "unchecked" })
protected <T extends Field> T build(String caption, Class<?> dataType,
Class<T> fieldType) throws BindException {
T field = super.build(caption, dataType, fieldType);
if (caption.equalsIgnoreCase("image")) {
final UploadField imageField = new UploadField() {
#Override
protected void updateDisplay() {
final byte[] pngData = (byte[]) getValue();
String filename = getLastFileName();
String mimeType = getLastMimeType();
long filesize = getLastFileSize();
if (mimeType.equals("image/jpeg")) {
StreamSource imagesource = new ImageSource(pngData);
StreamResource resource = new StreamResource(
imagesource, "Uploaded File");
Embedded embedded = new Embedded("Image:" + filename
+ "(" + filesize + " bytes)", resource);
getRootLayout().addComponent(embedded);
} else {
super.updateDisplay();
}
}
};
imageField.setFieldType(FieldType.BYTE_ARRAY);
...
This however fails to display the already available image, errors out with the stacktrace:
Caused by: java.lang.IllegalArgumentException: Property type class com.vaadin.ui.Image is not compatible with UploadField
at org.vaadin.easyuploads.UploadField.setPropertyDataSource(UploadField.java:1021)
at com.vaadin.data.fieldgroup.FieldGroup.bind(FieldGroup.java:265)
at com.vaadin.data.fieldgroup.BeanFieldGroup.bind(BeanFieldGroup.java:167)
at com.vaadin.data.fieldgroup.FieldGroup.setItemDataSource(FieldGroup.java:106)
at com.vaadin.data.fieldgroup.BeanFieldGroup.setItemDataSource(BeanFieldGroup.java:142)
Is there a cleaner way of using an Image as part of the FieldGroup in vaadin 7?
I would suggest replacing in your Pojo the Image instance with a simple byte[], because looking through the UploadField code, I can't see any natural way of converting the result from the upload (which is either a byte[] or a File instance) into something else, using the FieldGroup like you asked.
If you look inside AbstractField.getValue(), you will see that the model value is eventually passed through a settable converter which would have normally helped you in this case (see com.vaadin.data.util.converter.Converter). But I think you are pretty much forced to use byte[] if you want to bind a image bean to the FieldGroup.
Anyway, if you DO replace with byte[] the following steps will help you:
Create a custom FieldGroupFieldFactory that will create an UploadField if you want to bind to a byte[] property + passes a ValueChangeListener for the UploadField is done uploading:
public class ImageEnhancedFieldFactory extends DefaultFieldGroupFieldFactory {
private Property.ValueChangeListener fileUploadedListener;
private ImageEnhancedFieldFactory(Property.ValueChangeListener fileUploadedListener) {
this.fileUploadedListener = fileUploadedListener;
}
#Override
public <T extends Field> T createField(Class<?> type, Class<T> fieldType) {
if (byte[].class.equals(type)) {
UploadField uploadField = new UploadField(UploadField.StorageMode.MEMORY);
uploadField.setFieldType(UploadField.FieldType.BYTE_ARRAY);
uploadField.setButtonCaption("Change image");
uploadField.addListener(fileUploadedListener);
return (T) uploadField;
}
return super.createField(type, fieldType);
}
}
Create an Image instance that shows the content of the byte[] from the pojo:
final ImagePojo imagePojo = new ImagePojo();
imagePojo.setName("superman");
imagePojo.setImageContent(new byte[0]);
BeanItem<ImagePojo> item = new BeanItem<ImagePojo>(imagePojo);
final StreamResource imageResource = new StreamResource(new StreamResource.StreamSource() {
#Override
public InputStream getStream() {
return new ByteArrayInputStream(imagePojo.getImageContent());
}
}, "myimage");
imageResource.setCacheTime(0);
final Image image = new Image("Image", imageResource);
addComponent(image);
NOTE: its necessary to set the cache time to 0 in order to prevent the browser from caching the resource( see https://vaadin.com/book/vaadin7/-/page/components.embedded.html in the section Generating and Reloading Images)
3.Create the FieldGroup (with the new FieldGroupFieldFactory set) and bind to the properties of the pojo, including the one that contains the image content (the byte[]):
FieldGroup fieldGroup = new FieldGroup(item);
fieldGroup.setFieldFactory(new ImageEnhancedFieldFactory(new Property.ValueChangeListener() {
#Override
public void valueChange(Property.ValueChangeEvent event) {
SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmssSSS");
String filename = "myfilename-" + df.format(new Date()) + ".jpg";
imagePojo.setImageContent((byte[])event.getProperty().getValue());
image.markAsDirty();
imageResource.setFilename(filename);
}
}));
addComponent(fieldGroup.buildAndBind("Image name", "name"));
addComponent(fieldGroup.buildAndBind("Image content", "imageContent"));
I left a snippet on Gist of a component that you can paste in you UI and play around if you need (https://gist.github.com/gabrielruiu/9953279)