Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Primefaces cropper error when nothing selected on image

I have this following error when I try to crop an image using primefaces cropper, but nothing is selected on the image (the selection is not there ) :

Mar 17, 2013 5:10:46 PM com.sun.faces.lifecycle.ProcessValidationsPhase execute WARNING: negative or zero width

java.awt.image.RasterFormatException: negative or zero width
        at java.awt.image.Raster.<init>(Raster.java:1108)
        at java.awt.image.WritableRaster.<init>(WritableRaster.java:129)
        at sun.awt.image.SunWritableRaster.<init>(SunWritableRaster.java:129)
        at sun.awt.image.ByteComponentRaster.<init>(ByteComponentRaster.java:154)
        at sun.awt.image.ByteInterleavedRaster.<init>(ByteInterleavedRaster.java:191)
        at sun.awt.image.ByteInterleavedRaster.createWritableChild(ByteInterleavedRaster.java:1261)
        at java.awt.image.BufferedImage.getSubimage(BufferedImage.java:1173)
        at org.primefaces.component.imagecropper.ImageCropperRenderer.getConvertedValue(ImageCropperRenderer.java:146)
        at javax.faces.component.UIInput.getConvertedValue(UIInput.java:1030)
        at javax.faces.component.UIInput.validate(UIInput.java:960)
        at javax.faces.component.UIInput.executeValidate(UIInput.java:1233)
        at javax.faces.component.UIInput.processValidators(UIInput.java:698)
        at com.sun.faces.context.PartialViewContextImpl$PhaseAwareVisitCallback.visit(PartialViewContextImpl.java:510)
        at com.sun.faces.component.visit.PartialVisitContext.invokeVisitCallback(PartialVisitContext.java:183)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1612)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
        at javax.faces.component.UIForm.visitTree(UIForm.java:362)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623)
        at com.sun.faces.context.PartialViewContextImpl.processComponents(PartialViewContextImpl.java:378)
        at com.sun.faces.context.PartialViewContextImpl.processPartial(PartialViewContextImpl.java:253)
        at javax.faces.context.PartialViewContextWrapper.processPartial(PartialViewContextWrapper.java:183)
        at javax.faces.context.PartialViewContextWrapper.processPartial(PartialViewContextWrapper.java:183)
        at javax.faces.context.PartialViewContextWrapper.processPartial(PartialViewContextWrapper.java:183)
        at javax.faces.component.UIViewRoot.processValidators(UIViewRoot.java:1171)
        at com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:76)
        at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
        at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
        at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
        at org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:79)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
        at org.omnifaces.filter.FacesExceptionFilter.doFilter(FacesExceptionFilter.java:56)
        at org.omnifaces.filter.HttpFilter.doFilter(HttpFilter.java:75)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
        at org.omnifaces.filter.GzipResponseFilter.doFilter(GzipResponseFilter.java:148)
        at org.omnifaces.filter.HttpFilter.doFilter(HttpFilter.java:75)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
        at org.omnifaces.filter.CharacterEncodingFilter.doFilter(CharacterEncodingFilter.java:115)
        at org.omnifaces.filter.HttpFilter.doFilter(HttpFilter.java:75)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:225)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
        at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
        at org.apache.coyote.ajp.AjpProcessor.process(AjpProcessor.java:200)
        at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:579)
        at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:722)

Mar 17, 2013 5:10:46 PM com.sun.faces.renderkit.html_basic.OutcomeTargetRenderer getNavigationCase
WARNING: JSF1090: Navigation case not resolved for component j_idt74.

I really don't know how to solve this because it seems that the error doesn't occur in the process of cropping..

Can you please help me to solve this problem ? I really don't know what to do.

I am using Primefaces 3.5 and Myfaces 2.1.17.

Thank you very much.

UPDATE : The cropper bean :

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.imageio.stream.FileImageOutputStream;
import javax.servlet.ServletContext;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.primefaces.model.CroppedImage;

