diff --git a/.gitignore b/.gitignore
index 5f47acc..a34877e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -205,4 +205,9 @@ temp/
### Vaadin ###
.vaadin-designer
-.designer
\ No newline at end of file
+.designer
+
+# vs-code history
+.history
+
+
diff --git a/.project b/.project
index cccdaf9..04fbe54 100644
--- a/.project
+++ b/.project
@@ -20,4 +20,15 @@
org.eclipse.jdt.core.javanature
org.eclipse.m2e.core.maven2Nature
+
+
+ 1689214028499
+
+ 30
+
+ org.eclipse.core.resources.regexFilterMatcher
+ node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__
+
+
+
diff --git a/README.md b/README.md
index f4f2063..5cf21c0 100644
--- a/README.md
+++ b/README.md
@@ -19,6 +19,9 @@ Install the component using [Vaadin Directory](https://vaadin.com/directory/comp
[docs.f0rce.de/cropper](https://docs.f0rce.de/cropper)
+## Example
+Check the example folder for an example Vaadin view that uses cropper.
+
## License
diff --git a/example/src/de/f0rce/cropper/view/ImageCropView.java b/example/src/de/f0rce/cropper/view/ImageCropView.java
new file mode 100644
index 0000000..b189d7d
--- /dev/null
+++ b/example/src/de/f0rce/cropper/view/ImageCropView.java
@@ -0,0 +1,66 @@
+package de.f0rce.cropper.example;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Stack;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import com.vaadin.flow.component.Component;
+import com.vaadin.flow.component.button.Button;
+import com.vaadin.flow.component.html.Image;
+import com.vaadin.flow.component.orderedlayout.VerticalLayout;
+
+import de.f0rce.cropper.settings.enums.ViewMode;
+import de.f0rce.cropper.CroppableImage;
+import de.f0rce.cropper.CroppableImageBuilder;
+
+@Route(value = ImageCropView.NAME)
+public class ImageCropView extends VerticalLayout
+{
+ private static final long serialVersionUID = 1L;
+ Logger logger = LogManager.getLogger();
+
+ public static final String NAME = "ImageCropView";
+
+
+ public ImageCropView()
+ {
+ build();
+ }
+
+ /**
+ * @throws Exception
+ */
+ protected void build()
+ {
+ var builder = new CroppableImageBuilder(
+ () -> fetchImage(), "image/png");
+ builder.setId(generatedImage.buildSwatchS3Key(this.category, includeVersion));
+ builder.setViewMode(ViewMode.ONE);
+ builder.setAspectRatio(0.0);
+ builder.setInitialAspectRatio(GeneratedImage.SWATCH_HEIGHT / GeneratedImage.SWATCH_WIDTH);
+ builder.setScalable(false);
+ builder.setZoomable(false);
+ builder.setMinCropBoxWidth(ImageRequest.DEFAULT_WIDTH);
+ builder.setMinCropBoxHeight(ImageRequest.DEFAULT_HEIGHT);
+
+
+ var copper = builder.build();
+ Button cropButton = new Button("crop", e -> {
+ /// Displayed the cropped image.
+ var image = cropper.getImage();
+ add(image);
+ });
+
+ add(cropper, cropButton);
+
+ }
+
+ InputStream fetchImage() {
+ /// load the image from a file or the network and return it
+ /// as an input stream of bytes
+ }
+
+}
diff --git a/example/src/de/f0rce/cropper/widgets/CroppableImage.java b/example/src/de/f0rce/cropper/widgets/CroppableImage.java
new file mode 100644
index 0000000..88adf3b
--- /dev/null
+++ b/example/src/de/f0rce/cropper/widgets/CroppableImage.java
@@ -0,0 +1,121 @@
+package de.f0rce.cropper.widgets;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import com.vaadin.flow.component.Component;
+import com.vaadin.flow.component.html.Div;
+import com.vaadin.flow.component.html.Image;
+
+import de.f0rce.cropper.Cropper;
+
+public class CroppableImage extends Div
+{
+ private static final long serialVersionUID = 1L;
+ Logger logger = LogManager.getLogger();
+ private Cropper cropper;
+ CroppableImageBuilder builder;
+
+
+ public CroppableImage(CroppableImageBuilder builder) throws Exception
+ {
+ this.builder = builder;
+ build();
+ }
+
+ private void build() throws Exception
+ {
+ getStyle().set("display", "block");
+ getStyle().set("max-width", "100%");
+ this.setId(builder.imageId);
+
+ add(buildCropper());
+ }
+
+ Component buildCropper() throws Exception
+ {
+ try (var imageStream = this.builder.imageFetcher.apply())
+ {
+ try
+ {
+ var b64Image = getB64Src();
+ this.cropper = new Cropper(
+ this.builder.cropperSettings, b64Image, this.builder.mimeType);
+ this.cropper.setId(this.builder.imageId);
+
+ return this.cropper;
+ }
+ catch (IOException e1)
+ {
+ this.logger.error(e1, e1);
+ throw e1;
+ }
+
+ }
+
+ }
+
+ private String getB64Src() throws Exception
+ {
+ String b64Image;
+ try (var imageStream = this.builder.imageFetcher.apply())
+ {
+ b64Image = java.util.Base64.getEncoder()
+ .encodeToString(IOUtils.toByteArray(imageStream));
+
+ return b64Image;
+ }
+ catch (IOException e1)
+ {
+ this.logger.error(e1, e1);
+ throw e1;
+ }
+
+ }
+
+ // Get the cropped image as a byte stream
+ public InputStream getCroppedStream()
+ {
+ return new ByteArrayInputStream(this.cropper.getImageBase64());
+ }
+
+ /// Returns the uncropped image with a b64 embedded src.
+ public Image getImage() throws Exception
+ {
+ var image = new Image();
+ image.setSrc("data:" + this.builder.mimeType + ";base64," + this.getB64Src());
+ return image;
+ }
+
+ /// Returns the cropped image with a b64 embedded src.
+ public Image getCroppedImage() throws Exception
+ {
+ var bytes = this.cropper.getImageBase64();
+ // var b64String = new String(bytes);
+
+ var b64String = java.util.Base64.getEncoder()
+ .encodeToString(bytes);
+
+ var image = new Image();
+ image.setSrc("data:" + this.builder.mimeType + ";base64," + b64String);
+ return image;
+ }
+
+
+ public static interface ImageFetcher
+ {
+ InputStream apply() throws Exception;
+ }
+
+ public void setImageId(String id)
+ {
+ this.builder.imageId = id;
+
+ }
+
+}
diff --git a/example/src/de/f0rce/cropper/widgets/CroppableImageBuilder.java b/example/src/de/f0rce/cropper/widgets/CroppableImageBuilder.java
new file mode 100644
index 0000000..8b49f59
--- /dev/null
+++ b/example/src/de/f0rce/cropper/widgets/CroppableImageBuilder.java
@@ -0,0 +1,100 @@
+package de.f0rce.cropper.widgets;
+
+import java.io.InputStream;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import de.f0rce.cropper.settings.CropperSettings;
+import de.f0rce.cropper.settings.enums.ViewMode;
+
+public class CroppableImageBuilder
+{
+ Logger logger = LogManager.getLogger();
+ ImageFetcher imageFetcher;
+ CropperSettings cropperSettings = new CropperSettings();
+ String mimeType;
+ String imageId;
+
+ public CroppableImageBuilder(ImageFetcher imageFetcher, String mimeType) throws Exception
+ {
+ this.imageFetcher = imageFetcher;
+ this.mimeType = mimeType;
+
+ }
+
+ public void setInitialAspectRatio(double initialAspectRatio)
+ {
+ this.cropperSettings.setInitialAspectRatio(initialAspectRatio);
+ }
+
+ /* There is no way to directly set the size of the crop box so we hack it.
+ * By calling this method we set the min crop box size (width and height)
+ * and then set the autoCropArea to a really small value which results
+ * in the min crop box size being set as the initial crop box.
+ */
+ public void forceCropBoxSize(int widthPx, int heightPx)
+ {
+ this.cropperSettings.setAutoCropArea(0.01);
+ this.cropperSettings.setMinCropBoxWidth(widthPx);
+ this.cropperSettings.setMinCropBoxHeight(heightPx);
+ }
+
+ public void setCroppedImageHeight(int heightPx)
+ {
+ this.cropperSettings.setCroppedImageHeight(heightPx);
+ }
+
+ public void setCroppedImageWidth(int widthPx)
+ {
+ this.cropperSettings.setCroppedImageWidth(widthPx);
+ }
+
+ public void setMinCropBoxHeight(int heightPx)
+ {
+
+ this.cropperSettings.setMinCropBoxHeight(heightPx);
+ }
+
+ public void setMinCropBoxWidth(int widthPx)
+ {
+ this.cropperSettings.setMinCropBoxWidth(widthPx);
+ }
+
+ public void setViewMode(ViewMode mode)
+ {
+ this.cropperSettings.setViewMode(mode);
+ }
+
+ public void setAspectRatio(double aspectRatio)
+ {
+ this.cropperSettings.setAspectRatio(aspectRatio);
+ }
+
+ public void setScalable(boolean scalable)
+ {
+ this.cropperSettings.setScalable(scalable);
+ }
+
+ public void setZoomable(boolean zoomable)
+ {
+ this.cropperSettings.setZoomable(zoomable);
+ }
+
+ public CroppableImage build() throws Exception
+ {
+ return new CroppableImage(this);
+ }
+
+ public static interface ImageFetcher
+ {
+ InputStream apply() throws Exception;
+ }
+
+ public void setImageId(String id)
+ {
+ this.imageId = id;
+
+ }
+
+}