Работа с GDI+. Проблема: Gaussian Blur

Язык Visual Basic на платформе .NET.

Модераторы: Ramzes, Sebas

MIT
Мега гуру
Мега гуру
Аватара пользователя
 
Сообщения: 2211
Зарегистрирован: 17.09.2006 (Вс) 22:46

Работа с GDI+. Проблема: Gaussian Blur

Сообщение MIT » 19.01.2009 (Пн) 0:26

Обсуждения подтемы "PixelFormat"

Оказывается, не на всяком изображении можно построить Graphics, что для меня стало довольно необычной новостью. Если PixelFormat = Format8bppIndexed {198659}, то при попытке создания графики появляется исключение:
VB08EE писал(а):Невозможно создать объект графики из изображения, имеющего формат с индексированными точками.

Как с этим бороться?

P.S. Сам пока еще не разбирался, так что если решение элементарное - сильно не пинайте.

───────────────
Структурирование подтем:
PixelFormat - Решение (статус: решено)
Out Of ImageAttributes - Решение (статус: решено)
Прозрачность по контуру - Решение (статус: решено)
Местная очистка - Решение (статус: решено)
Последний раз редактировалось MIT 17.02.2009 (Вт) 23:42, всего редактировалось 9 раз(а).
Изображение
You can change your face, but can`t change your mind. No matter what you do.
Создайте еще более понятный интерфейс и мир создаст еще более тупого юзера. (с) Баш

Nord777
Гуру
Гуру
Аватара пользователя
 
Сообщения: 1144
Зарегистрирован: 22.02.2004 (Вс) 13:15
Откуда: Подольск

Re: PixelFormat

Сообщение Nord777 » 19.01.2009 (Пн) 0:34

Как с этим бороться?
Напрямую никак. Наверно только путем преобразования к 32bpp
Microsoft Visual Studio 2008
Microsoft .NET Framework 3.5

MIT
Мега гуру
Мега гуру
Аватара пользователя
 
Сообщения: 2211
Зарегистрирован: 17.09.2006 (Вс) 22:46

Re: PixelFormat

Сообщение MIT » 19.01.2009 (Пн) 4:27

Возникает резонный вопрос: как преобразовать к 32bpp?
Изображение
You can change your face, but can`t change your mind. No matter what you do.
Создайте еще более понятный интерфейс и мир создаст еще более тупого юзера. (с) Баш

Nord777
Гуру
Гуру
Аватара пользователя
 
Сообщения: 1144
Зарегистрирован: 22.02.2004 (Вс) 13:15
Откуда: Подольск

Re: PixelFormat

Сообщение Nord777 » 19.01.2009 (Пн) 14:29

Код: Выделить всё
        Dim BMP8bpp As Bitmap
        Dim BMP32bpp As Bitmap

        'загрузить с диска изображение в формате 8bpp
        BMP8bpp = New Bitmap("D:\8bpp.bmp")

        'создать новое изображение в формате 32bpp
        BMP32bpp = New Bitmap(BMP8bpp.Width, BMP8bpp.Height, Imaging.PixelFormat.Format32bppRgb)

        'Нарисуем на приёмеике исходное изображение
        Using G As Graphics = Graphics.FromImage(BMP32bpp)
            G.DrawImage(BMP8bpp, 0, 0)
        End Using

        'BMP32bpp.Save("D:\32bpp.bmp", ImageFormat.Bmp)
Microsoft Visual Studio 2008
Microsoft .NET Framework 3.5

MIT
Мега гуру
Мега гуру
Аватара пользователя
 
Сообщения: 2211
Зарегистрирован: 17.09.2006 (Вс) 22:46

Re: PixelFormat

Сообщение MIT » 19.01.2009 (Пн) 14:58

Логично и весьма просто. Спасибо.

