Преобразовать массив данных в картинку и сохранить в файл

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

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

Mameluk
Начинающий
Начинающий
 
Сообщения: 7
Зарегистрирован: 09.04.2009 (Чт) 4:16

Преобразовать массив данных в картинку и сохранить в файл

Сообщение Mameluk » 06.11.2009 (Пт) 9:28

Ситуация такая. Имеется массив байтовых чисел, он может быть довольно большой (к примеру 25000х800). Мне надо его перобразовать в картинку (числа представляют градации серого: 0 к примеру белый цвет, 255 - черный), начертить кое-что на ней (несколько линий и надписей) и сохранить в виде .bmp файла. Я сделал через класс Bitmap и его метод Setpixel. Программа пашет, но Setpixel работает, естественно, очень медленно. Какими средствами это можно сделать, чтоб было быстро? Я че-то нашел про функцию SetDIBitsToDevice, на так и не понял, как с ней работать в VB.NET. Приведу примерные отрывки из кода моей программы:

Код: Выделить всё
Dim initImage As Bitmap
        initImage = New Bitmap(800, 800)

For i = 0 To 799
            For j = 0 To 799
                    colorP = data(i,j) 'массив с данными цветов
                    initImage.SetPixel(i, j, Color.FromArgb(colorP, colorP, colorP))
            Next j
Next i
'...

Dim Gr As Graphics = Graphics.FromImage(initImage)
'...

        Gr.Clear(Color.White)
        ulCorner = New Point(0, 0)
        Gr.DrawImage(initImage, ulCorner)
        Gr.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAliasGridFit
        Gr.DrawLine(Pens.Black, imageOffset - 1, 10, imageOffset - 1, (newHeight - 1) + 10) 'Ось слева
        Gr.DrawLine(Pens.Black, imageOffset - 1 + pings, 10, imageOffset - 1 + pings, (newHeight - 1) + 10) 'Ось справа
'....
        drawFont = New Font("Arial", 10, FontStyle.Regular)
        drawBrush = New SolidBrush(Color.Black)
        format1 = New StringFormat
        format1.Alignment = StringAlignment.Far
        Gr.DrawString("бла-бла-бла", drawFont, drawBrush, 10, 10, format1)
'....

initImage.Save("C:\1.bmp", Imaging.ImageFormat.Bmp)



Как сделать тоже самое, только через DIB?

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

Re: Преобразовать массив данных в картинку и сохранить в файл

Сообщение MIT » 06.11.2009 (Пт) 12:48

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

Mameluk
Начинающий
Начинающий
 
Сообщения: 7
Зарегистрирован: 09.04.2009 (Чт) 4:16

Re: Преобразовать массив данных в картинку и сохранить в файл

Сообщение Mameluk » 07.11.2009 (Сб) 17:37

MIT, а можно небольшой примерчик, как использовать эту технологию?

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

Re: Преобразовать массив данных в картинку и сохранить в файл

Сообщение MIT » 07.11.2009 (Сб) 18:15

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

Mameluk
Начинающий
Начинающий
 
Сообщения: 7
Зарегистрирован: 09.04.2009 (Чт) 4:16

Re: Преобразовать массив данных в картинку и сохранить в файл

Сообщение Mameluk » 09.11.2009 (Пн) 7:22

