I'm really stumped with this one:
This is my method to create a dynamic image.
private Image createImage(final String id, final byte[] imageData){
NonCachingImage chartImage=new NonCachingImage(id) {
private static final long serialVersionUID = 1L;
#Override
protected IResource getImageResource() {
return new DynamicImageResource(){
private static final long serialVersionUID=1L;
#Override
protected byte[] getImageData(Attributes attributes) {
String myImageStr = new StringBuffer(
WicketApplication.TOMCAT_IMAGE_DOC_BASE).
append("13835.jpg").toString();
File file = new File(myImageStr);
try {
return Files.readBytes(file);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
};
}
};
chartImage.setOutputMarkupId(true);
chartImage.setOutputMarkupPlaceholderTag(true);
return chartImage;
}
This is where I use it
Image img = createImage("orig_photo", uploadedFile.getBytes());
pnlForm.addOrReplace(img);
My HTML
<img width="100" height="133" title="Photo" wicket:id="orig_photo"/>
Get this error:
Get this error in Javascript Inspect Element:
GET https://localhost/admin/admnwtxtprofile?5-IResourceListener-wProfileTxtPnl-wProfileTxtForm-orig_photo&antiCache=1439492929071 404 (Not Found)
You have imageData supplied to your createImage but then not used inside method.
I assume your uploadedFile is from some folder? May be temp?
The code below similar to yours' is working fine, showing the image.
public class WicketApplication extends WebApplication {
public static final String LOCAL_IMAGE_BASE = "c:\\myimages\\";
...
}
public class TestDynaImageFilePage extends WebPage {
public TestDynaImageFilePage(PageParameters parameters) {
super(parameters);
Form<Void> form = new Form<Void>("imageForm");
form.setOutputMarkupId(true);
add(form);
addFormComponents(form);
}
private void addFormComponents(Form<Void> form) {
Path path = Paths.get("src/main/webapp/images/help.png");
try {
byte[] data = java.nio.file.Files.readAllBytes(path);
Image img = createImage("orig_photo", data);
form.addOrReplace(img);
} catch (IOException e) {
e.printStackTrace();
}
}
private Image createImage(final String id, final byte[] imageData) {
NonCachingImage chartImage = new NonCachingImage(id) {
private static final long serialVersionUID = 1L;
#Override
protected IResource getImageResource() {
return new DynamicImageResource() {
private static final long serialVersionUID = 1L;
#Override
protected byte[] getImageData(Attributes attributes) {
String myImageStr = new StringBuffer(
WicketApplication.LOCAL_IMAGE_BASE).
append("help.png").toString();
File file = new File(myImageStr);
try {
return Files.readBytes(file);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
};
}
};
chartImage.setOutputMarkupId(true);
chartImage.setOutputMarkupPlaceholderTag(true);
return chartImage;
}
}
HTML:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns:wicket>
<head>
</head>
<body>
<form wicket:id="imageForm">
<img width="100" height="133" title="Photo" wicket:id="orig_photo"/>
</form>
</body>
</html>
I think this may have something to do with how Wicket request/response life cycle. I have the same code in BeforeRender method and it works fine but when I copy it in OnSubmit, it doesn't work.
My solution was to refresh the page in OnSubmit instead of calling the above method.
Related
I have implemented html to pdf conversion using openhtmltopdf and I use it in Struts 2 action and it works very well. However, in the case of very large data, e.g. the html data is > 3Mb (pdf file ~1.6Mb) when I test it with JMeter for 50 hits the application crashes with message java.lang.OutOfMemoryError: Java heap space.
If I increase the java limit with the -Xmx option I just get some extra hits
The code i use is like this:
First clean html
public class HtmlToXhtmlConverterHTMLCleaner2 extends AbstractHtmlToXhtmlConverter
implements IHtmlToXhtmlConverter {
public HtmlToXhtmlConverterHTMLCleaner2(String htmlData) {
super(htmlData);
}
#Override
public void convert() {
final HtmlCleaner cleaner = new HtmlCleaner();
CleanerProperties cleanerProperties = cleaner.getProperties();
cleanerProperties.setAdvancedXmlEscape(true);
cleanerProperties.setOmitXmlDeclaration(true);
cleanerProperties.setOmitDoctypeDeclaration(false);
cleanerProperties.setTranslateSpecialEntities(true);
cleanerProperties.setTransResCharsToNCR(true);
cleanerProperties.setRecognizeUnicodeChars(true);
cleanerProperties.setIgnoreQuestAndExclam(true);
cleanerProperties.setUseEmptyElementTags(false);
cleanerProperties.setPruneTags("script");
final XmlSerializer xmlSerializer = new PrettyXmlSerializer(cleanerProperties);
try {
final TagNode rootTagNode = cleaner.clean(htmlData);
this.xhtmlData = xmlSerializer.getAsString(rootTagNode);
} catch (Exception ex) {
ex.printStackTrace();
}
}
then convert cleaned html to pdf
public class PDFConverterHtmlToPdf extends AbstractPDFConverter implements IPDFConverter {
ByteArrayOutputStream psfData;
public PDFConverterHtmlToPdf(String xhtmlData, String cssFile) {
super();
this.xhtmlData = xhtmlData;
this.cssFile = cssFile;
}
#Override
public void convert() {
pdfData = new ByteArrayOutputStream();
try {
// There are more options on the builder than shown below.
PdfRendererBuilder builder = new PdfRendererBuilder();
if(cssFile != null && cssFile.length() > 0){
builder.withHtmlContent(xhtmlData, cssFile);
} else {
builder.withHtmlContent(xhtmlData, "");
}
builder.toStream(pdfData);
builder.run();
} catch (Exception e) {
e.printStackTrace();
}
}
}
then send data from strus2 action to request
private void buildPdfContent(String htmlContent) {
String pdfConverterCssFile = "http://localhost:8080/DocumentConverterApi/css/htmlToPdf.css";
PDFConverterHelp pdfConverterHelp = new PDFConverterHelp("demo.pdf",
htmlContent, pdfConverterCssFile);
pdfConverterHelp.build();
inputStream = new ByteArrayInputStream(pdfConverterHelp.getPDFFile().toByteArray());
pdfConverterHelp.closePdfData();
contentDisposition = "inline;filename=\"" + "demo.pdf\"";
}
I'm doing something wron?
Is there any other way to implement it without the risk of crashing the application?
I have created a upload button, or upload buttons with Vaadin 14. Works like a charm. Perfect. But how do I access the images I uploaded? I have tried to read the tutorials on Vaadin's web page, but they only show the example I have post below. Not how to access the picture. I want to get all the pixels in a matrix form and turn them all into 0..255 gray scale.
Question:
Do you know what method to use to get the images, when I have upload or upload the pictures with this code?
#Data
public class PictureUpload {
private Upload upload;
public PictureUpload() {
// Add picture uploader
upload = new Upload();
addPictureUploader();
}
private void addPictureUploader() {
Div output = new Div();
MultiFileMemoryBuffer buffer = new MultiFileMemoryBuffer();
upload.setReceiver(buffer);
upload.setAcceptedFileTypes("image/jpeg", "image/png", "image/gif");
upload.addSucceededListener(event -> {
Component component = createComponent(event.getMIMEType(), event.getFileName(), buffer.getInputStream(event.getFileName()));
showOutput(event.getFileName(), component, output);
});
}
private Component createComponent(String mimeType, String fileName, InputStream stream) {
if (mimeType.startsWith("text")) {
return createTextComponent(stream);
} else if (mimeType.startsWith("image")) {
Image image = new Image();
try {
byte[] bytes = IOUtils.toByteArray(stream);
image.getElement().setAttribute("src", new StreamResource(fileName, () -> new ByteArrayInputStream(bytes)));
try (ImageInputStream in = ImageIO.createImageInputStream(new ByteArrayInputStream(bytes))) {
final Iterator<ImageReader> readers = ImageIO.getImageReaders(in);
if (readers.hasNext()) {
ImageReader reader = readers.next();
try {
reader.setInput(in);
image.setWidth(reader.getWidth(0) + "px");
image.setHeight(reader.getHeight(0) + "px");
} finally {
reader.dispose();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return image;
}
Div content = new Div();
String text = String.format("Mime type: '%s'\nSHA-256 hash: '%s'", mimeType, MessageDigestUtil.sha256(stream.toString()));
content.setText(text);
return content;
}
private Component createTextComponent(InputStream stream) {
String text;
try {
text = IOUtils.toString(stream, StandardCharsets.UTF_8);
} catch (IOException e) {
text = "exception reading stream";
}
return new Text(text);
}
private void showOutput(String text, Component content, HasComponents outputContainer) {
HtmlComponent p = new HtmlComponent(Tag.P);
p.getElement().setText(text);
outputContainer.add(p);
outputContainer.add(content);
}
}
Update:
I did some test with Mr. Lund's example code below in the comments. It seems that I have trouble to show a picture with this code:
#Data
public class LoadExportTemplate {
private VerticalLayout subjectCounterExportButtonUploaders;
public LoadExportTemplate() {
subjectCounterExportButtonUploaders = new VerticalLayout();
Upload pictureUpload = new PictureUpload().getUpload();
Div output = new PictureUpload().getOutput();
subjectCounterExportButtonUploaders.add(pictureUpload, output);
}
}
Where I insert the subjectCounterExportButtonUploaders with this MainView code. I can't see the picture when I upload it.
#Route("")
#Viewport("width=device-width, minimum-scale=1, initial-scale=1, user-scalable=yes, viewport-fit=cover")
#PreserveOnRefresh
public class MainView extends AppLayout {
/**
*
*/
private static final long serialVersionUID = 1L;
public MainView() {
// Get the components
VerticalLayout buildPredictValidateTemplate = new BuildPredictValidateTemplate().getBuildButtonPredictButtonValidateButtonTextArea();
VerticalLayout subjectCounterExportButtonUpload = new LoadExportTemplate().getSubjectCounterExportButtonUploaders();
// Create logo and drawer
Image barImage = new Image("img/barImage.png", "Fisherfaces Logo");
barImage.setHeight("55px");
addToNavbar(new DrawerToggle(), barImage);
// Create tabs and add listeners to them
Tab buildPredictValidate = new Tab("Build & Predict & Validate");
buildPredictValidate.getElement().addEventListener("click", e -> {
getContent().getChildren().forEach(component -> {
boolean visible = component.equals(buildPredictValidateTemplate);
component.setVisible(visible);
});
});
Tab loadExport = new Tab("Load & Export");
loadExport.getElement().addEventListener("click", e -> {
// Walk around from the bug
getContent().getChildren().forEach(component -> {
boolean visible = component.equals(subjectCounterExportButtonUpload);
component.setVisible(visible);
});
});
// Set the contents
setContent(new Div(buildPredictValidateTemplate, subjectCounterExportButtonUpload));
subjectCounterExportButtonUpload.setVisible(false);
// Add them and place them as vertical
Tabs tabs = new Tabs(buildPredictValidate, loadExport);
tabs.setOrientation(Tabs.Orientation.VERTICAL);
addToDrawer(tabs);
}
}
But this example works. Here I can see the picture when I upload it.
#Route(value = UploadView.ROUTE)
#PageTitle(UploadView.TITLE)
public class UploadView extends AppLayout{
/**
*
*/
private static final long serialVersionUID = 1L;
public static final String ROUTE = "upload";
public static final String TITLE = "Upload";
public UploadView() {
PictureUpload pictureUpload = new PictureUpload();
VerticalLayout vl = new VerticalLayout();
vl.add(pictureUpload.getUpload(),pictureUpload.getOutput());
setContent(vl);
}
}
Do you know why?
In the comments you clarified that all you want is to get the byte[] of the image after the upload. Here is how you could do that.
Variant 1: MultiFileMemoryBuffer
MultiFileMemoryBuffer buffer = new MultiFileMemoryBuffer();
upload.setReceiver(buffer);
upload.setAcceptedFileTypes("image/jpeg", "image/png", "image/gif");
upload.addSucceededListener(event -> {
byte[] imageBytes = IOUtils.toByteArray(buffer.getInputStream(event.getFileName()));
});
Variant 2: be your own Receiver interface
public class UploadView implements Receiver {
private FastByteArrayOutputStream outputStream;
private Upload upload;
private Button actualUploadButton;
public UploadView(){
upload = new Upload(this);
upload.setAcceptedFileTypes("image/jpeg", "image/png", "image/gif");
upload.addSucceededListener(event -> {
// uploaded file is now in outputStream
byte[] newImageBytes = outputStream.toByteArray();
Notification.show("We have now got the uploaded images bytearray!");
});
upload.setMaxFiles(10);
actualUploadButton = new Button(getTranslation("upload-image"), VaadinIcon.UPLOAD.create());
actualUploadButton.setWidth("100%");
upload.setUploadButton(actualUploadButton);
add(upload);
}
#Override
public OutputStream receiveUpload(String s, String s1) {
return outputStream = new FastByteArrayOutputStream();
}
}
I have a simple setup including a HttpServer with some context to load image and CSS files:
public class Server {
private HttpServer httpServer;
public Server(int port, String path, HttpHandler handler) {
try {
httpServer = HttpServer.create(new InetSocketAddress(port), 0);
httpServer.createContext(path, handler);
// load css files
List<String> cssFiles = new ArrayList<String>();
Files.walk(Paths.get("../css")).forEach(filePath -> {
if (Files.isRegularFile(filePath)) {
cssFiles.add(filePath.getFileName().toString());
}
});
for (String cssFile : cssFiles) {
httpServer.createContext("/css/" + cssFile, new CssHandler(cssFile));
}
// load image files
List<String> imgFiles = new ArrayList<String>();
Files.walk(Paths.get("../images")).forEach(filePath -> {
if (Files.isRegularFile(filePath)) {
imgFiles.add(filePath.getFileName().toString());
}
});
for (String imgFile : imgFiles) {
httpServer.createContext("/images/" + imgFile, new ImageHandler(imgFile));
}
httpServer.setExecutor(null);
} catch (IOException e) {
e.printStackTrace();
}
}
public void start() {
this.httpServer.start();
}
}
In addition to that there is a css handler which works perfectly fine and and an image handler class, which serves images defined in html tags, BUT images which are included via css tag "background-image" cannot be loaded.. why?
ImageHandler:
class ImageHandler implements HttpHandler {
private String img;
public ImageHandler(String img) {
this.img = img;
}
#Override
public void handle(HttpExchange http) throws IOException {
if (http.getRequestMethod().equals("GET")) {
System.out.println("img transfered..." + img);
try {
StringBuilder contentBuilder = new StringBuilder();
try {
BufferedReader in = new BufferedReader(new FileReader("../images/" + img));
String str;
while ((str = in.readLine()) != null) {
contentBuilder.append(str);
}
in.close();
} catch (IOException e) {
}
String response = contentBuilder.toString();
http.sendResponseHeaders(200, response.length());
OutputStream os = http.getResponseBody();
os.write(response.getBytes());
os.flush();
os.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
Sooo,
this works:
<img src="images/example.png"/>
But this one doesn't work:
background-image: url("images/example.png");
Could anybody explain why and suggest how to solve this problem?
Since partial URLs are relative to the source of the style sheet, and your paths structure looks like this:
/images/example.png
/css/example.css
So image URLs in example.css should either be absolute (/images/example.png), or have the correct relative path (../images/example.png).
I have project it's jetty server which use freemarker. I use russian letters in my templates and receive ?. All subjects i have read before didn't help me.
I use in my code
.setContentType("text/html;charset=utf-8");
.setCharacterEncoding("UTF-8");
all my files is utf-8.
My Freemarker page genertor servlet
public class PageGenerator {
private static PageGenerator pageGenerator;
private Configuration cfg;
public static PageGenerator instance() {
if (pageGenerator == null)
pageGenerator = new PageGenerator();
return pageGenerator;
}
public String getPage(String filename, Map<String, Object> data) {
Writer stream = new StringWriter();
try {
Template template = cfg.getTemplate(filename);
template.process(data, stream);
} catch (IOException | TemplateException e) {
e.printStackTrace();
}
return stream.toString();
}
private PageGenerator() {
cfg = setCfg();
}
private Configuration setCfg(){
cfg = new Configuration(Configuration.VERSION_2_3_20);
try {
cfg.setDirectoryForTemplateLoading(new File("templates/"));
cfg.setDefaultEncoding("UTF-8");
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
} catch (IOException e) {
e.printStackTrace();
}
return cfg;
}
}
But in brouser my page in windows-1252 encoding.
Thanks for idea ddekany I used debag mode and find out that Class Response that extends HttpServletResponse has "magic" method .setCharacterEncoding() which set Character Encoding in response stream
I have a wicket page which has a link ADD PRODUCT. On clicking the link a modal window open which takes the product information.
ProductAddPanel.java
public class ProductAddPanel extends Panel {
private InlineFrame uploadIFrame = null;
private ModalWindow window;
private Merchant merchant;
private Page redirectPage;
private List<Component> refreshables;
public ProductAddPanel(String id,final Merchant mct,ModalWindow window,List<Component> refreshables,Page p) {
super(id);
this.window = window;
merchant = mct;
redirectPage = p;
this.refreshables = refreshables;
setOutputMarkupId(true);
}
#Override
protected void onBeforeRender() {
super.onBeforeRender();
if (uploadIFrame == null) {
// the iframe should be attached to a page to be able to get its pagemap,
// that's why i'm adding it in onBeforRender
addUploadIFrame();
}
}
// Create the iframe containing the upload widget
private void addUploadIFrame() {
IPageLink iFrameLink = new IPageLink() {
#Override
public Page getPage() {
return new UploadIFrame(window,merchant,redirectPage,refreshables) {
#Override
protected String getOnUploadedCallback() {
return "onUpload_" + ProductAddPanel.this.getMarkupId();
}
};
}
#Override
public Class<UploadIFrame> getPageIdentity() {
return UploadIFrame.class;
}
};
uploadIFrame = new InlineFrame("upload", iFrameLink);
add(uploadIFrame);
}
}
ProductAddPanel.html
<wicket:panel>
<iframe wicket:id="upload" frameborder="0"style="height: 600px; width: 475px;overflow: hidden"></iframe>
</wicket:panel>
I am using a Iframe to upload the image. I have added a iframe to my ProductPanel.html. Because it is not possible to upload file using ajax submit.
UploadIframe.java
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
DynamicImage imageEntry = new DynamicImage();
if(uploadField.getFileUpload() != null && uploadField.getFileUpload().getClientFileName() != null){
FileUpload upload = uploadField.getFileUpload();
String ct = upload.getContentType();
if (!imgctypes.containsKey(ct)) {
hasError = true;
}
if(upload.getSize() > maximagesize){
hasError = true;
}
if(hasError == false){
System.out.println("######################## Image can be uploaded ################");
imageEntry.setContentType(upload.getContentType());
imageEntry.setImageName(upload.getClientFileName());
imageEntry.setImageSize(upload.getSize());
if(imageEntry != null){
try {
save(imageEntry,upload.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
}else{
target.appendJavaScript("$().toastmessage('showNoticeToast','Please select a valid image!!')");
System.out.println("#################### Error in image uploading ###################");
}
}else{
System.out.println("########################### Image not Selected #####################");
}
MerchantProduct mp =new MerchantProduct();
Product p = new Product();
Date d=new Date();
try {
p.setProductImage(imageEntry.getImageName());
mp.setProduct(p);
Ebean.save(mp);
} catch (Exception e) {
e.printStackTrace();
}
for(Component r: refreshables){
target.add(r);
}
window.close(target);
setResponsePage(MerchantProductPage.class);
}
public void save(DynamicImage imageEntry, InputStream imageStream) throws IOException{
//Read the image data
ByteArrayOutputStream baos = new ByteArrayOutputStream();
copy(imageStream,baos);
baos.close();
byte [] imageData = baos.toByteArray();
baos = null;
//Get the image suffix
String suffix = null;
if("image/gif".equalsIgnoreCase(imageEntry.getContentType())){
suffix = ".gif";
}else if ("image/jpeg".equalsIgnoreCase(imageEntry.getContentType())) {
suffix = ".jpeg";
} else if ("image/png".equalsIgnoreCase(imageEntry.getContentType())) {
suffix = ".png";
}
// Create a unique name for the file in the image directory and
// write the image data into it.
File newFile = createImageFile(suffix);
OutputStream outStream = new FileOutputStream(newFile);
outStream.write(imageData);
outStream.close();
imageEntry.setImageName(newFile.getAbsolutePath());
}
//copy data from src to dst
private void copy(InputStream source, OutputStream destination) throws IOException{
try {
// Transfer bytes from source to destination
byte[] buf = new byte[1024];
int len;
while ((len = source.read(buf)) > 0) {
destination.write(buf, 0, len);
}
source.close();
destination.close();
if (logger.isDebugEnabled()) {
logger.debug("Copying image...");
}
} catch (IOException ioe) {
logger.error(ioe);
throw ioe;
}
}
private File createImageFile(String suffix){
UUID uuid = UUID.randomUUID();
File file = new File(imageDir,uuid.toString() + suffix);
if(logger.isDebugEnabled()){
logger.debug("File "+ file.getAbsolutePath() + "created.");
}
return file;
}
}
}
I am using setResonsePage() to redirect to initial page on which "Add Product" link is present. So that i get the refreshed page having new product information.
My problem is that modal window is not closing on window.close() and inside that window i am getting the refreshed page.
My requirement is that Modal window should close and page should be refreshed. I am passing the Parentpage.class in my setResponsePage().
Any help and advices appreciated! Thanks in advance.
In the ParentPage.class on which modal window is open i called setWindowClosedCallback() method in which I am adding getPage() to target so that page will refresh when modal window is closed.
Here is the code for same
modalDialog.setWindowClosedCallback(new ModalWindow.WindowClosedCallback()
{
private static final long serialVersionUID = 1L;
#Override
public void onClose(AjaxRequestTarget target)
{
target.addComponent(getPage());
}
});