А есть ли еще подобные подводные камни?
Изображение
You can change your face, but can`t change your mind. No matter what you do.
Создайте еще более понятный интерфейс и мир создаст еще более тупого юзера. (с) Баш

Nord777
Гуру
Гуру
Аватара пользователя
 
Сообщения: 1144
Зарегистрирован: 22.02.2004 (Вс) 13:15
Откуда: Подольск

Re: PixelFormat

Сообщение Nord777 » 19.01.2009 (Пн) 15:17

GDI+ далека от совершенства. Это единственный камень. :)
Microsoft Visual Studio 2008
Microsoft .NET Framework 3.5

MIT
Мега гуру
Мега гуру
Аватара пользователя
 
Сообщения: 2211
Зарегистрирован: 17.09.2006 (Вс) 22:46

Re: Работа с GDI+. Обсуждение проблем

Сообщение MIT » 26.01.2009 (Пн) 21:24

Обсуждения подтемы "Out Of ImageAttributes"

Столкнулся с ошибкой "Out Of Memory" при рисовании изображения с применением аттрибутов.
Вот наглядный пример данной ошибки:
Код: Выделить всё
Imports System.Drawing.Imaging

Public Class Form1
    Dim matrixItems As Single()() = { _
    New Single() {1, 0, 0, 0, 0}, _
    New Single() {0, 1, 0, 0, 0}, _
    New Single() {0, 0, 1, 0, 0}, _
    New Single() {0, 0, 0, 0.6F, 0}, _
    New Single() {0, 0, 0, 0, 1}}
    Dim colorMatrix As ColorMatrix
    Dim imageAtt As ImageAttributes

    Dim img As Image
    Dim TestImage As Image

    Dim WithEvents wc As Net.WebClient

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        colorMatrix = New ColorMatrix(matrixItems)
        imageAtt = New ImageAttributes
        imageAtt.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap)

        wc = New Net.WebClient

        wc.DownloadDataAsync(New Uri("http://bbs.vbstreets.ru/download/file.php?avatar=11295_1230764984.png"))

        TestImage = New Bitmap(100, 100)
        Using g As Graphics = Graphics.FromImage(TestImage)
            g.Clear(Color.CornflowerBlue)
            g.DrawString("Test Image With Attributes", Me.Font, Brushes.Black, New Rectangle(10, 10, 80, 80))
        End Using
    End Sub
    Private Sub wc_DownloadDataCompleted(ByVal sender As Object, ByVal e As System.Net.DownloadDataCompletedEventArgs) Handles wc.DownloadDataCompleted
        Dim ms As New IO.MemoryStream, bw As New IO.BinaryWriter(ms)
        bw.Write(e.Result)
        ms.Position = 0
        wc.Dispose()
        img = Image.FromStream(ms)
        ms.Dispose()
        Me.Invalidate()
    End Sub

    Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
        With e.Graphics
            If img IsNot Nothing Then
                .DrawImageUnscaled(img, 0, 0)
                .DrawImage(img, New Rectangle(img.Width + 1, 0, img.Width, img.Height), 0, 0, img.Width, img.Height, GraphicsUnit.Pixel, imageAtt)
                .DrawImage(TestImage, New Rectangle(0, img.Height + 1, img.Width, img.Height), 0, 0, TestImage.Width, TestImage.Height, GraphicsUnit.Pixel, imageAtt)
            Else
                .SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
                .TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias

                .DrawString("Подождите, идет загрузка изображения...", Me.Font, Brushes.Black, 20, 20)
            End If
        End With
    End Sub
End Class

В котором загружается изображение (мой аватор, с ним эта ошибка "прокатывает") и прорисовывается с прозрачностью.

С чем связано появление данной ошибки (какое условие ее появления, ведь некоторые-то рисуются) и как с ней бороться?
Изображение
You can change your face, but can`t change your mind. No matter what you do.
Создайте еще более понятный интерфейс и мир создаст еще более тупого юзера. (с) Баш

Nord777
Гуру
Гуру
Аватара пользователя
 
Сообщения: 1144
Зарегистрирован: 22.02.2004 (Вс) 13:15
Откуда: Подольск

Re: Работа с GDI+. Проблема: Out Of ImageAttributes

Сообщение Nord777 » 26.01.2009 (Пн) 21:51

А так не пробовал?
Код: Выделить всё
    Private Sub wc_DownloadDataCompleted(ByVal sender As Object, ByVal e As System.Net.DownloadDataCompletedEventArgs) Handles wc.DownloadDataCompleted
        img = Image.FromStream(New IO.MemoryStream(e.Result))
        Me.Invalidate()
    End Sub
Microsoft Visual Studio 2008
Microsoft .NET Framework 3.5

MIT
Мега гуру
Мега гуру
Аватара пользователя
 
Сообщения: 2211
Зарегистрирован: 17.09.2006 (Вс) 22:46

Re: Работа с GDI+. Проблема: Out Of ImageAttributes

Сообщение MIT » 26.01.2009 (Пн) 21:57

