It's actually quite simple once the process is understood despite some misleading answers that can be found online. I hope this is gonna help someone in the future.
The technique I used is to :
Pick image
Once image is picked, display it in a cropper without sending it through the wire.
Here there are a few option and I choosed to : When user moves the cropper rectangle around, the coordinates of the rectangle populate an hidden input field.
Send the coordinate to bean and crop it on server side.
I did it this way because the cropper jquery lib I wanted to use didn't transform the image to base 64 and just gave the coordinates of a rectangle. However if someone want to send the cropped image directly in the future I figured it would be really easy. Just like I did except you have to put the cropped image as string base 64 in a hidden input text (instead of rectangle coordinates - this is explained under-) and transform it back on the server side, that's all. (I don't know how efficient / secure that is however). At least that resolved my issue I had with primefaces, which was not wanting to send unnecessary data over the wire multiple times.
1. First let's display the image without sending it to the server.
At this point when the image is displayed if you check inside the src tag of the img you will see that it is the data of the image as base 64:
src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAAQABAAD/2wCEAAYEBQYFBAYGBQ...
<h:form id="lolo" enctype="multipart/form-data">
<p:fileUpload
value="#{adminCreateTeam.teamImg}"
mode="simple" allowTypes="/(\.|\/)(gif|jpe?g|png)$/"/>
<img id="blah" src="#" alt="your image" />
</h:form>
<script>
var reader = new FileReader();
reader.onload = function (e) {
$('#blah').attr('src', e.target.result);
}
function readURL(input) {
if (input.files && input.files[0]) {
reader.readAsDataURL(input.files[0]);
}
}
$("#lolo\\:imgInp").change(function(){
readURL(this);
});
</script>
- Once we have done that it becomes a bit dependent on the jquery cropping library used. I used the cropper lib. With that one we want to have the coordinate of the cropped rectangle. With the coordinates data we populate an hidden input and send it back to the bean to then recrop it on java side.
Alternatively a better solution (imo) would be to use a library that crop the image and give the data client side as base 64, populate an hidden field and send it back to the bean, to then convert base 64 to an image. Each of these steps is quiet easy and can be found on stackoverflow.
Since I wanted to use the cropper library I did it the first way:
This is added inside the form:
<h:inputHidden value="#{adminCreateTeam.rect}"/>
<p:commandButton value="submit" action="#{adminCreateTeam.picTest}" ajax="false"/>
This is the updated onload:
// with this the hidden field is gonna be populated by the
// cropping rectangle data.
var $imageCrop = $('#blah').cropper({
aspectRatio: 1/1,
viewMode: 1,
crop: function(e) {
// Output the result data for cropping image.
// string with all the data delimited by /
$('#lolo\\:hiddenB64').val(e.x + '/' + e.y + '/' + e.width + '/' + e.height);
}
});
//So the image changes in the cropper when a new image is picked
reader.onload = function (e) {
$imageCrop.cropper('replace',e.target.result);
}
We crop the image on with java
public void picTest() {
//getting coord.
String data[] = rect.split("/");
try (InputStream in = new ByteArrayInputStream(teamImg.getContents())) {
BufferedImage bImageFromConvert = ImageIO.read(in);
// line under this crops. It's possible there is a zoom to figure out, I didn't check yet. Seemed correct on first and only try. In any case you'll figure it out
// surely the parsing shouldn't be here but I need to sleep real bad.
BufferedImage dest = bImageFromConvert.getSubimage((int)(Double.parseDouble(data[0])), (int)(Double.parseDouble(data[1])),
(int)(Double.parseDouble(data[2])), (int)(Double.parseDouble(data[3])));
// path to the folder
Path folder = Paths.get(dirs.getString("imgTeams"));
String filename = "team_pic";
String extension = FilenameUtils.getExtension(teamImg.getFileName());
Path file = Files.createTempFile(folder, filename + "-", "." + extension);
ImageIO.write(dest, "jpeg", file.toFile());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}