2009-11-16 4 views
10

많은 수의 이미지의 크기를 조정해야하는 상황이 있습니다. 이 이미지는 현재 파일 시스템에 .jpg 파일로 저장되어 있지만 나중에 프로젝트의 메모리에 byte []가 있어야합니다. 원본 이미지 크기는 가변적이지만 출력은 미리 정해진 3 가지 크기 여야합니다. 가로 세로 비율은 원본 이미지를 공백으로 채 웁니다 (즉, 높이가 큰 이미지는 정사각형 타겟 이미지 크기에 맞도록 크기가 조정되며 왼쪽 및 오른쪽에 흰색이 넓게 나타납니다).이미지 크기 조정 성능 : System.Drawing 대 System.Windows.Media

처음에는 .NET 2.0을 대상으로 프로젝트를 빌드하고 System.Drawing 클래스를 사용하여로드/크기 조정/저장을 수행했습니다. 관련 코드가 포함

original = Image.FromFile(inputFile); //NOTE: Reused for each of the 3 target sizes 
Bitmap resized = new Bitmap(size, size); 
//Draw the image to a new image of the intended size 
Graphics g = Graphics.FromImage(resized); 
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; 
g.Clear(Color.White); 
g.DrawImage(original, center - width/2f, center - height/2f, width, height); 
g.Dispose(); 
//Save the new image to the output path 
resized.Save(outputFile, ImageFormat.Jpeg); 

내가, .NET 3.5 포트에이 프로젝트를 원하므로 동일한 기능을 수행 할 System.Windows.Media 클래스를 사용했습니다. 나는 그것을 작동 시키지만 성능은 끔찍하다. 이미지 당 처리 시간은 약 50 배 더 길다. 대다수의 시간은 이미지를로드하는 데 소비됩니다. 관련 코드는 다음을 포함합니다 :

BitmapImage original = new BitmapImage(); //Again, reused for each of the 3 target sizes 
original.BeginInit(); 
original.StreamSource = new MemoryStream(imageData); //imageData is a byte[] of the data loaded from a FileStream 
original.CreateOptions = BitmapCreateOptions.None; 
original.CacheOption = BitmapCacheOption.Default; 
original.EndInit(); //Here's where the vast majority of the time is spent 
original.Freeze(); 

// Target Rect for the resize operation 
Rect rect = new Rect(center - width/2d, center - height/2d, width, height); 

// Create a DrawingVisual/Context to render with 
DrawingVisual drawingVisual = new DrawingVisual(); 
using (DrawingContext drawingContext = drawingVisual.RenderOpen()) 
{ 
    drawingContext.DrawImage(original, rect); 
} 

// Use RenderTargetBitmap to resize the original image 
RenderTargetBitmap resizedImage = new RenderTargetBitmap(
    size, size,       // Resized dimensions 
    96, 96,        // Default DPI values 
    PixelFormats.Default);    // Default pixel format 
resizedImage.Render(drawingVisual); 

// Encode the image using the original format and save the modified image 
SaveImageData(resizedImage, outputFile); 

나는 많은 시간을 들이기 위해 무엇인가 잘못하고 있습니까? 나는 URI를 취하는 BitmapImage의 생성자를 사용하여 동일한 성능 문제를 시도했다. 누구든지 이전에 이와 같은 작업을 수행 한 적이 있습니까?이를 수행하기위한 성능 향상 방법이 있는지 알고 있습니까? 아니면 그냥 System.Drawing을 사용해야할까요? 감사!

답변

10

그리고 그 모든 내용을 입력하면 System.Windows.Media 클래스의 MS에서 심볼을로드하고 느리게 진행되는 단계를 수행 할 수있었습니다. 즉시 원인과 해결책을 찾았습니다. 입력 이미지가 색상 프로파일과 함께 저장되었으며 각 이미지의 색상 프로파일 (파일 시스템에서)을로드하려고 시도했습니다. 위의 코드에서 BitmapCreateOptions.None을 BitmapCreateOptions.IgnoreColorProfile로 전환하면 더 이상이 작업을 수행하지 않고 System.Drawing과 동일한 속도로 수행합니다.

희망 사항은이 문제에 부딪히는 다른 사용자에게 도움이되기를 바랍니다.

+0

팁 주셔서 감사합니다! – Jan

0

나는 관련이있을 수 MSDN에 System.Drawing 페이지에서이 생각 :

System.Drawing 네임 스페이스가 GDI + 기본 그래픽 기능에 대한 액세스를 제공합니다. System.Drawing.Drawing2D, System.Drawing.Imaging 및 System.Drawing.Text 네임 스페이스에 고급 기능이 제공됩니다. Graphics 클래스는 표시 장치에 그리는 방법을 제공합니다. Rectangle 및 Point와 같은 클래스는 GDI + 프리미티브를 캡슐화합니다. Pen 클래스는 선과 곡선을 그리는 데 사용되고 추상 클래스 Brush에서 파생 된 클래스는 도형의 내부를 채우는 데 사용됩니다. System.Drawing를 사용하여

당신이 System.Windows.Media를 통해 갈 것보다 실제 기본 그래픽 기능에 가까운 :

도면, 텍스트, 오디오/비디오 등이 포함 된 리치 미디어의 통합을 가능하게 객체를 정의 WPF (Windows Presentation Foundation) 응용 프로그램 내의 내용

System.Drawing은 여전히 ​​지원됩니다.

0

코드에서 흥미로운 상황을 발견했습니다.

using(DrawingContext drawingContext = drawingVisual.RenderOpen()) 

내가 왜이 속도까지 코드 모르겠지만, 당신은 그것을 시도를 제공 할 수 있습니다 : 다음 줄에서using를 제거 .

+2

그렇게하면 코드가 실제로 렌더링되지 않으므로 속도가 빨라집니다. 드로잉 컨텍스트는 실제로 드로잉 컨텍스트가 drawContext.Close()를 호출하거나 drawContext가 스코프 (사용법)에서 벗어날 때까지 언더 레이 비주얼에 대한 지시를 그릴 수 없습니다. –

+0

멋진 정보, 타이! –

5

어려운 일을하는 것처럼 보입니다. DecodePixelHeight 및 DecodePixelWidth를 설정하여 WPF가 작업을 수행하도록 할 수 있습니다. 이것은 크기 조정 이미지를로드하는 동안 발생하게됩니다 :

BitmapImage resizedImage = new BitmapImage 
{ 
    StreamSource = new MemoryStream(imageData), 
    CreateOptions = BitmapCreateOptions.IgnoreColorProfile, 
    DecodePixelHeight = height, 
    DecodePixelWidth = width, 
} 
resizedImage.BeginInit(); // Needed only so we can call EndInit() 
resizedImage.EndInit(); // This does the actual loading and resizing 

imageSaveImageData(resizedImage, outputFile); 

은 또한 당신이 내 코드에서 발견 된 IgnoreColorProfile 솔루션을 포함.

업데이트 당신의 질문을 다시 읽고 DrawingVisual을 사용하는 이유는 이미지 주위에 공백이 있어야 사각형이됩니다. DecodePixelHeight 및 DecodePixelWidth는 목표를 달성하지 못하므로 내 솔루션이 질문에 대답하지 않습니다.

공백없이 크기를 조정해야하는 사람이이 질문에 해당하는 경우를 대비하여 여기에 대한 답을 남겨 둘 것입니다.