:shock: Не понял... Это как так? Фантастика, блин.
Последний раз редактировалось MIT 26.01.2009 (Пн) 22:09, всего редактировалось 1 раз.
Изображение
You can change your face, but can`t change your mind. No matter what you do.
Создайте еще более понятный интерфейс и мир создаст еще более тупого юзера. (с) Баш

Williams
Гуру
Гуру
Аватара пользователя
 
Сообщения: 1280
Зарегистрирован: 06.05.2008 (Вт) 18:35
Откуда: System.Reflection.Williams (увидел себя в зеркале :))

Re: Работа с GDI+. Проблема: Out Of ImageAttributes

Сообщение Williams » 26.01.2009 (Пн) 21:59

MIT писал(а)::shock: Непонял... Это как так? Фантастика, блин.

хы, простота залог успеха :)
Все просто упаковано в одну строчку
И вы думаете, что вас оставят в живых после прочтения этого поста?

Nord777
Гуру
Гуру
Аватара пользователя
 
Сообщения: 1144
Зарегистрирован: 22.02.2004 (Вс) 13:15
Откуда: Подольск

Re: Работа с GDI+. Проблема: Out Of ImageAttributes

Сообщение Nord777 » 26.01.2009 (Пн) 22:01

Походу вместе с потоком прибивается байтовый массив из которого состоит твоя картинка.
Это так, навскидку.
Microsoft Visual Studio 2008
Microsoft .NET Framework 3.5

MIT
Мега гуру
Мега гуру
Аватара пользователя
 
Сообщения: 2211
Зарегистрирован: 17.09.2006 (Вс) 22:46

Re: Работа с GDI+. Проблема: Out Of ImageAttributes

Сообщение MIT » 26.01.2009 (Пн) 22:08

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

Williams писал(а):хы, простота залог успеха Все просто упаковано в одну строчку
А где логика? Ведь код
Код: Выделить всё
img = Image.FromStream(New IO.MemoryStream(e.Result))
и
Код: Выделить всё
        Dim ms As New IO.MemoryStream, bw As New IO.BinaryWriter(ms)
        bw.Write(e.Result)
        ms.Position = 0
        img = Image.FromStream(ms)
        ms.Dispose()
это одно и тоже, пусть второй вариант и длиннее (кстати, а почему я этого сразу не заметил?)


добовлено:
Без ms.Dispose() работает. Странно. Но ведь с ним-то картинка все же рисуется.
Последний раз редактировалось MIT 26.01.2009 (Пн) 22:15, всего редактировалось 1 раз.
Изображение
You can change your face, but can`t change your mind. No matter what you do.
Создайте еще более понятный интерфейс и мир создаст еще более тупого юзера. (с) Баш

Nord777
Гуру
Гуру
Аватара пользователя
 
Сообщения: 1144
Зарегистрирован: 22.02.2004 (Вс) 13:15
Откуда: Подольск

Re: Работа с GDI+. Проблема: Out Of ImageAttributes

Сообщение Nord777 » 26.01.2009 (Пн) 22:13

Ведь без аттрибутов картинка рисуется замечательно и в любое время ее вызова
Наверно просто успевает отрисоваться. Попробуй сдвинь форму за пределы экрана и обратно.

поток так и так будет рано или поздно прибит сборщиком мусора
Врядли. Картинка будет держать ссылку.
Microsoft Visual Studio 2008
Microsoft .NET Framework 3.5

ANDLL
Великий гастроном
Великий гастроном
Аватара пользователя
 
Сообщения: 3450
Зарегистрирован: 29.06.2003 (Вс) 18:55

Re: Работа с GDI+. Проблема: Out Of ImageAttributes

Сообщение ANDLL » 26.01.2009 (Пн) 22:14

это одно и тоже, пусть второй вариант и длиннее (кстати, а почему я этого сразу не заметил?)
Проблема в ms.Dispose.
Научитесь читать документацию о используемых функциях
MSDN писал(а):You must keep the stream open for the lifetime of the Image.
Гастрономия - наука о пище, о ее приготовлении, употреблении, переварении и испражнении.
Блог

MIT
Мега гуру
Мега гуру
Аватара пользователя
 
Сообщения: 2211
Зарегистрирован: 17.09.2006 (Вс) 22:46

Re: Работа с GDI+. Проблема: Out Of ImageAttributes

Сообщение MIT » 26.01.2009 (Пн) 22:20

