Модераторы: gambit, Kefir, Partizan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> [WPF] Window-размеры в пикселях и разрешение в dpi, как определить 
V
    Опции темы
marcusmae
Дата 12.4.2008, 21:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


stravaganza
**


Профиль
Группа: Участник
Сообщений: 874
Регистрация: 26.3.2006

Репутация: нет
Всего: 39



Здравствуйте, друзья,

Полдня изучаю WPF, возникли вопросы.

Отрендерил в RenderTargetBitmap изображение содержимого окна и через енкодер перенёс в bitmap. Этот битмап устанавливается затем на фон хостящегося в окне контрола Windows.Forms. Вот так :

Код

            VisualBrush visualBrush = new VisualBrush(this);
            DrawingVisual drawingVisual = new DrawingVisual();
            DrawingContext drawingContext = drawingVisual.RenderOpen();

            drawingContext.DrawRectangle(visualBrush, null,
                new Rect(new System.Windows.Size(this.Width, this.Height)));
            drawingContext.Close();

            RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap(
                (int)this.Width, (int)this.Height,
                96, 96, System.Windows.Media.PixelFormats.Pbgra32);
            renderTargetBitmap.Render(drawingVisual);
            BitmapEncoder bitmapEncoder = new BmpBitmapEncoder();
            bitmapEncoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
            System.IO.MemoryStream memoryStream = new System.IO.MemoryStream();
            bitmapEncoder.Save(memoryStream);
            Bitmap background = new Bitmap(memoryStream);
            //AnimatedLoadingWindow.Grayscale(background);
            this.loadingCircle.BackgroundImage = background;
            grid.Children.Add(this.host);


И что мы видим? Скриншот содержимого окна выглядит чуть-чуть по-больше, чем живой оригинал - некоторые кнопки вылезли за границы. Как это могло случиться? = Полагаю, дело либо в размерах, либо в разрешении.

1) Размеры окна считаются с границей или без? Если с границей, то как определить размеры без границ, если нету .ClientRectangle?
2) Как получить текущие значения горизонтального и вертикального разрешений в dpi?

Может, я ещё где-то неправ?..

Спасибо.


--------------------
ἀπὸ μηχανῆς θεός
PM MAIL ICQ GTalk   Вверх
marcusmae
Дата 12.4.2008, 21:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


stravaganza
**


Профиль
Группа: Участник
Сообщений: 874
Регистрация: 26.3.2006

Репутация: нет
Всего: 39



Стоит запостить вопрос, как решения начинают приходить сами собой smile

Что ж, дело было действительно в размерах! Размеры чего указаны для окна - по-прежнему точно не знаю, но мне-то нужны были размеры контейнера в окне. Этот контейнер - Grid. При том, что он развёрнут на всё окно (размер = авто), его длина и ширина меньше, чем у самого окна smile Именно их требовалось взять, чтоб скриншот пришёлс аккурат по размеру окна. Ну а dpi берутся из графики.

Код

        protected void BeginAnimatedLoading(Grid grid)
        {
            VisualBrush visualBrush = new VisualBrush(this);
            DrawingVisual drawingVisual = new DrawingVisual();
            DrawingContext drawingContext = drawingVisual.RenderOpen();

            drawingContext.DrawRectangle(visualBrush, null,
                new Rect(new System.Windows.Size(grid.ActualWidth, grid.ActualHeight)));
            drawingContext.Close();

            using (Graphics g = this.loadingCircle.CreateGraphics())
            {
                RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap(
                    (int)grid.ActualWidth,
                    (int)grid.ActualHeight,
                    g.DpiX, g.DpiY, System.Windows.Media.PixelFormats.Pbgra32);
                renderTargetBitmap.Render(drawingVisual);
                BitmapEncoder bitmapEncoder = new BmpBitmapEncoder();
                bitmapEncoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
                System.IO.MemoryStream memoryStream = new System.IO.MemoryStream();
                bitmapEncoder.Save(memoryStream);
                Bitmap background = new Bitmap(memoryStream);
                AnimatedLoadingWindow.Grayscale(background);
                this.loadingCircle.BackgroundImage = background;
            }
            grid.Children.Add(this.host);
        }



--------------------
ἀπὸ μηχανῆς θεός
PM MAIL ICQ GTalk   Вверх
marcusmae
Дата 16.4.2008, 14:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


stravaganza
**


Профиль
Группа: Участник
Сообщений: 874
Регистрация: 26.3.2006

Репутация: нет
Всего: 39



Небольшой experience для Базы Знаний.

Если кому интересно, то при более основательном рассмотрении рендеринг содержимого окна WPF с помощью RenderTargetBitmap оказался весьма глючным.

Код

        protected void StartAnimatedLoading(Grid grid)
        {
            using (DrawingContext drawingContext = this.drawingVisual.RenderOpen())
            {
                drawingContext.DrawRectangle(new VisualBrush(this), null,
                    new Rect(new System.Windows.Size(grid.ActualWidth,
                        grid.ActualHeight)));
            }

            using (Graphics gControl = this.loadingCircle.CreateGraphics())
            {
                RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap(
                    (int)grid.ActualWidth,
                    (int)grid.ActualHeight,
                    gControl.DpiX, gControl.DpiY, System.Windows.Media.PixelFormats.Pbgra32);
                renderTargetBitmap.Render(drawingVisual);

                BitmapEncoder bitmapEncoder = new BmpBitmapEncoder();
                bitmapEncoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
                System.IO.MemoryStream memoryStream = new System.IO.MemoryStream();
                bitmapEncoder.Save(memoryStream);
                renderTargetBitmap.Clear();
                Bitmap background = new Bitmap(memoryStream);

                // Apply translucent overlay.
                using (Graphics gBitmap = Graphics.FromImage(background))
                    gBitmap.FillRectangle(fillBrush, 0, 0,
                        background.Width, background.Height);

                this.loadingCircle.BackgroundImage = background;
            }
        }