import com.meinanliegen.backingbean.User;
import com.meinanliegen.handlers.filters.Configurations;

@ManagedBean
@ViewScoped
public class ImageCropperBean implements Serializable {
  private static final long serialVersionUID = -7835902358418363820L;
  private static final Logger LOGGER = Logger.getLogger(ImageCropperBean.class);
  private CroppedImage croppedImage;
  private String photoCropped;
  // This only contains the relative path to the temp image : /temp/croppedImage
  private String relativeImagePhotoCropped;
  private String originalUploadedPhotoFileName;
  @ManagedProperty(value = "#{user}")
  private User user;

  public CroppedImage getCroppedImage() {
    return croppedImage;
  }

  public void setCroppedImage(CroppedImage croppedImage) {
    this.croppedImage = croppedImage;
  }

  public String getPhotoCropped() {
    return photoCropped;
  }

  public void setPhotoCropped(String photoCropped) {
    this.photoCropped = photoCropped;
  }

  public String getRelativeImagePhotoCropped() {
    return relativeImagePhotoCropped;
  }

  public void setRelativeImagePhotoCropped(String relativeImagePhotoCropped) {
    this.relativeImagePhotoCropped = relativeImagePhotoCropped;
  }

  public User getUser() {
    return user;
  }

  public void setUser(User user) {
    this.user = user;
  }

  public String crop() {
    if (croppedImage == null) {
      LOGGER.error("The cropped image is null");
    }
    else {
      manageTheCrop();
    }
    return null;
    }

  private void manageTheCrop() {
    FacesContext facesContext = FacesContext.getCurrentInstance();
    ServletContext servletContext = (ServletContext) facesContext.getExternalContext().getContext();

    String originalFilePhotoName = croppedImage.getOriginalFilename();
    String tempLocationForCroppedFile = servletContext.getRealPath(Configurations.UPLOAD_TEMP_FILE_PATH);

    String prefix = FilenameUtils.getBaseName(originalFilePhotoName);
    String suffix = FilenameUtils.getExtension(originalFilePhotoName);

    // First time we need to save the original photo name
    if (originalUploadedPhotoFileName == null) {
      originalUploadedPhotoFileName = prefix + "." + suffix;
    }

    try {
      // We will keep the same name for cropped photo, until the user decides
      File photoCroppedFile = File.createTempFile(prefix, "." + suffix, new File(tempLocationForCroppedFile));
      photoCropped = photoCroppedFile.getPath();
      cropImageAddContentTo(photoCropped);

      String prefixCroppedPhoto = FilenameUtils.getBaseName(photoCropped);
      String suffixCroppedPhoto = FilenameUtils.getExtension(photoCropped);
      String photoCroppedFileName = prefixCroppedPhoto + "." + suffixCroppedPhoto;
      relativeImagePhotoCropped = Configurations.UPLOAD_TEMP_FILE_PATH + photoCroppedFileName;
    }
    catch (IOException ex) {
      LOGGER.error(ex);
      BeanUtils.addMessage(FacesMessage.SEVERITY_ERROR, "Bitte versuchen Sie es noch einmal.",
      "Fehler beim Zuschneiden Ihres Fotos");
    }
      }

public void saveCroppedImageAsPrimaryUserImage() {
if (photoCropped != null) {
  String profilePhotoChosenFilePrefix = String.format("%s_%s_%s", user.getFirstName(), user.getLastName(),
      originalUploadedPhotoFileName);
  try {
    // We will save the last cropped image as profile
    File finalPhotoLocation = new File(Configurations.UPLOAD_FILE_PATH, profilePhotoChosenFilePrefix);

    OutputStream output = null;
    output = new FileOutputStream(finalPhotoLocation);
    IOUtils.copy(new FileInputStream(photoCropped), output);
    user.setTempProfilePictureSrc(relativeImagePhotoCropped);
    user.setProfilePictureSrc("../uploads/" + finalPhotoLocation.getName());
  }
  catch (IOException ex) {
    LOGGER.error(ex);
    BeanUtils.addMessage(FacesMessage.SEVERITY_ERROR, "Bitte versuchen Sie es noch         einmal.", "Fehlermeldung");
      }
    }
  }