Nord777 писал(а):Попробуй сдвинь форму за пределы экрана и обратно.
Даже после ресайза картинка спокойно перерисовывается.
ANDLL писал(а):Научитесь читать документацию о используемых функциях
Уж не подумал бы, что проблема закралась в код преобразования массива.
Изображение
You can change your face, but can`t change your mind. No matter what you do.
Создайте еще более понятный интерфейс и мир создаст еще более тупого юзера. (с) Баш

Nord777
Гуру
Гуру
Аватара пользователя
 
Сообщения: 1144
Зарегистрирован: 22.02.2004 (Вс) 13:15
Откуда: Подольск

Re: Работа с GDI+. Проблема: Out Of ImageAttributes

Сообщение Nord777 » 27.01.2009 (Вт) 6:50

Даже после ресайза картинка спокойно перерисовывается.
Я говорил про код с Dispose.
Microsoft Visual Studio 2008
Microsoft .NET Framework 3.5

MIT
Мега гуру
Мега гуру
Аватара пользователя
 
Сообщения: 2211
Зарегистрирован: 17.09.2006 (Вс) 22:46

Re: Работа с GDI+. Проблема: Out Of ImageAttributes

Сообщение MIT » 27.01.2009 (Вт) 12:19

Я тоже, все замечательно работает. Причем картинку можно использовать когда, где и как угодно (за исключением аттрибутов), этому Dispose никак не мешает.
Изображение
You can change your face, but can`t change your mind. No matter what you do.
Создайте еще более понятный интерфейс и мир создаст еще более тупого юзера. (с) Баш

MIT
Мега гуру
Мега гуру
Аватара пользователя
 
Сообщения: 2211
Зарегистрирован: 17.09.2006 (Вс) 22:46

Re: Работа с GDI+. Проблема: Прозрачность по контуру

Сообщение MIT » 27.01.2009 (Вт) 14:36

Обсуждения подтемы "Прозрачность по контуру"

Задача в следующем:
Есть изображение, которому надо сделать прозрачность, но не общую, по контуру. Т.е. плавный переход от прозрачности к картинке с радиусом, например, 10 px.
Для наглядности:
Изображение

Есть ли стандартные средства для подобных преобразований или придется делать руками - Set/GetPixel?

Вопрос между делом: возможно ли приращение к картинке альфа канала?
Пример:
Изображение
Изображение
You can change your face, but can`t change your mind. No matter what you do.
Создайте еще более понятный интерфейс и мир создаст еще более тупого юзера. (с) Баш

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4148
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: Работа с GDI+. Проблема: Прозрачность по контуру

Сообщение Mikle » 27.01.2009 (Вт) 16:10

Тут Nord777 уже описывал решения подобныъ задач, только наоборот, ARGB мы разбирали на 4 канала.
viewtopic.php?f=2&t=32551&hilit=+%D0%B0%D0%BB%D1%8C%D1%84%D0%B0+%D0%BA%D0%B0%D0%BD%D0%B0%D0%BB

MIT
Мега гуру
Мега гуру
Аватара пользователя
 
Сообщения: 2211
Зарегистрирован: 17.09.2006 (Вс) 22:46

Re: Работа с GDI+. Проблема: Прозрачность по контуру

Сообщение MIT » 29.01.2009 (Чт) 1:37

Да-а... Сколько раз я спотыкался о свое незнание самых-самых основ. Опять такой случай.

Из приведенного примера вышеуказанной статьи (тот, который ARGB) понял следующее:
1) Создается двухмерный Integer массив, размером с изображение для хранения цветов (использование Integer`а обосновывается 32-битной цветовой схемой хранения данных о пикселе) для исходного изображения и для результатов
2) В неуправляемой памяти распределяется место под этот самый массив (массивы), что бы его (их) не подвинули (спасибо статье с головного сайта про NET указатели и маршалинг)
3) Производится битное копирование изображения сначала в простой Integer массив, затем в распределенную неуправлямую память
4) Заполняются массивы кодом (пример - альфа):
Код: Выделить всё
alfa = (BmpArray(Row, Col) >> 24) And &HFF
AArray(Row, Col) = alfa Or (alfa << 8) Or (alfa << 16) Or &HFF000000

4.1) Берем Integer, сдвигаем биты вправо на 24, оставляя только альфу
4.2) ОБрезаем альфу до 8 бит
4.3) заполняем каналы RGB значением alfa (для получения GrayScale изображения на выходе), приплюсовывая в нему непрозрачность в A-канал
5) Создаем новое 32х битное изображение, копируя в него данные из неуправляемого массива
...
6) Освобождаем память

Не понял:
1) Что означает блокировка/разблокировка Bitmap`а в памяти и зачем это нужно
2) Относительно пункта 4.2 - почему alfa объявлена как Integer, если предпологается "обрезание" до 1 байта

Максимально разжевано объясните, плиз, где я прав, а где не очень.
Кстати, придя в NET из VB6, где битовыми сдвигами в стандартном функционале и не пахло, а мне они и не нужны были, с ними почти не знаком. Также прошу пнуть в сторону фундаментальной информации по теме.

Уж очень хочется заполнить в своей голове подобного рода безграмотность.
Изображение
You can change your face, but can`t change your mind. No matter what you do.
Создайте еще более понятный интерфейс и мир создаст еще более тупого юзера. (с) Баш

