How save an image on the server after changing it on the view layer?

SaeedP

Well-known member
Joined
Oct 21, 2020
Messages
113
Programming Experience
3-5
Hello

Consider I upload an image to the server, then I changed some elements of the image with an image editor on the view layer (assume the view layer uses an image editor) then how can I save it as a new image on the server? (I mean how should be the back end code).

regards,
Saeed
 
Last edited:
The view layer of supposed to just a way for the user to interact with the data model. So if the view layer updates the image, your data model should have all the changes. Just save those changes back to into your data store.

How did your upload code save to your data store initially? You would do the same kind of logic, except the data should already be available to you on the server side unless your image editor only works client side and does not update the data model on the server side. In that case, you will have no choice but to resend the updated image for upload again.
 
The view layer of supposed to just a way for the user to interact with the data model. So if the view layer updates the image, your data model should have all the changes. Just save those changes back to into your data store.
i mean if we dont want to change the main image and want to save the new image with another neme.
 
Then save the image with a new name first, and then have the view backed by that new image. As the user edits the image, the changes her saved to the new image.
 
Yes, and if the view is rendering that data from whatever model set it's state, and as the OP stated, his view is able to edit the image, then the data should be updated. Then whatever model that set the state should be notified that the underlying data has been changed, and there for should persist it.

Or are you saying that in MVC, the controller will only take data one way from the model and put it into the view. The controller should never take notifications from the view of changes made by the user, and update the model based on those changes?
 
You mean I should use this code:

C#:
[HttpPost]
        public async Task<ActionResult<Image>> PostImage([FromForm] ImageData imageData)
        {
            if (imageData.File.Length > 0)
            {
                string path = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", imageData.File.FileName);
                using (var stream = System.IO.File.Create(path))
                {
                    await imageData.File.CopyToAsync(stream);
                }

                Image file = await _context.Images.FirstOrDefaultAsync(f => f.FileName == imageData.File.FileName);
                if (file == null)
                {
                    Image image = new Image()
                    {
                        ContentType = imageData.File.ContentType,
                        DateModified = DateTime.Now,
                        FileName = imageData.File.FileName,
                        Path = path,
                        //Description = imageData.Description
                    };
                    _context.Images.Add(image);
                    await _context.SaveChangesAsync();
                    return CreatedAtAction(nameof(GetImage), new { id = image.ImageId }, image);
                }
                else
                {
                    return BadRequest($"The path, {path}, already exists. Submit an HTTP PUT to update the image.");
                }
            }
            return BadRequest($" {nameof(PostImage)} Error: The image file is {imageData.File.Length} bytes.");
        }


There are some questions in my mind:

- Do I should use the post attribute?
- If I want to give the saved image another name, what should I do?

The view layer is written in Vue js and the app also has a view model layer.


thanks
 
As a result of lines 6-10, you already have copy of the image sitting on your server. (Really bad idea to store untrusted data straight into your WWW root, BTW!!!)

To get another copy of that image file, just use File.Copy() with a new destination name.

So now that only problem left is how to "bind" that new image with your view that allows the editing. That really depends on what your image editing widget does and how it transmits the edits back up to the serve. Does it use HTTP POST to upload a complete new updated image? Does it use HTTP PUT to try to transmit just the deltas? Depending on how data is sent by the view, you would have to make a corresponding reciever in your controller.
 
From the last 8 websites I built this year, this is how I recommend doing it. This is also how I done it. Your problem can be solved from 1, 2. But to do it properly, read from 1, 10. Read below the quote below to know why.
  1. First. Lines 12 to 30 can be deleted or better move them in-place of line 8.
  2. Don't upload files to a root folder.
  3. Allowing uploaded files to be uploaded by users should be avoided if possible. If not avoidable;
  4. Create an uploads path for files to be created. This will not be used for uploading files!
  5. Record the print (finger print) of the file uploaded using MD5/SHA/etc, and store the print as a new file name in a directory outside your wwwroot. Ie. Do not write bytes of data to this file other than the print used to name it. Ex: 2V5M1M7N3NB5D08H7YP28.jpg or whatever the MD5 generates. It's the finger print of the file.
  6. Don't use this path, as it's accessible via IP. C:\inetpub*. Your images filenames need to be uploaded to a directory outside your site root ie no. 4. (May require a permission grant from the folder owner depending where you store them.)
  7. Interpret the file type being uploaded by reading the extension used by the uploader (this does not prove the extension type), but with it you can confirm its a format you accept, and then store the print (as explained on 5) of the whole file as the value for a database 'id' field and store the files bytes into a 'filebytes' field in a database table. It's recommended to store these values into a separate database to your main project. And definitely don't store them on the file system until you re-construct the image.
  8. Now the file exists in the database, you can read the bytes into a writer and attempt to write the new image into the empty file you created earlier used in step 5. Remember to recreate the image from the data.
  9. Take the new file path you just built from the writer, and produce it to your model to be presented to your new view. The unique id we created gives the file a unique filename so you are unlikely to have conflicting filenames. It would be logical to store additional info about the user uploading the file to your files database table so you can later identify which user owns which file. (This assumes you are not using anonymous uploads.)
  10. If the file does not create, it will be because the frameworks failed to construct the new image due to tampering by the user who uploaded it. Reconstructing an image is the only way to "securely" accept one. .Net Frameworks offers limited security for this.
I suggest reading up on byte array to image conversion. You will do your reading with a memorystream, and write your files using systemio.

As a result of lines 6-10, you already have copy of the image sitting on your server.
Be careful. This only creates a copy of the uploaded file and it does not recreate the image as a new image, which is a security risk.
 
Last edited:
I know. That's why I wrote the sentence about untrusted data immediately after that.
 
I am sorry, I seemed to have skimmed over the bracketed message you wrote. I specifically picked on this part of your post :
As a result of lines 6-10, you already have copy of the image sitting on your server.
Because you was implying to use the image just uploaded, and as its wrote, it didn't imply that a new image MUST be created for security reasons. (Don't perceive the caps as shouting. Just emphases.)
I was actually doubtful that my post made the sense it made to me when I first wrote it. So I re-edited it to add extra clarity hoping the OP understood. So I'll assume that thumbs up is an agreement to my suggestion!
The view layer is written in Vue js and the app also has a view model layer.
I did however miss this quoted above though when skimming the code. Although this wasn't in the opening thread, its necessary to include facts like this so you get one post, one reply with the answers you need. Rather than me replying two times due to you not mentioning this at the start of your opening thread. Anyway...

What you can do here, is; you can call forceRerender to update your view since you are using VueJS. this means that you can take new data from the image editor and update it through VueJs. Calling a method such as forceRerender can re-render your view even if you never changed anything in it. That is one of the benefits of VueJS, is that you can add and remove elements from the dom at ease just like in this quick snip :

C#:
forceRerender() {
    //Remove from dom
    this.renderComponent = false;
    //https://vuejsdevelopers.com/2019/01/22/vue-what-is-next-tick/
    this.$nextTick().then(() => {
    //Add back to dom
    this.renderComponent = true;
  });
}
forceRerender() is a method of NodeJS used throughout the distros competitors. So it can be used in Angular, React, Etc.
 
Back
Top Bottom