Цитата

ArgumentException was unhandled
Cannot read from the specified command buffer pointer.

TargetSite = {Void SendCommand(Byte*, Int32)}


Возникает на строчке

Код

renderTargetBitmap.Render(drawingVisual);


Этот самый SendCommand каким-то образом связан, в частности с событиями : описанная ошибка возникает при повторном вызове .Render по событию, например, по клику на кнопку - первый раз всё строится, на второй и последующий - вываливает ArgumentException. Без событий всё нормаьно работает. Кто-нибудь что-нить думает по этому поводу? Я лично пока не представляю, что с этим можно поделать при том, что исключение недокументировано smile

Так что вернулся к более традиционному варианту - через Win32 :

Код

        #region Win32 Interop Methods
        [DllImport("gdi32.dll")]
        private static extern bool BitBlt(
            IntPtr hdcDest, // handle to destination DC 
            int nXDest,     // x-coord of destination upper-left corner 
            int nYDest,     // y-coord of destination upper-left corner 
            int nWidth,     // width of destination rectangle 
            int nHeight,    // height of destination rectangle 
            IntPtr hdcSrc,  // handle to source DC 
            int nXSrc,      // x-coordinate of source upper-left corner 
            int nYSrc,      // y-coordinate of source upper-left corner 
            Int32 dwRop     // raster operation code 
        );

        [DllImport("user32.dll")]
        private extern static IntPtr GetDC(IntPtr hWnd);

        [DllImport("user32.dll")]
        private extern static int ReleaseDC(IntPtr hWnd, IntPtr hDC);
        #endregion

        /// <summary>
        /// Begin indicating that an asynchronous operation is occuring.
        /// </summary>
        protected void StartAnimatedLoading(Grid grid)
        {
            WindowInteropHelper windowInteropHelper = new WindowInteropHelper(this);

            IntPtr srcDc = AnimatedLoadingWindow.GetDC(windowInteropHelper.Owner);

            Bitmap screenshot = new Bitmap( 
                (int)grid.ActualWidth, (int)grid.ActualHeight);

            // Create a GDI+ context from the created bitmap...
            using (Graphics g = Graphics.FromImage(screenshot))
            {
                System.Windows.Point location = grid.PointToScreen(
                    new System.Windows.Point(0,0));

                // Copy image of form into bitmap...
                IntPtr screenshotDc = g.GetHdc();
                AnimatedLoadingWindow.BitBlt(screenshotDc, 0, 0,
                    screenshot.Width, screenshot.Height,
                    srcDc, (int)location.X, (int)location.Y,
                    0x00CC0020 /* SRCCOPY */);

                // Release resources...
                AnimatedLoadingWindow.ReleaseDC(windowInteropHelper.Owner, srcDc);
                g.ReleaseHdc(screenshotDc);

                // Apply translucent overlay.
                g.FillRectangle(fillBrush, 0, 0, screenshot.Width, screenshot.Height);
            }

            this.loadingCircle.BackgroundImage = screenshot;
        }


Здесь тоже есть весёлые проблемы, но уже не катастрофические : при втором вызове и далее эта штука упорно рисует белые листы, то есть вообще не видит содержимого окна! Поэтому я беру не хэдл самого окна WPF, а хэндл Owner-а, что влечёт необходимость вычисления .PointToScreen().

Это сообщение отредактировал(а) marcusmae - 16.4.2008, 14:24


--------------------
ἀπὸ μηχανῆς θεός
PM MAIL ICQ GTalk   Вверх
Kefir
Дата 16.4.2008, 21:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


«Hakuna Matata»
***


Профиль
Группа: Комодератор
Сообщений: 1878
Регистрация: 25.1.2003
Где: Tampere, Suomi

Репутация: 22
Всего: 87



так, разбирался на скорую руку - воспроизвести ничего так и не удалось. работает, зараза, как часы. может, я чего-то неправильно написал...
screen - это бордер с прямоугольником, я его снимаю и показываю результаты в бордере view. поставил и на клик кнопки и на ресайз окна.
Код

        public Window1()
        {
                this.InitializeComponent();
            
                // Insert code required on object creation below this point.
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Render();
        }

        private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            Render();
        }

        private void Render()
        {
            Image image = new Image();
            image.Stretch = Stretch.None;

            DrawingVisual drawingVisual = new DrawingVisual();
            using (DrawingContext drawingContext = drawingVisual.RenderOpen())
            {
                drawingContext.DrawRectangle(new VisualBrush(screen), null,
                    new Rect(new System.Windows.Size(screen.ActualWidth,
                        screen.ActualHeight)));
            }

            RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap(
                    (int)screen.ActualWidth,
                    (int)screen.ActualHeight,
                    96, 96, System.Windows.Media.PixelFormats.Pbgra32);
            renderTargetBitmap.Render(drawingVisual);
            image.Source = renderTargetBitmap;
            this.view.Child = image;
        }


Добавлено @ 21:23
а если не секрет - зачем эти хитрые извращения?..

Это сообщение отредактировал(а) Kefir - 16.4.2008, 21:27
PM MAIL WWW Skype   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | WPF и Silverlight | Следующая тема »


 




[ Время генерации скрипта: 0.0636 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.