MIT, в общем сделал как в твоем примере, но не помогло =( :

Код: Выделить всё
<StructLayout(LayoutKind.Explicit, Size:=4)> _
   Public Structure RGB_Struct
        <FieldOffset(0)> Dim RGB As Integer
        <FieldOffset(0)> Dim B As Byte
        <FieldOffset(1)> Dim G As Byte
        <FieldOffset(2)> Dim R As Byte
    End Structure

        Dim BmpArray((Data.Count - 1) * 800 - 1) As RGB_Struct
        Dim GCHRGB As GCHandle

        For i = 0 To Data.Count - 2
            For j = 0 To 799
                BmpArray(i * j).R = 255
                BmpArray(i * j).G = 255
                BmpArray(i * j).B = 255
            Next j
        Next i

        GCHRGB = GCHandle.Alloc(BmpArray, GCHandleType.Pinned)
        initImage = New Bitmap(Data.Count - 1, 800, (Data.Count - 1) * 4, Imaging.PixelFormat.Format32bppRgb, GCHRGB.AddrOfPinnedObject)

Вот так, если просто заполнять белым цветом, картинка размером 24000*800 пикселей вырисовывается примерно за 5 секунд.


Но если я начинаю считывать данные о цвете из массива:

Код: Выделить всё
For i = 0 To Data.Count - 2
            For j = 0 To 799
                colorP = Data(i)(j)                               ' ****** dim  Data As New ArrayList
                BmpArray(i * j).R = colorP
                BmpArray(i * j).G = color
                BmpArray(i * j).B = colorP
            Next j
        Next i

        GCHRGB = GCHandle.Alloc(BmpArray, GCHandleType.Pinned)
        initImage = New Bitmap(Data.Count - 1, 800, (Data.Count - 1) * 4, Imaging.PixelFormat.Format32bppRgb, GCHRGB.AddrOfPinnedObject)


то картинка рисуется секунд 25, то есть в 5 раз медленнее. Получается куда больше времени уходит на считывание массива.

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

Re: Преобразовать массив данных в картинку и сохранить в файл

Сообщение MIT » 09.11.2009 (Пн) 8:14

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

Mameluk
Начинающий
Начинающий
 
Сообщения: 7
Зарегистрирован: 09.04.2009 (Чт) 4:16

Re: Преобразовать массив данных в картинку и сохранить в файл

Сообщение Mameluk » 09.11.2009 (Пн) 8:41

Эх, если б было все так просто :(, но без промежуточного массива не обойтись, так как после считывания его из файла требуется выполнить над ним некоторые пребразования, которые невозможны без полного считывания файла (ведь я даже наперед размеры картинки не знаю)

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

Re: Преобразовать массив данных в картинку и сохранить в файл

Сообщение Nord777 » 09.11.2009 (Пн) 8:58

Время заполнения ~200 мс
Код: Выделить всё
   Dim initImage As Bitmap
   Const W As Integer = 24000
   Const H As Integer = 800
   Const UB As Integer = W * H - 1
   Dim Grаy(UB) As Byte

   Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
      Dim SW As New Stopwatch
      SW.Start()
      XXX()
      SW.Stop()
      MsgBox(SW.ElapsedMilliseconds.ToString)
   End Sub

   Sub XXX()
      Dim BmpArray(UB) As RGB_Struct
      Dim GCHRGB As GCHandle
      Dim C As Integer

      For i As Integer = 0 To UB
         C = Grаy(i)
         BmpArray(i).RGB = (C << 16 Or C << 8 Or C)
      Next i

      GCHRGB = GCHandle.Alloc(BmpArray, GCHandleType.Pinned)
      initImage = New Bitmap(W, H, W * 4, Imaging.PixelFormat.Format32bppRgb, GCHRGB.AddrOfPinnedObject)
   End Sub
Microsoft Visual Studio 2008
Microsoft .NET Framework 3.5

Mameluk
Начинающий
Начинающий
 
Сообщения: 7
Зарегистрирован: 09.04.2009 (Чт) 4:16

Re: Преобразовать массив данных в картинку и сохранить в файл

Сообщение Mameluk » 10.11.2009 (Вт) 2:22

Nord777, хм интересно, действительно при таком коде у меня картинку рисуется за 135 милисекунд. Но вот что удивительно. Если я вместо одномерного массива использую динамический массив (ArrayList) одномерный, время возрастает до 400 мс. Но когда использую двумерный ArrayList (как в моей программе) то время возрастает до 15(!) секунд оО:
Код: Выделить всё
Sub XXX()
        Dim BmpArray(UB) As RGB_Struct
        Dim GCHRGB As GCHandle
        Dim C As Integer
        Dim Gray1 As New ArrayList
        Gray1.Add(New Object() {100, 100})

        For i As Integer = 0 To UB
            C = Gray(0)(1)
            BmpArray(i).RGB = (C << 16 Or C << 8 Or C)
        Next i

        GCHRGB = GCHandle.Alloc(BmpArray, GCHandleType.Pinned)
        initImage = New Bitmap(W, H, W * 4, Imaging.PixelFormat.Format32bppRgb, GCHRGB.AddrOfPinnedObject)

    End Sub

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

Кстати само сохранение такой картинки в файл:
Код: Выделить всё
initImage.Save("C:\1.bmp", Imaging.ImageFormat.Bmp)

занимает где-то 4 секунды.

1Steps
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 505
Зарегистрирован: 20.12.2006 (Ср) 0:50
Откуда: New York

Re: Преобразовать массив данных в картинку и сохранить в файл

Сообщение 1Steps » 10.11.2009 (Вт) 3:56

Вместо ArrayList используй Generic или любой типизированный массив.
Удалена за ненадобностью.

Mameluk
Начинающий
Начинающий
 
Сообщения: 7
Зарегистрирован: 09.04.2009 (Чт) 4:16

Re: Преобразовать массив данных в картинку и сохранить в файл

Сообщение Mameluk » 10.11.2009 (Вт) 5:21

Ммм, а Generic это что? =) Я сейчас ArrayList заменил массивом массивов. Вот с ним проблем нет, все делается быстро. Есдинственная проблема, как я и говорил то что его точный размер я наперед не знаю, приходится задавать примерно, исходя из размера файла с данными.

1Steps
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 505
Зарегистрирован: 20.12.2006 (Ср) 0:50
Откуда: New York

Re: Преобразовать массив данных в картинку и сохранить в файл

Сообщение 1Steps » 10.11.2009 (Вт) 5:57

Удалена за ненадобностью.

Mameluk
Начинающий
Начинающий
 
Сообщения: 7
Зарегистрирован: 09.04.2009 (Чт) 4:16

Re: Преобразовать массив данных в картинку и сохранить в файл

Сообщение Mameluk » 10.11.2009 (Вт) 7:05

Действительно, в случае с List(T) все отлично. MIT, Nord777, 1Steps, большие вам спасибо.


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

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

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

    TopList