  public void cropImageAddContentTo(String croppedImagePath) {
    try {
      cropImage(croppedImagePath);
    }
    catch (IOException ex) {
      LOGGER.error(ex);
      BeanUtils.addMessage(FacesMessage.SEVERITY_ERROR, "Fehlermeldung",
          "Es ist eiin Fehler aufgetreten. Bitte versuchen Sie es noch einmal.");
    }
  }

  public void cropImage(String imageFileName) throws IOException {
    FileImageOutputStream imageFileOutput = null;
    imageFileOutput = new FileImageOutputStream(new File(imageFileName));
    imageFileOutput.write(croppedImage.getBytes(), 0, croppedImage.getBytes().length);
    imageFileOutput.close();
  }
}

and the JSF part :

<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">

<p:row>
    <p:column style="height:120px; width 120px;">
        <p:panelGrid columns="2">
            <p:row>
                <p:column>
                    <div class="photo">
                        <p:graphicImage id="standardUploadedImage" value="#{user.tempProfilePictureSrc}" />
                    </div>
                </p:column>
            </p:row>
            <p:row>
                <h:panelGroup id="adjustImage">
                    <p:column style="width:150px">
                        <p:panelGrid>
                            <p:row>
                                <p:column>
                                    <h:outputText value="Bild innerhalb des Rahmens positionieren"
                                        rendered="#{uploadPhotoHandler.userImageUploaded == true}" />
                                </p:column>
                            </p:row>
                            <p:row>
                                <p:column>
                                    <p:commandButton value="Bild anpassen" oncomplete="cropWidget.show()"
                                        update=":growl cropDialog" immediate="true"
                                        rendered="#{uploadPhotoHandler.userImageUploaded == true}"
                                        styleClass="css3button" />
                                </p:column>
                            </p:row>
                        </p:panelGrid>
                    </p:column>
                </h:panelGroup>
            </p:row>
        </p:panelGrid>
    </p:column>
</p:row>

<p:row>
    <p:column>
        <p:fileUpload fileUploadListener="#{uploadPhotoHandler.handleFileUpload}" mode="advanced"
            label="Portraitfoto hochladen" sizeLimit="5242880" allowTypes="/(\.|\/)(gif|jpe?g|png)$/"
            invalidSizeMessage="Datei darf maximal 5 MB groß sein"
            invalidFileMessage="Bitte prüfen Sie das Format. Es können nur jpg, gif, png Dateien verwendet werden."
            update=":growl standardUploadedImage uploadedImage imageCropper adjustImage" auto="true"
            required="false" />
    </p:column>
</p:row>

