Open andersr opened 1 year ago
Hey did you figure thus out by any chance ?
Hey there’s an older version of the codesandbox example which has it, but currently travelling with just a phone until Feb. I’ll update the example with a downloadable version again but you should just be able to check the revision history there.
It’s not specific to this library - you need to convert the canvas to a blob and then create a URL ( https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL ) and a button which calls that URL.
Is there a possibility to do this without canvas ? Like what if the user doesnt want a preview. Just drop, crop and submit ?
I think you would still need to make an offscreen canvas with the crop copied to it, even if the user never sees it.
On Tue, 17 Jan 2023 at 18:37, Joshua @.***> wrote:
Is there a possibility to do this without canvas ? Like what if the user doesnt want a preview. Just drop, crop and submit ?
— Reply to this email directly, view it on GitHub https://github.com/DominicTobias/react-image-crop/issues/529#issuecomment-1385293642, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFZT6RHCXWLFY6XG47C7XLWSZ755ANCNFSM6AAAAAATO5VBIQ . You are receiving this because you commented.Message ID: @.***>
@DominicTobias thanks for this tip. By offscreen, is this simply a css-based off screen, or are you referring to this: https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas
I was thinking with CSS but this sounds like a better solution 👍
On Tue, 17 Jan 2023 at 20:41, Anders Ramsay @.***> wrote:
@DominicTobias https://github.com/DominicTobias thanks for this tip. By offscreen, is this simply a css-based off screen, or are you referring to this: https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas
— Reply to this email directly, view it on GitHub https://github.com/DominicTobias/react-image-crop/issues/529#issuecomment-1385440913, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFZT6RUA5Z7HPVXDW7IXA3WS2OQ5ANCNFSM6AAAAAATO5VBIQ . You are receiving this because you were mentioned.Message ID: @.***>
Hey sorry to disturb here again but how would you handle this for a circular crop ?
Hey sorry to disturb here again but how would you handle this for a circular crop ?
I’ve not personally tried to do a circle crop to canvas. Normally I’d say just do it with CSS for reasons explained here - https://github.com/DominicTobias/react-image-crop/issues/409#issuecomment-797857537
but if you want to create a downloadable version with a circle you’d have to do it on the canvas as a black circular border or something ⚫️ which I haven’t tried to do before but if you can find some code to do it, then you can just paste it after the other canvas code to do it over the top
I was thinking with CSS but this sounds like a better solution 👍 …
for example:
function onSubmitCrop() {
if (completedCrop) {
// create a canvas element to draw the cropped image
const canvas = document.createElement("canvas");
// get the image element
const image = imgRef.current;
// draw the image on the canvas
if (image) {
const crop = completedCrop;
const scaleX = image.naturalWidth / image.width;
const scaleY = image.naturalHeight / image.height;
const ctx = canvas.getContext("2d");
const pixelRatio = window.devicePixelRatio;
canvas.width = crop.width * pixelRatio * scaleX;
canvas.height = crop.height * pixelRatio * scaleY;
if (ctx) {
ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
ctx.imageSmoothingQuality = "high";
ctx.drawImage(
image,
crop.x * scaleX,
crop.y * scaleY,
crop.width * scaleX,
crop.height * scaleY,
0,
0,
crop.width * scaleX,
crop.height * scaleY
);
}
const base64Image = canvas.toDataURL("image/png"); // can be changed to jpeg/jpg etc
if (base64Image) {
// @ts-ignore
const fileType = base64Image.split(";")[0].split(":")[1];
const buffer = Buffer.from(
base64Image.replace(/^data:image\/\w+;base64,/, ""),
"base64"
);
const file = new File([buffer], fileName, { type: fileType });
onSubmit(file); // function passed as a prop
}
}
}
}
If anyone is still having trouble, this is how I did it.
You can create a hidden link:
const hiddenAnchorRef = useRef<HTMLAnchorElement>(null)
const blobUrlRef = useRef('')
<a
ref={hiddenAnchorRef}
download
style={{
position: 'absolute',
top: '-200vh',
visibility: 'hidden',
}}
>
Hidden download
</a>
And you can create a blob, create a URL with the blob, assign it to the anchor, trigger a click:
function onDownloadCropClick() {
if (!previewCanvasRef.current) {
throw new Error('Crop canvas does not exist')
}
previewCanvasRef.current.toBlob((blob) => {
if (!blob) {
throw new Error('Failed to create blob')
}
if (blobUrlRef.current) {
URL.revokeObjectURL(blobUrlRef.current)
}
blobUrlRef.current = URL.createObjectURL(blob)
hiddenAnchorRef.current!.href = blobUrlRef.current
hiddenAnchorRef.current!.click()
})
}
Note that if you doubled the size of the canvas on e.g. retina screens to get extra sharpness (I do this in canvasPreview.ts
based on window.devicePixelRatio
), then you also need to size the canvas down by a factor of window.devicePixelRatio
which makes things more complicated. You would have to copy to an offscreen canvas that is a normal size first.
function onSubmitCrop() { if (completedCrop) { // create a canvas element to draw the cropped image const canvas = document.createElement("canvas"); // get the image element const image = imgRef.current; // draw the image on the canvas if (image) { const crop = completedCrop; const scaleX = image.naturalWidth / image.width; const scaleY = image.naturalHeight / image.height; const ctx = canvas.getContext("2d"); const pixelRatio = window.devicePixelRatio; canvas.width = crop.width * pixelRatio * scaleX; canvas.height = crop.height * pixelRatio * scaleY; if (ctx) { ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0); ctx.imageSmoothingQuality = "high"; ctx.drawImage( image, crop.x * scaleX, crop.y * scaleY, crop.width * scaleX, crop.height * scaleY, 0, 0, crop.width * scaleX, crop.height * scaleY ); } const base64Image = canvas.toDataURL("image/png"); // can be changed to jpeg/jpg etc if (base64Image) { // @ts-ignore const fileType = base64Image.split(";")[0].split(":")[1]; const buffer = Buffer.from( base64Image.replace(/^data:image\/\w+;base64,/, ""), "base64" ); const file = new File([buffer], fileName, { type: fileType }); onSubmit(file); // function passed as a prop } } } }
This works magic! For anyone with buffer error, just npm i buffer
and import {Buffer} from 'buffer';
it should solve the issue.
If your backend is using multer package to parce, you can do
const formDataForImage = new FormData();
formDataForImage.append('file', fileCropped);
then attach that formDataForImage as obj in the body in the post request, it should work.
@DominicTobias Can you also add the above solution in the documentation as reference? Thanks!
Hi, it worked locally in dev but I ran into a lot of issues with the build because of the Buffer. 😅 Currently using Vite/React and I have referred to this solution: https://stackoverflow.com/questions/72773373/buffer-is-not-exported-by-vite-browser-externalbuffer
I used the OP's inject method:
rollupOptions: {
plugins: [inject({Buffer: ['Buffer', 'Buffer']})],
external: ['Buffer'],
},
but I am getting errors
Uncaught TypeError: Failed to resolve module specifier "Buffer". Relative references must start with either "/", "./", or "../".
in deployment ( it pass the build in pipeline). So I don't think I write it correctly.... I know this is probably a Vite related issue, but in case anyone knows, please give me some tip on how to fix this? Thanks! 🙏
Hi, I solved my issues now:
By now I completely ditched the previous solution.
npm i process buffer
. <script>
window.global = window;
</script>
<script type="module">
import {Buffer} from 'buffer/'; // <-- no typo here ("/")
import process from 'process';
window.Buffer = Buffer;
window.process = process;
</script>
resolve: {
alias: {
process: 'process/browser',
},
},
import {Buffer} from 'buffer/index.js';
I am not able to locate any information in the docs on how to actually access the cropped version of the image, so that it can be used. It appears I am not alone. These all seems to be variations on the same question: #525, #523, #522, #501, #457, and #501.
If you could please update the docs (or point it out in case I missed it) for how to actually access the cropped version of the image, that would great. Thank you.