MIT
Мега гуру
Мега гуру
Аватара пользователя
 
Сообщения: 2211
Зарегистрирован: 17.09.2006 (Вс) 22:46

Re: Работа с GDI+. Проблема: Прозрачность по контуру

Сообщение MIT » 29.01.2009 (Чт) 16:30

Нашел статью о блокировке - http://www.bobpowell.net/lockingbits.htm
и общий FAQ по GDIp - http://www.bobpowell.net/faqmain.htm

Кто чем дополнить может?
Изображение
You can change your face, but can`t change your mind. No matter what you do.
Создайте еще более понятный интерфейс и мир создаст еще более тупого юзера. (с) Баш

MIT
Мега гуру
Мега гуру
Аватара пользователя
 
Сообщения: 2211
Зарегистрирован: 17.09.2006 (Вс) 22:46

Re: Работа с GDI+. Проблема: Прозрачность по контуру

Сообщение MIT » 29.01.2009 (Чт) 22:54

Жаль, конечно, что никто так и не помог, пришлось тупо методом тыка и просмотра результата действия каждой строки при отладке изучать описанный код. Метод тыка помог, я даже понял что и зачем там делается.
Написал небольшую функцию, которая при помощи вышеуказанных возможностей "приклеавает" к 32bpp-картинке альфу, выраженную Red-каналом другого 32bpp-изображения.
WindowsApplication1.rar
(35.6 Кб) Скачиваний: 175

Просьба просвященных в теме людей оценить творение. Сам смог проверить только на утечку неуправляемой памяти - все норм, за корректность остальных действий не уверен.
Изображение
You can change your face, but can`t change your mind. No matter what you do.
Создайте еще более понятный интерфейс и мир создаст еще более тупого юзера. (с) Баш

Nord777
Гуру
Гуру
Аватара пользователя
 
Сообщения: 1144
Зарегистрирован: 22.02.2004 (Вс) 13:15
Откуда: Подольск

Re: Работа с GDI+. Проблема: Прозрачность по контуру

Сообщение Nord777 » 29.01.2009 (Чт) 23:22

Я тоже, все замечательно работает. Причем картинку можно использовать когда, где и как угодно (за исключением аттрибутов), этому Dispose никак не мешает.
А это результат того, о чем я пытался тебе сказать:
Изображение
И это еще не самый "страшный" вариант.
Можно конечно продолжать использовать когда, где и как угодно, но лучше не использовать.
Вложения
scrMIT.PNG
scrMIT.PNG (6.91 Кб) Просмотров: 10147
Microsoft Visual Studio 2008
Microsoft .NET Framework 3.5

Nord777
Гуру
Гуру
Аватара пользователя
 
Сообщения: 1144
Зарегистрирован: 22.02.2004 (Вс) 13:15
Откуда: Подольск

Re: Работа с GDI+. Проблема: Прозрачность по контуру

Сообщение Nord777 » 30.01.2009 (Пт) 13:11

Код: Выделить всё
Imports System.Runtime.InteropServices
Imports System.Drawing.Drawing2D
Imports System.Drawing.Imaging

