문제

I've a set of images that I'm programmatically drawing a simple watermark on them using System.Windows and System.Windows.Media.Imaging (yes, not with GDI+) by following a tutorial in here.

Most of the images are not more than 500Kb, but after applying a simple watermark, which is a text with a transparent background, the image size is drastically increasing.

For example, a 440Kb image is becoming 8.33MB after applying the watermark with the below method, and that is shocking me.

private static BitmapFrame ApplyWatermark(BitmapFrame image, string waterMarkText) {
    const int x = 5;
    var y = image.Height - 20;
    var targetVisual = new DrawingVisual();
    var targetContext = targetVisual.RenderOpen();
    var brush = (SolidColorBrush)(new BrushConverter().ConvertFrom("#FFFFFF"));
    brush.Opacity = 0.5;
    targetContext.DrawImage(image, new Rect(0, 0, image.Width, image.Height));
    targetContext.DrawRectangle(brush, new Pen(), new Rect(0, y, image.Width, 20));
    targetContext.DrawText(new FormattedText(waterMarkText, CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
                             new Typeface("Batang"), 13, Brushes.Black), new Point(x, y));
    targetContext.Close();
    var target = new RenderTargetBitmap((int)image.Width, (int)image.Height, 96, 96, PixelFormats.Default);
    target.Render(targetVisual);
    var targetFrame = BitmapFrame.Create(target);
    return targetFrame;
}

I've noticed that the image quality is improved compared than the original image. The image is more smoother and colors are more lighter. But, you know I don't really want this. I want the image to be as it is, but include the watermark. No quality increases, and of course no drastic changes in image size.

Is there any settings that I'm missing in here to tell my program to keep the quality as same as source image? How can I prevent the significant change of the image size after the changes in my ApplyWatermark method?

Edit

1. This is how I convert BitmapFrame to Stream. Then I use that Stream to save the image to AmazonS3

private Stream EncodeBitmap(BitmapFrame image) {
    BitmapEncoder enc = new BmpBitmapEncoder();
    enc.Frames.Add(BitmapFrame.Create(image));
    var memoryStream = new MemoryStream();
    enc.Save(memoryStream);
    return memoryStream;
}

2. This is how I get the BitmapFrame from Stream

private static BitmapFrame ReadBitmapFrame(Stream stream) {
    var photoDecoder = BitmapDecoder.Create(
        stream,
        BitmapCreateOptions.PreservePixelFormat,
        BitmapCacheOption.None);
    return photoDecoder.Frames[0];
}

3. This is how I read the file from local directory

public Stream FindFileInLocalImageDir() {
    try {
        var path = @"D:\Some\Path\Image.png";
        return !File.Exists(path) ? null : File.Open(path, FileMode.Open, FileAccess.Read,  FileShare.Read);
        } catch (Exception) {
            return null;
    }
}
도움이 되었습니까?

해결책 2

The reason I asked my question in the comments earlier, is because I noticed there were several different encoders available. A bitmap usually has a significantly larger file size, due to the amount of information it's storing about your image.

I haven't tested this myself, but have you tried a different encoder?

var pngEncoder = new PngBitmapEncoder();
pngEncoder.Frames.Add(ApplyWatermark(null, null));

MemoryStream stm = File.Create(image);
pngEncoder.Save(stm);
return stm;

다른 팁

The problem is that when you edit the image, the compression is gone. A 730x1108 JPG with 433kB disc size with 32bit (you mentioned transparency, so ARGB) will need at least 730 * 1108 * 4 = 3,09MB on disc. Of course you can compress it afterwards again (for disc, network stream of what else).

This is the reason why image software always needs much memory even when working with compressed data.

Conclusion: You will need the free memory to work with the image. Not possible to have it otherwise completly at hand.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top