Reputation: 873
I'm facing with an problem which is at my opinion not working.
I did install a library in angular cropper.js
https://github.com/matheusdavidson/angular-cropperjs
And in the Frontend I am dealing with some code that the developer developed this library.
So my iteration will be like this.
the cropped image will be sent to my api in backend and there to save the files and to show the file in some other place.
The actual crop it saves a link with blob and there is my img.
The post request it works and I can see the img is there in the folder but when I try to get the image the get it works but in the console of frontend it says me that.
GET http://localhost:4200/images/image-1607708300007.jpg 404 (Not Found)
But in the GET
request it is the image there.
{"_id":"5fd3bf6f946e9c40163d82f3",
"imageTitle":"undefined",
"imageDesc":"undefined",
"imageUrl":"/images/image-1607712623266.jpg",
"uploaded":"2020-12-11T18:50:23.288Z","__v":0}
But if I try with postman to get this it is not working.
I am trying in postman like this.
http://localhost:4200/images/image-1607713934301.jpg
it is the same error mesage as in console.
`<pre>Cannot GET /images/image-1607713934301.jpg</pre>`
If I try to log what the frontend it sends to backend I do have something like.
console.log(req.file);
{ fieldname: 'file',
originalname: 'acf6a796-7b4b-4b12-b429-1d21352f3a45.jpeg',
encoding: '7bit',
mimetype: 'image/jpeg',
destination: '/Users/abedinzhuniqi/Projects/xxxx/images',
filename: 'image-1607712623266.jpg',
path:
'/Users/abedinzhuniqi/Projects/xxxx/images/image-1607712623266.jpg',
size: 1540633 }
This is my frontend code. This is the html.
<angular-cropper #angularCropper
[cropperOptions]="imgConfig"
[imageUrl]="imgUrl | safeurl"></angular-cropper>
<div class="btn-group">
<label class="btn btn-primary btn-upload" for="inputImage" title="Upload image file" >
<input type="file" class="sr-only" id="inputImage" name="file" accept="image/*" (change)="fileChangeEvent($event)">
<span class="docs-tooltip" data-toggle="tooltip" title="" data-original-title="Import image with Blob URLs">
<span class="fa fa-upload"></span>
</span>
</label>
</div>
<button type="button" class="btn btn-primary" data-method="crop" title="Crop" (click)="saveImage()">
<span class="docs-tooltip" data-toggle="tooltip" title="" data-original-title="cropper.crop()">
<span class="fa fa-check"></span>
</span>
</button>
And this is my TS.
imgUrl = "";
image: Image;
imageURL;
imgConfig = {
aspectRatio : 3/4,
dragMode : "move",
background : true,
movable: true,
rotatable : true,
scalable: true,
zoomable: true,
viewMode: 1,
checkImageOrigin : true,
checkCrossOrigin: true
};
fileChangeEvent(event: any): void {
this.imgUrl = URL.createObjectURL(event.target.files[0]);
this.image = event.target.files[0];
}
saveImage() {
console.log(this.image);
const file = new File([this.imgUrl], this.image.type);
this.imageService.addImage(this.image, file).subscribe((res: any) => {
if (res.body) {
this.imageService.getImageByID(res.body._id).subscribe((t: Image) => {
this.imageURL = t.imageUrl;
});
}
}, (err: any) => {
console.log(err);
});
}
This is the Service
export class ImageService {
apiUrl = environment.backend;
constructor(private http: HttpClient) { }
addImage(image: Image, file: File): Observable<any> {
const formData = new FormData();
formData.append("file", file);
formData.append("imageTitle", image.imageTitle);
formData.append("imageDesc", image.imageDesc);
const header = new HttpHeaders();
const params = new HttpParams();
const options = {
params,
reportProgress: true,
headers: header
};
const req = new HttpRequest("POST", this.apiUrl, formData, options);
return this.http.request(req);
}
getImageByID(id: string): Observable<any> {
const url = `${this.apiUrl}/${id}`;
return this.http.get<Image>(url).pipe(
catchError(this.handleError)
);
}
private handleError(error: HttpErrorResponse): any {
if (error.error instanceof ErrorEvent) {
console.error('An error occurred:', error.error.message);
} else {
console.error(
`Backend returned code ${error.status}, ` +
`body was: ${error.error}`);
}
return throwError(
'Something bad happened; please try again later.');
}
}
And my backend API looks like this.
const multer = require('multer');
const Image = require("../models/image");
const storage = multer.diskStorage({
destination: (req, file, cb) => {
console.log(cb);
cb(null, path.join(__dirname, '../../../../images'));
},
filename: (req, file, cb) => {
var filetype = '';
if(file.mimetype === 'image/gif') {
filetype = 'gif';
}
if(file.mimetype === 'image/png') {
filetype = 'png';
}
if(file.mimetype === 'image/jpeg') {
filetype = 'jpg';
}
cb(null, 'image-' + Date.now() + '.' + filetype);
}
});
const upload = multer({storage: storage});
routes.get('/:id', function(req, res, next) {
Image.findById(req.params.id, function (err, gallery) {
if (err) return next(err);
res.json(gallery);
});
});
// post data
routes.post('/', upload.single('file'), function(req, res, next) {
if(!req.file) {
return res.status(500).send({ message: 'Upload fail'});
} else {
req.body.imageUrl = req.file.filename;
Image.create(req.body, function (err, image) {
if (err) {
console.log(err);
return next(err);
}
res.json(image);
});
}
});
Upvotes: 4
Views: 777
Reputation: 6883
Your server should send image content. Currently you respond with only JSON which contains path to image, but not an image itself. To do so you need add static file middleware:
app.use('/images', express.static(path.join(process.cwd(), '../images'))
Then you should make your host produce correct URLs you'll need to update the object you return from server like this:
routes.get('/:id', function(req, res, next) {
Image.findById(req.params.id, function (err, gallery) {
if (err) return next(err);
res.json({
...gallery.toJSON(),
imageUrl: `//${req.host}:${req.port}/${gallery.imageUrl}`,
});
});
});
Thus you'll serve you static content and receive correct URLs on the frontend side.
Upvotes: 2