Public Class Form1
  Dim ComboImg, AlphaSourceImg, woAlphaImg As Bitmap

  ''' <summary>
  ''' Массив, хранящий "пикселы" полупрозрачной картинки
  ''' </summary>
  ''' <remarks>
  ''' Время его жизни = время жизни формы на которой располагается картинка
  ''' </remarks>
  Dim ComboArr() As ARGB_Struct

  '===============================================================================================
  Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    Dim Rect As Rectangle
    Dim GBr As LinearGradientBrush

    'Обычное изображение(без полупразрачности)
    woAlphaImg = New Bitmap(64, 64)
    'Изображение-источник альфа-канала.
    AlphaSourceImg = New Bitmap(woAlphaImg.Width, woAlphaImg.Height)

    'Заливка обычного изображение синим фоном
    Using g As Graphics = Graphics.FromImage(woAlphaImg)
      g.Clear(Color.Blue)
    End Using

    'Подготовить изображение-источник альфа-канала.
    Using g As Graphics = Graphics.FromImage(AlphaSourceImg)
      Rect = New Rectangle(New Point(0, 0), AlphaSourceImg.Size)
      GBr = New LinearGradientBrush(Rect, Color.White, Color.Red, LinearGradientMode.Horizontal)
      g.FillRectangle(GBr, Rect)
      g.DrawString(Now, Me.Font, Brushes.Red, 2, 0)
    End Using

    'Создать изображение с альфа-каналом.
    ComboImg = SetAlpha(woAlphaImg, AlphaSourceImg)
    GBr.Dispose()
  End Sub

  '==============================================================================================
  Private Function SetAlpha(ByVal SrcBmp As Bitmap, ByVal AlphaBmp As Bitmap) As Bitmap
    If SrcBmp.Size <> AlphaBmp.Size Then Return SrcBmp

    Dim ComboBmp, tmpAlphaBmp As Bitmap
    Dim gchAplpha, gchCombo As GCHandle
    Dim LockMode As ImageLockMode = ImageLockMode.ReadOnly
    Dim PixFrmt As PixelFormat = PixelFormat.Format32bppArgb
    Dim W% = SrcBmp.Width, H% = SrcBmp.Height, Stride% = SrcBmp.Width * 4
    Dim ImageSize% = W * H

    Dim AlphaArr(ImageSize - 1) As ARGB_Struct
    ReDim ComboArr(ImageSize - 1)

    gchAplpha = GCHandle.Alloc(AlphaArr, GCHandleType.Pinned)
    tmpAlphaBmp = New Bitmap(W, H, Stride, PixFrmt, gchAplpha.AddrOfPinnedObject)
    gchAplpha.Free()

    gchCombo = GCHandle.Alloc(ComboArr, GCHandleType.Pinned)
    ComboBmp = New Bitmap(W, H, Stride, PixFrmt, gchCombo.AddrOfPinnedObject)


    'Это вместо Marshal.Copy
    Using G As Graphics = Graphics.FromImage(ComboBmp)
      G.DrawImage(SrcBmp, 0, 0)
    End Using
    'Это вместо Marshal.Copy
    Using G As Graphics = Graphics.FromImage(tmpAlphaBmp)
      G.DrawImage(AlphaBmp, 0, 0)
    End Using

    'Установить альфа-канал
    For indx As Integer = 0 To ImageSize - 1
      ComboArr(indx).A = AlphaArr(indx).G
    Next

    Return ComboBmp
  End Function

  '==============================================================================================
  Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
    If ComboImg IsNot Nothing Then
      'Вывести обычное изображение
      e.Graphics.DrawImage(woAlphaImg, 10, 10)
      'Вывести полупрозрачное изображение
      e.Graphics.DrawImage(ComboImg, woAlphaImg.Width + 10, 10)
      'Вывести изображение-источник альфы
      e.Graphics.DrawImage(AlphaSourceImg, woAlphaImg.Width + 10, woAlphaImg.Height + 10)
    End If
  End Sub

  '==============================================================================================
  <StructLayout(LayoutKind.Explicit, Size:=4)> _
  Structure ARGB_Struct
    <FieldOffset(0)> Dim ARGB As Integer
    <FieldOffset(0)> Dim B As Byte
    <FieldOffset(1)> Dim G As Byte
    <FieldOffset(2)> Dim R As Byte
    <FieldOffset(3)> Dim A As Byte
  End Structure

End Class
Microsoft Visual Studio 2008
Microsoft .NET Framework 3.5

MIT
Мега гуру
Мега гуру
Аватара пользователя
 
Сообщения: 2211
Зарегистрирован: 17.09.2006 (Вс) 22:46

Re: Работа с GDI+. Проблема: Прозрачность по контуру

Сообщение MIT » 30.01.2009 (Пт) 14:08

Спасибо!

