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; + + } + +}