<p:row>
    <p:column>
        <p:confirmDialog id="cropDialog" header="Bild anpassen" severity="alert" showEffect="fade" closeOnEscape="true"
            closable="true" hideEffect="fade" widgetVar="cropWidget">
            <p:panelGrid>
                <p:row>
                    <p:column colspan="2">
                        <p:panelGrid columns="3" style="height:50px">
                            <p:row>
                                <p:column>
                                    <p:commandButton id="cancel" value="Löschen" onclick="cropWidget.hide()"
                                        type="button"
                                        update=":growl imageCropper uploadedImage standardUploadedImage"
                                        immediate="true" styleClass="css3button" />
                                </p:column>
                            </p:row>
                            <p:row>
                                <p:column>
                                    <h:panelGrid id="cropBtnPanel">
                                        <p:commandButton id="crop" value="Zuschneiden"
                                            action="#{imageCropperBean.crop}"
                                            update=":growl imageCropper uploadedImage standardUploadedImage cropFinished crop cropBtnPanel ApplyBtnPanel"
                                            process="crop imageCropper" styleClass="css3button"
                                            rendered="#{imageCropperBean.showCrop}" />
                                    </h:panelGrid>
                                </p:column>
                            </p:row>
                            <p:row>
                                <p:column>
                                    <h:panelGrid id="ApplyBtnPanel">
                                        <p:commandButton id="cropFinished" value="Übernehmen"
                                            actionListener="#{imageCropperBean.saveCroppedImageAsPrimaryUserImage}"
                                            oncomplete="cropWidget.hide()"
                                            update=":growl imageCropper uploadedImage standardUploadedImage crop cropFinished cropBtnPanel ApplyBtnPanel"
                                            process="cropFinished imageCropper" styleClass="css3button"
                                            rendered="#{imageCropperBean.showApply}" />
                                    </h:panelGrid>
                                </p:column>
                            </p:row>
                        </p:panelGrid>
                    </p:column>
                </p:row>

                <p:row>
                    <p:column headerText="Original">
                        <div class="photoToBeCropped">
                            <p:imageCropper id="imageCropper" 
                                            value="#{imageCropperBean.croppedImage}"
                                            image="#{user.tempProfilePictureSrc}" 
                                            initialCoords="225,75,300,125"
                                            aspectRatio="1.0" 
                                            rendered="#{uploadPhotoHandler.userImageUploaded == true}"
                                            minSize="170" 
                                            required="true" />
                        </div>
                    </p:column>
                    <p:column headerText="Cropped">
                        <div class="photoToBeCropped">
                            <p:graphicImage id="uploadedImage" value="#{imageCropperBean.relativeImagePhotoCropped}" />
                        </div>
                    </p:column>
                </p:row>
            </p:panelGrid>
        </p:confirmDialog>
    </p:column>
</p:row>

It is worth to be mentioned that this entire crop module is embedded in one wizard primefaces step.

like image 883
Ioan Avatar asked Feb 18 '23 03:02

Ioan


2 Answers

I can reproduce it on their own showcase. When I deselect the image and click Crop, then I see the unhandled exception in the ajax response:

enter image description here

(it'd been nice if they installed a decent ajax exception handler, so that this was immediately visible to the enduser)

Well, this is really a bug in their own code. This is 4 days ago already been reported as issue 5349 which is currently unscheduled.

If you really can't wait for them to fix it, then your best is to override the renderer to skip the job in getConvertedValue():

public class MyImageCropperRenderer extends ImageCropperRenderer {

    @Override
    public Object getConvertedValue(FacesContext context, UIComponent component, Object submittedValue) throws ConverterException {
        if (submittedValue == null || ((String) submittedValue).endsWith("_0_0")) {
            return null;
        }

        return super.getConvertedValue(context, component, submittedValue);
    }

}

The submitted value is in the format x_y_w_h wherein the _w_h would be _0_0 when nothing is selected. In that case, the above custom renderer will thus return immediately null instead of continuing the conversion job which would throw that exception.

To get this renderer to run, register it as follows in faces-config.xml wherein the <renderer-class> is the FQN of the custom renderer:

<render-kit>
    <renderer>
        <component-family>org.primefaces.component</component-family>
        <renderer-type>org.primefaces.component.ImageCropperRenderer</renderer-type>
        <renderer-class>com.example.MyImageCropperRenderer</renderer-class>
    </renderer>
</render-kit>
like image 162
BalusC Avatar answered Mar 08 '23 14:03

BalusC


I used the solution posted for BalusC. But sporadically I get the value "_2_0" or something like that. In these cases, the error happens again. Then I resolved so:

@Override
public Object getConvertedValue(FacesContext context, UIComponent component, Object submittedValue) throws ConverterException {
    if (submittedValue != null ){
        String[] submittedValueArray = ((String) submittedValue).split("_");
        if (!"0".equals(submittedValueArray[2]) && !"0".equals(submittedValueArray[3])) {
            return super.getConvertedValue(context, component, submittedValue);
        }           
    }
    return null;
}
like image 41
RamonOliveira Avatar answered Mar 08 '23 13:03

RamonOliveira