Кстати про структуру я что-то сам не догадался...
Изображение
You can change your face, but can`t change your mind. No matter what you do.
Создайте еще более понятный интерфейс и мир создаст еще более тупого юзера. (с) Баш

kitsemen
Начинающий
Начинающий
Аватара пользователя
 
Сообщения: 5
Зарегистрирован: 06.02.2009 (Пт) 6:37

Re: Работа с GDI+. Проблема: Прозрачность по контуру

Сообщение kitsemen » 06.02.2009 (Пт) 6:56

MIT писал(а):Обсуждения подтемы "PixelFormat"

Оказывается, не на всяком изображении можно построить Graphics, что для меня стало довольно необычной новостью. Если PixelFormat = Format8bppIndexed {198659}, то при попытке создания графики появляется исключение:
VB08EE писал(а):Невозможно создать объект графики из изображения, имеющего формат с индексированными точками.

Как с этим бороться?


Если более интересует конкретная реализация посмотри у меня на сайте http://igorr.110mb.com/dll_colorquantizer.html . Откомментирована правда на украинском, но зато на vb .net :D

Дело в том, что формат Format8bppIndexed - не единый. 1, 4 - та же история. Работать непосредственно с данными нужно. То же относится к формату Format16bppArgb1555.

К тому же, квантование цвета RGB в индексированный может не устроить тебя с точки зрения качества. Нужно проводить дополнительные операции по его улучшению (т.н. "диффузия", - чтоб избежать резких переходов примерно одинакового цвета).

Написано на vb2008
Ваш Семен

MIT
Мега гуру
Мега гуру
Аватара пользователя
 
Сообщения: 2211
Зарегистрирован: 17.09.2006 (Вс) 22:46

Re: Работа с GDI+. Проблема: Местная очистка

Сообщение MIT » 10.02.2009 (Вт) 19:44

Обсуждения подтемы "Местная очистка"

Похожая тема уже создавалась мной (Очистка в Graphics. .Clear не катит), но вопрос получил свое продолжение: теперь необходимо "почистить" кусок изображения.
Проникнувшись вышеописанным способом работы с изображениями написал такой вот код:
Код: Выделить всё
Imports System.Runtime.InteropServices
Imports System.Drawing.Imaging

Public Class Form1
    Dim bmp As Bitmap

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        bmp = New Bitmap(200, 200)
        Using g As Graphics = Graphics.FromImage(bmp)
            With g
                .Clear(Color.CornflowerBlue)
                .DrawRectangle(Pens.Black, 0, 0, bmp.Width - 1, bmp.Height - 1)
            End With
        End Using
   End Sub

    Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
        e.Graphics.DrawImageUnscaled(bmp, 20, 20)
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Clear(bmp, New Rectangle(20, 20, 50, 50))
        Invalidate()
    End Sub

    Dim BmpArray(,) As Integer 'ARGB_Struct
    Private Sub Clear(ByRef SrcBmp As Bitmap, ByVal ClearRegion As Rectangle)
        Dim GCHRGB As GCHandle
        Dim s As Size = SrcBmp.Size

        Dim BMD As Imaging.BitmapData = SrcBmp.LockBits(Rectangle.Round(SrcBmp.GetBounds(GraphicsUnit.Pixel)), Imaging.ImageLockMode.ReadOnly, Imaging.PixelFormat.Format32bppArgb)
        SrcBmp.UnlockBits(BMD)

        Dim Intg(SrcBmp.Width * SrcBmp.Height - 1) As Integer
        ReDim BmpArray(SrcBmp.Width - 1, SrcBmp.Height - 1)
        GCHRGB = GCHandle.Alloc(BmpArray, GCHandleType.Pinned)

        Marshal.Copy(BMD.Scan0, Intg, 0, SrcBmp.Width * SrcBmp.Height)
        Marshal.Copy(Intg, 0, GCHRGB.AddrOfPinnedObject, SrcBmp.Width * SrcBmp.Height)

        For Row As Integer = ClearRegion.X To ClearRegion.Width + ClearRegion.X
            For Col As Integer = ClearRegion.Y To ClearRegion.Height + ClearRegion.Y
                BmpArray(Row, Col) = 0 '.ARGB = 0
            Next
        Next

        SrcBmp.Dispose()
        SrcBmp = New Bitmap(s.Width, s.Height, s.Width * 4, PixelFormat.Format32bppArgb, GCHRGB.AddrOfPinnedObject)
        If GCHRGB.IsAllocated Then GCHRGB.Free()
    End Sub
End Class

Т.е. с прямоугольными областями все не так уж и сложно оказывается. А как к этому "прикрутить" очистку по региону? Руки чешутся в сторону region.GetRegionData.Data, но я не очень понимаю, что включает в себя данная информация - на точки не похоже, да и MSDN ничего умного не пишет. Помогите разобраться.
Да, кстати, указанный выше код мне не кажется рациональным... Почему - не знаю, может где тупость написал, поправьте, если что.
Изображение
You can change your face, but can`t change your mind. No matter what you do.
Создайте еще более понятный интерфейс и мир создаст еще более тупого юзера. (с) Баш

Nord777
Гуру
Гуру
Аватара пользователя
 
Сообщения: 1144
Зарегистрирован: 22.02.2004 (Вс) 13:15
Откуда: Подольск

Re: Работа с GDI+. Проблема: Местная очистка

Сообщение Nord777 » 10.02.2009 (Вт) 20:44

MIT, для чего ты с завидным упорством вставляешь в код эту строку???
Код: Выделить всё
If GCHRGB.IsAllocated Then GCHRGB.Free()

