5

I want to watermark files in a folder with another image. However, am getting the error

'Parameter Not Valid'

when invoking the code

img.Save(filepath, System.Drawing.Imaging.ImageFormat.Jpeg);

I have the following code;

    public static string WatermarkImagesInFolder(string url)
    {
        if (url == null)
            throw new Exception("URL must be provided");

        string path = HttpContext.Current.Server.MapPath(url);

        if (!Directory.Exists(path))
            throw new DirectoryNotFoundException();

        Directory.CreateDirectory(String.Format(@"{0}\watermarked", path));

        List<string> urls = GetJpgFilesFromFolder(path);

        foreach (string imageUrl in urls)
        {
            Image img = WatermarkImage(imageUrl);

            string filename = Path.GetFileName(imageUrl);
            string filepath = String.Format(@"{0}\watermarked\{1}", path, filename);
            img.Save(filepath, System.Drawing.Imaging.ImageFormat.Jpeg);
        }

        return "complete";
    }

and

    public static Image WatermarkImage(string filename)
    {
        using (Image image = Image.FromFile(filename))
        using (Image watermarkImage = Image.FromFile(HttpContext.Current.Server.MapPath(ConfigurationManager.AppSettings["WatermarkImageUrl"])))
        using (Graphics imageGraphics = Graphics.FromImage(image))
        using (TextureBrush watermarkBrush = new TextureBrush(watermarkImage))
        {
            int x = (image.Width / 2 - watermarkImage.Width / 2);
            int y = (image.Height / 2 - watermarkImage.Height / 2);
            watermarkBrush.TranslateTransform(x, y);
            imageGraphics.FillRectangle(watermarkBrush, new Rectangle(new Point(x, y), new Size(watermarkImage.Width + 1, watermarkImage.Height)));
            return image;
        }
    }

as an example of input for img.save;

img.save("C:\\IMAGES\\wateremarked\\IMAGE (1).jpg", System.Drawing.Imaging.ImageFormat.Jpeg);

any ideas on what could be causing the error here please?

Udhay Titus
  • 5,761
  • 4
  • 23
  • 41
Matthew Flynn
  • 3,661
  • 7
  • 40
  • 98

2 Answers2

10

In your WatermarkImage you have the image object in a using statement. As soon as that goes out of scope, Dispose is invoked on the image. You would need to return a copy of the image - or not use the using statement & ensure you dispose properly later.

See : Exception: Parameter is not valid (on passing new image to pictureBox)

public static string WatermarkImagesInFolder(string url)
{
    if (url == null)
        throw new Exception("URL must be provided");

    string path = HttpContext.Current.Server.MapPath(url);

    if (!Directory.Exists(path))
        throw new DirectoryNotFoundException();

    Directory.CreateDirectory(String.Format(@"{0}\watermarked", path));

    List<string> urls = GetJpgFilesFromFolder(path);

    foreach (string imageUrl in urls)
    {
        using(Image img = WatermarkImage(imageUrl))
        {
        string filename = Path.GetFileName(imageUrl);
        string filepath = String.Format(@"{0}\watermarked\{1}", path, filename);
        img.Save(filepath, System.Drawing.Imaging.ImageFormat.Jpeg);
        }
    }

    return "complete";
}

public static Image WatermarkImage(string filename)
{
    Image image = Image.FromFile(filename);
    using (Image watermarkImage = Image.FromFile(HttpContext.Current.Server.MapPath(ConfigurationManager.AppSettings["WatermarkImageUrl"])))
    using (Graphics imageGraphics = Graphics.FromImage(image))
    using (TextureBrush watermarkBrush = new TextureBrush(watermarkImage))
    {
        int x = (image.Width / 2 - watermarkImage.Width / 2);
        int y = (image.Height / 2 - watermarkImage.Height / 2);
        watermarkBrush.TranslateTransform(x, y);
        imageGraphics.FillRectangle(watermarkBrush, new Rectangle(new Point(x, y), new Size(watermarkImage.Width + 1, watermarkImage.Height)));
        return image;
    }
}
Community
  • 1
  • 1
PaulF
  • 6,673
  • 2
  • 18
  • 29
0

Here is my alternative solution, which gives the ability to use picture stream, but not it's location as it's currently browsed from Kendo Control as in my example and it still have not physical location yet.

    public static Image ApplyWatermark(HttpPostedFileBase img, string appDataPath)
{
    Image resultImage = null;
    using (Image image = Image.FromStream(img.InputStream))
    {
        using (Image watermarkImage = Image.FromFile(appDataPath + "\\Watermark\\sample-watermark.png"))
        {
            using (Graphics imageGraphics = Graphics.FromImage(image))
            {
                using (Brush watermarkBrush = new TextureBrush(watermarkImage))
                {
                    imageGraphics.FillRectangle(watermarkBrush, new Rectangle(new Point(0, 0), image.Size));
                    resultImage = (Image)image.Clone();
                }
            }
        }
    }

    return resultImage;
}

private void SaveImagesOnDisk(IEnumerable<HttpPostedFileBase> images, int rentalPropertyId)
    {
        if (images != null)
        {
            foreach (var file in images)
            {
                // Some browsers send file names with full path. This needs to be stripped.
                var fileName = Path.GetFileName(file.FileName);
                var appDataPath = this.Server.MapPath("~/App_Data/");
                var newPath = Path.Combine(appDataPath, rentalPropertyId.ToString());
                if (!Directory.Exists(newPath))
                {
                    DirectoryInfo di = Directory.CreateDirectory(newPath);
                }

                var physicalPath = Path.Combine(newPath, fileName);
                System.Drawing.Image markedImage = Helper.ApplyWatermark(file, appDataPath);
                markedImage.Save(physicalPath, System.Drawing.Imaging.ImageFormat.Png);
            }
        }

        //return this.Json(new { status = "OK" }, "text/plain");
    }
ppenchev
  • 127
  • 1
  • 10