내 WPF 응용 프로그램에는 비트 맵의 일부를 표시하기 위해 특별히 작성한 사용자 지정 컨트롤이 있습니다. 비트 맵은 내 회사의 백엔드 Windows 서비스에서 내 프로그램으로 전송 된 객체에 포함되어 있으며 byte
배열입니다. 데이터에 포함되는 것은 직사각형이며 관심있는 이미지의 부분을 표시해야합니다.클립 영역이 작동하지 않습니다.
또한 사용자가 컨트롤을 클릭하면 해당 영역의 세 가지 다른 "배율"사이를 전환합니다. 이 설정을 "줌 상태"라고합니다. 기본적으로 한 설정에서 표시되는 사각형의 너비는 데이터와 함께 전송되는 사각형으로 지정된 영역보다 60 픽셀 큽니다. 두 번째 설정에서 사각형의 너비는 25 % 증가하고 세 번째 설정에서는 50 % 증가합니다. 높이는 항상 비트 맵 부분의 종횡비가 컨트롤과 동일하게 유지되도록 계산됩니다.
지금까지 나는 위에서 설명한 사각형 계산에 의해 지정된 영역으로 잘린 데이터에서 새로운 비트 맵을 생성 해 왔습니다. 그러나 우리가받은 데이터의 양과 비트 맵의 크기를 고려할 때 이것은 엄청난 양의 메모리를 사용하고 있습니다. 나는 메모리 소비를 줄이는 방법을 찾아야한다.
자르기에 대한 검색을 WPF &에서 찾았습니다. 이미지를 자르면 this MSDN article이 나옵니다. 이것은 이미 이상하게 보였습니다. 저는 이미 직사각형을 계산 중입니다. 메모리가 적게 사용됩니다. 따라서 오늘 아침에 코드를 수정하여 원래 이미지 &을 Int32Rect
에서 CroppedBitmap
으로 만드는 대신 RetangleGeometry
구조체를 만들고이 사각형에 컨트롤의 Clip
속성을 설정합니다. 결과는, 그러나, 나는 아무것도 전혀 보지 않고있다.
RectangleGeometry
을 만드는 코드를 주석 처리했으며 그 시점에서 컨트롤의 전체 이미지를 보았으므로이 문제는 사각형을 계산하는 코드 어딘가에 있음을 알고 있습니다. 코드의 계산이 옳다는 것을 알고 있지만, RectangleGeometry
으로 변환하면 뭔가 빠져 나가야합니다.
<Style TargetType="{x:Type local:ZoomableImage}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ZoomableImage}">
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
ContextMenu="{TemplateBinding ContextMenu}"
Cursor="{TemplateBinding Cursor}"
Margin="{TemplateBinding Margin}"
Name="ImageBorder">
<Image BitmapEffect="{TemplateBinding BitmapEffect}"
BitmapEffectInput="{TemplateBinding BitmapEffectInput}"
CacheMode="{TemplateBinding CacheMode}"
Effect="{TemplateBinding Effect}"
HorizontalAlignment="Stretch"
Name="Image"
Source="{TemplateBinding ImageToBeZoomed}"
Stretch="{TemplateBinding Stretch}"
VerticalAlignment="Stretch" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
을 그리고 여기에 클립 사각형을 계산하는 코드이다 :
private void CreateClipRectangle() {
Rect srcRect = new Rect(PlateRectangle.X, PlateRectangle.Y, PlateRectangle.Width, PlateRectangle.Height);
// We want to show some pixels outside the plate's rectangle, so add 60 to the PlateRectangle's Width.
srcRect.Width += 60.0;
// Adjust the Width property for the ZoomState, which increases the height & width of the rectangle around the license plate
if (ZoomState == ZoomStates.ZoomPlus25) {
srcRect.Width = srcRect.Width * 1.25;
} else if (ZoomState == ZoomStates.ZoomPlus50) {
srcRect.Width = srcRect.Width * 1.50;
}
// Make sure that srcRect.Width is not bigger than the ImageToBeZoomed's PixelWidth!
if (srcRect.Width > ImageToBeZoomed.PixelWidth) srcRect.Width = ImageToBeZoomed.PixelWidth;
// We need to keep the aspect ratio of the source rectangle the same as the Image's.
// Compute srcRect.Height so the srcRect will have the correct aspect ratio, but don't let
// the rectangle's height get bigger than the original image's height!
srcRect.Height = Math.Min(ImageToBeZoomed.PixelHeight, Math.Round(srcRect.Width * ImageBorder.ActualHeight/ImageBorder.ActualWidth));
// Adjust srcRect.X & srcRect.Y to center the source image in the output image
srcRect.X = srcRect.X - (srcRect.Width - PlateRectangle.Width )/2.0;
srcRect.Y = srcRect.Y - (srcRect.Height - PlateRectangle.Height)/2.0;
// Adjust srcRect to keep the cropped region from going off the image's edges.
if (srcRect.X < 0) srcRect.X = 0.0;
if (srcRect.Y < 0) srcRect.Y = 0.0;
if ((srcRect.X + srcRect.Width ) > ImageToBeZoomed.PixelWidth ) srcRect.X = ImageToBeZoomed.PixelWidth - srcRect.Width;
if ((srcRect.Y + srcRect.Height) > ImageToBeZoomed.PixelHeight) srcRect.Y = ImageToBeZoomed.PixelHeight - srcRect.Height;
// Create a new RectangleGeometry object that we will use to clip the ImageToBeZoomed and put it into the Clip property.
ImageControl.Clip = new RectangleGeometry(srcRect, 0.0, 0.0);
}
ImageToBeZoomed
유형 BitmapSource
의 인 DependencyProperty
입니다
PlateRectangle
속성
public static BitmapImage BitmapFromBytes(byte[] imageBytes) {
BitmapImage image = null;
if (imageBytes != null) {
image = new BitmapImage();
try {
using (MemoryStream memoryStream = new MemoryStream(imageBytes)) {
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.StreamSource = memoryStream;
image.EndInit();
// Freeze the BitmapImage. This helps plug memory leaks & saves memory.
image.Freeze();
}
} catch (Exception ex) {
// . . .
}
}
return image;
}
값은 ints
그리고 그들이 픽셀 같습니다 byte
어레이는이 코드를 사용하여 BitmapImage
로 변환된다. 문제가 픽셀에서 장치 독립적 인 단위로 변환해야 할 필요가있을 수 있습니까?
이 함께 연주에서 편집 한
, 나는 내가 Y는 0 또는 음의 값 이외의 다른 RectangleGeometry
구조체의 Rect
재산의 좌표를 설정하면 내가 어떤 이미지를 볼 것으로 나타났습니다. 이것은 나에게 의미가 없습니다. 대부분의 경우 관심 영역은 이미지 중간에 있습니다 & 아니 상단 또는 하단 가장자리 근처. 누구에게 이것이 왜 그렇게 대단한 아이디어가 있습니까?
편집 2
암 i를 WPF Clip
기능에 문제가있는 하나?
예를 들어 픽셀 버퍼의 복사본을 만드는 것이 간단합니까? [이 답변] (http://stackoverflow.com/a/23810646/1136211)에 나와 있습니다. – Clemens
그게 정확히 내가하고 있었던 일이고 비효율적입니다. 프로그램의 메모리 사용을 줄이려고합니다. –
샘플 이미지 데이터로 코드 샘플을 게시 할 수 있습니까? 나는 그래픽에 몇 가지 특급을 가지고 있는데, 당신을 위해 뭔가를 가질 수 있습니다. – pushpraj