Посмотри на мой код выше. Там стоит всего однин вызов Free (заметь не два)
И сделано это для того, что бы сборщик мусора не переместил область памяти(которую использует обьект Bitmap для хранения данных о пикселях) в другое место. А он её рано или поздно переместит(если освободишь gchandle). Или ты думал я картинку в фотошопе нарисовал?
Microsoft Visual Studio 2008
Microsoft .NET Framework 3.5

MIT
Мега гуру
Мега гуру
Аватара пользователя
 
Сообщения: 2211
Зарегистрирован: 17.09.2006 (Вс) 22:46

Re: Работа с GDI+. Проблема: Местная очистка

Сообщение MIT » 10.02.2009 (Вт) 23:17

Nord777 писал(а):MIT, для чего ты с завидным упорством вставляешь в код эту строку???
Код: Выделить всё
If GCHRGB.IsAllocated Then GCHRGB.Free()
Я думал так: в неуправляемой памяти (которую сборщик не может потревожить) мы создаем байтовый массив для редактирования, обрабатываем его, после чего в управляемой памяти создаем Bitmap (SrcBmp = New Bitmap(... , GCHRGB.AddrOfPinnedObject)), куда копируем данные об изображении, который и будет нормальной картинкой, а неуправляемую инфу прибиваем методом Free.
Но я так понимаю, что не прав. Поясни.
Nord777 писал(а):Там стоит всего однин вызов Free (заметь не два)
Сколько не перечитывал свой код, но так и не нашел второго вызова Free :?

Вполне возможно, что у меня в голове не совсем полно сформировались знание по теме...
Изображение
You can change your face, but can`t change your mind. No matter what you do.
Создайте еще более понятный интерфейс и мир создаст еще более тупого юзера. (с) Баш

Nord777
Гуру
Гуру
Аватара пользователя
 
Сообщения: 1144
Зарегистрирован: 22.02.2004 (Вс) 13:15
Откуда: Подольск

Re: Работа с GDI+. Проблема: Местная очистка

Сообщение Nord777 » 11.02.2009 (Ср) 1:48

Я думал так: в неуправляемой памяти (которую сборщик не может потревожить) мы создаем байтовый массив для редактирования
массив создется в управляемой памяти и сборщик мусора его может переместить. Для того, что бы он не мог переместить твой массив ты его "прикрепляешь" этой строкой:
Код: Выделить всё
GCHRGB = GCHandle.Alloc(BmpArray, GCHandleType.Pinned)

Далее ты используешь этот конструктор:
Код: Выделить всё
SrcBmp = New Bitmap(s.Width, s.Height, s.Width * 4, PixelFormat.Format32bppArgb, GCHRGB.AddrOfPinnedObject)
Этим ты говоришь использовать для пикселей нового изображения другой участок памяти(свой массив). Как только массив будет перемещен сборщиком в другую область памяти - картинка начнет отображать мусор, потому что указатель на данные о пикселях изображения продолжает указывать на старый адрес в памяти. А если этот участок окажется ненужным и сборщик его анулирует - получишь еще и OutOfMemory.

Сколько не перечитывал свой код, но так и не нашел второго вызова Free
Я говорил про свой код. У меня два GCHandle.Alloc, но один Free.
Причем Free для массива временной картинки, которая при выходе из процедуры нигде не используется.

В твоем случае переменную GCHRGB надо обьявлять на уровне формы, а вызов Free надо ставить перед Alloc.
Примерно так:
Код: Выделить всё
      If GCHRGB.IsAllocated Then GCHRGB.Free()
      GCHRGB = GCHandle.Alloc(BmpArray, GCHandleType.Pinned)


Чтобы понять, что происходит - оставь свой код без изменения(тот, который ты сюда запостил)
1) Измени размер картинки на 100х100 пикселей
2) добавь кнопку и лейбл
3) добавь обработчик для кнопки:
Код: Выделить всё
   Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
      Dim Gen As Integer = GC.GetGeneration(BmpArray)
      Label1.Text = Gen.ToString
   End Sub

4) запусти приложение.
5) Нажми Button1. Следом Button2. Посмотри цифру в Label1
6) Сожми форму до минимальных размеров и снова растяни(Возможно несколько раз). Посмотри что стало с картинкой.
7) Нажми Button2. Посмотри цифру в Label1
8.) Прочитай статью о GC в .NET
Microsoft Visual Studio 2008
Microsoft .NET Framework 3.5

След.

Вернуться в Visual Basic .NET

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 13

    TopList  
cron