Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.88/8: Рейтинг темы: голосов - 8, средняя оценка - 4.88
0 / 0 / 1
Регистрация: 28.02.2014
Сообщений: 58
1

Помогите понять код

23.02.2016, 16:42. Показов 1482. Ответов 2
Метки нет (Все метки)

если ты добрый человек можно этот код про комментировать я что то не до конца его понимаю
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 public static Bitmap CopyAsNegative(this Image sourceImage)
        {
            Bitmap bmpNew = GetArgbCopy(sourceImage);
            BitmapData bmpData = bmpNew.LockBits(new Rectangle(0, 0, sourceImage.Width, sourceImage.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
 
            IntPtr ptr = bmpData.Scan0;
 
            byte[] byteBuffer = new byte[bmpData.Stride * bmpNew.Height];
 
            Marshal.Copy(ptr, byteBuffer, 0, byteBuffer.Length);
            byte[] pixelBuffer = null;
 
            int pixel = 0;
 
            for (int k = 0; k < byteBuffer.Length; k += 4)
            {
                pixel = ~BitConverter.ToInt32(byteBuffer, k);
                pixelBuffer = BitConverter.GetBytes(pixel);
 
                byteBuffer[k] = pixelBuffer[0];
                byteBuffer[k + 1] = pixelBuffer[1];
                byteBuffer[k + 2] = pixelBuffer[2];
            }
 
            Marshal.Copy(byteBuffer, 0, ptr, byteBuffer.Length);
 
            bmpNew.UnlockBits(bmpData);
 
            bmpData = null;
            byteBuffer = null;
 
            return bmpNew;
        }
0

Помощь в написании контрольных, курсовых и дипломных работ здесь.

Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
23.02.2016, 16:42
Ответы с готовыми решениями:

Помогите понять код.
#include&lt;stdio.h&gt; #include&lt;conio.h&gt; int x_touper(char ch) { if(ch&gt;='a' &amp;&amp; ch&lt;='z') ...

Помогите понять javascript-код
У поисковика Google есть такая 'фишка', как интеграция в контекстное меню веб-броузера, чтобы можно...

Помогите понять код по теме алгоритма Дифии-Хелмана
Делаю лабу по теме алгоритму Дифии-Хелмана, с теорией проблемы, с кодом тоже нет проблем. Но одну...

помогите понять
в раскрутке сайта я полный ноль и в создании тоже.Люди знающие создали сайт,прогнали по...

2
1307 / 980 / 127
Регистрация: 08.12.2009
Сообщений: 1,299
24.02.2016, 06:05 2
рассмотрим этот метод на простом примере. все пояснения в коде.
сразу замечу, что метод GetArgbCopy (на строке №3 в вопросе) не является "стандартным", его исходный код был найден на том же ресурсе, что и CopyAsNegative и добавлен к моему примеру

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
 
namespace ConsoleApplication3892 {
    class Program
    {
        static void Main(string[] args)
        {
            // загружаем изображение из файла
            var bmp = Image.FromFile(@"C:\Users\Mikant\Desktop\image.png");
            // создаём на его основе негатив
            // (методы расширения (см. ниже) вызываются таким же образом,
            // как и собственные методы класса (в данном случае Bitmap) и без указания имени вмещающего класса (BitmapEx))
            var neg = bmp.CopyAsNegative();
            // сохраним негатив в файл
            neg.Save(@"C:\Users\Mikant\Desktop\negative.png");
        }
    }
 
    // НЕВЛОЖЕННЫЙ СТАТИЧЕСКИЙ класс, только в таких можно объявлять методы расширения
    public static class BitmapEx // название абсолютно не принципиально, но это вполне осмысленно и обоснованно
    {
        // собственно, сам метод. ключевое слово this перед типом первого аргумента
        // указывает, что перед нами метод расширения (в данном случае класса Image)
        // и его можно вызывать так, словно он объявлен в расширяемом классе
        // такой метод обязан быть статическим
        public static Bitmap CopyAsNegative(this Image sourceImage)
        {
            // вызов GetArgbCopy даст нам независимую копию изображения sourceImage
            // с нужным для данного алгоритма форматом. см. ниже
            Bitmap bmpNew = GetArgbCopy(sourceImage);
            // вызовом LockBits запрашивается доступ к (неуправляемой) памяти, в которой
            // хранится наша картинка: обыкновенный одномерный массив байт.
            // это, в свою очередь, позволит побайтово считывать и редактировать изображение,
            // что ГОРАЗДО быстрее вызовов GetPixel SetPixel
            //
            // параметр new Rectangle(0, 0, sourceImage.Width, sourceImage.Height) указывает, что
            // нам потребуется вся площадь картинки для работы (см. ниже)
            //
            // параметр ImageLockMode.ReadOnly, формально говоря, задан неправильно.
            // сейчас он указывает, что мы намереваемся только считывать содержимое картинки, но не производить
            // никаких записей/изменений в ней, ведь несколькими строками ниже, производится как раз её перезапись.
            // правильным было бы указать ImageLockMode.ReadWrite, но, по факту, до тех пор, пока не применяется флаг
            // ImageLockMode.UserInputBuffer, это не важно. можно хоть 0 сюда записать - на результат не повлияет. (см. ниже)
            //
            // параметр PixelFormat.Format32bppArgb указывает действительный формат изображения bmpNew,
            // чтобы, например, правильно рассчиталась развёртка (bmpData.Stride) - количество байт на один ряд пикселей
            BitmapData bmpData = bmpNew.LockBits(new Rectangle(0, 0,
                sourceImage.Width, sourceImage.Height),
                ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
            // на самом деле, LockBits умеет работать в двух режимах:
            // с пользовательским буфером (при задании флага ImageLockMode.UserInputBuffer и ручном выделении памяти)
            // и "обыкновенном", при котором буфер для работы ДОЛЖЕН СОЗДАВАТЬСЯ этим вызовом.
            // рассмотрим второй случай (этот вариант использования LockBits встречается повсеместно).
            //
            // ФОРМАЛЬНО при таком вызове ДОЛЖНО происходить следующее:
            // в зависимости от размера квадрата (первый параметр) и формата изображения (третий параметр)
            // выделяется необходимое количество памяти (неуправляемая, в куче (heap) gdi) под буфер
            // если стоит флаг ImageLockMode.ReadOnly (1), то в этот буфер копируется содержимое изображения
            // (его часть, определённая этим квадратом и, естественно, уже с учётом отступов от левого верхнего края)
            // затем пользователь, получив указателю на эту область памяти (буфер), может что-то оттуда считать
            // и что-то записать.
            // если стоит флаг ImageLockMode.WriteOnly (2), то при ВЫЗОВЕ UNLOCKBITS содержимое этого буфера будет
            // скопировано обратно в то место, где находится само изображение, таким образом, изменив его
            // флаг ImageLockMode.ReadWrite (3) объединяет эти 2 флага: 1 | 2 == 3 (то же, в бинарном виде 01 | 10 == 11)
            // 
            // НА САМОМ ДЕЛЕ
            // в этом ВТОРОМ случае, как правило, ВНЕ ЗАВИСИМОСТИ от аргументов
            // никакой новой памяти не выделяется, и появляется возможность по указателю,
            // напрямую работать с той памятью, в которой и размещается изображение.
            // то есть, если даже указать ImageLockMode.ReadOnly, и изменить данные по указателю, изменится и сама картинка.
            // правда, что сам указатель (bmpData.Scan0) будет задан уже с каким-то смещением, относительно начала
            // блока данных, определяемого первым и третьим аргументами
 
            // берём указатель на начало блока данных (массива), где хранится область изображение bmpNew
            IntPtr ptr = bmpData.Scan0;
 
            // ВНЕЗАПНО создаём ЕЩЁ ОДИН байтовый буфер
            // ТОГО ЖЕ размера, что и уже созданный в LockBits
            // в УПРАВЛЯЕМОЙ памяти
            byte[] byteBuffer = new byte[bmpData.Stride * bmpNew.Height];
 
            // копируем всю картинку из неуправляемого буфера в новый, управляемый
            Marshal.Copy(ptr, byteBuffer, 0, byteBuffer.Length);
            // ДУМАЕМ, что мы умнее всех вокруг и объявляем вне цикла
            // пару локальных переменных, которые будут использоваться в цикле,
            // мол это так быстрее будет работать...
            byte[] pixelBuffer = null;
            int pixel = 0;
 
            // дальше в цикле и будет происходить всё изменение изображения...
            // итератор k идёт с шагом 4 (k += 4 :: 0, 4, 8, 12, ...),
            // таким образом на каждом заходе в тело цикла оказываясь на
            // начальном байте каждого пикселя
            for (int k = 0; k < byteBuffer.Length; k += 4)
            {
                // берём 4 байта из буфера, представляющие один пиксель изображения.
                // тильда (~) обозначает поразрядное дополнение числа: т.е. если у нас был пиксель,
                // например, такой, что A = 1, R = 2, G = 3, B = 4, а формат пикселя Format32bppArgb
                // то это 0x01020304 в шестнадцатиричном виде, или 16909060 в десятичной системе счисления
                // но он, скорее всего, что на диске, что в памяти был записан в виде
                // 00000100 00000011 00000010 00000001 - с ОБРАТНЫМ порядком байт
                // (так принято на большинстве архитектур. называется little-Endian)
                // вызов метода ToInt32 взял 4 байта из массива, слепил из них целое int (с учётом порядка байт текущей архитектуры)
                // (byteBuffer[k] | byteBuffer[k + 1] << 8 | byteBuffer[k + 2] << 16 | byteBuffer[k + 3] << 24),
                // а затем происходит расчёт этого дополнения, и число из
                // 00000100 00000011 00000010 00000001
                // лёгким движением превращается в
                // 11111011 11111100 11111101 11111110
                // т.е. все 1 заменяются на 0 и наоборот
                // и вот это целое записывается в pixel
                pixel = ~BitConverter.ToInt32(byteBuffer, k);
                // затем происходит обратное преобразование (из int получаем массив байт)
                pixelBuffer = BitConverter.GetBytes(pixel);
                // альфа почему-то пропускается (при выделении памяти под byteBuffer память зануляется и A всегда будет равна нулю),
                // но 3 из 4х байт (цвета RGB нашего текущего пикселя)
                // записываются в byteBuffer - текущий буфер в управляемой памяти
                //
                // таким образом у результирующего изображения все значения по альфа каналу равны нулю
                // а значения RBG побайтово являются поразрядными дополнениями к соответствующим
                // значениям исходного изображения.
                // ещё раз, для примера:
                //        B(pixelBuffer[0])  G(pixelBuffer[1])  R(pixelBuffer[2])  A(pixelBuffer[3])       
                // было        00000100           00000011           00000010           00000001
                // станет      11111011           11111100           11111101           00000000
                //
                byteBuffer[k] = pixelBuffer[0];
                byteBuffer[k + 1] = pixelBuffer[1];
                byteBuffer[k + 2] = pixelBuffer[2];
            } // и так для всех пикселей всего изображения
 
            // копируем содержимое управляемого буфера в неуправляемый
            Marshal.Copy(byteBuffer, 0, ptr, byteBuffer.Length);
 
            // разблокируем картинку
            // при этом, если и была выделена дополнительная память, содержимое буфера, созданного LockBits
            // будет скопировано в ту область, где и расположено изображение bmpNew,
            bmpNew.UnlockBits(bmpData);
 
            // эти две строки ничего не значат, т.е. бессмысленны
            bmpData = null;
            byteBuffer = null;
 
            // возвращаем результат наших трудов
            return bmpNew;
        }
        // исходный код недостающего метода
        private static Bitmap GetArgbCopy(Image sourceImage)
        {
            // создаём пустое изображение того же размера, что и sourceImage.
            // при этом явно указываем формат записи отдельных пикселей,
            // в данном случае PixelFormat.Format32bppArgb. это означает, что на один пиксель/семпл
            // будет приходиться 32бита (4 байта = 1 int), по восемь на каждый из каналов: альфа, красный, зелёный, синий
            Bitmap bmpNew = new Bitmap(sourceImage.Width, sourceImage.Height, PixelFormat.Format32bppArgb);
 
            // создаём объект Graphics для рисования на bmpNew
            using (Graphics graphics = Graphics.FromImage(bmpNew))
            {
                // рисуем исходное изображение на новом, по сути копируя исходное
                // в случае несовпадения форматов пикселей исходного и нового, всё пройдёт хорошо
                // параметрами (new Rectangle) задаются области, какую порцию исходного изображения взять
                // и где на конечном разместить. в данном случае исходное полностью ложится на конечное
                graphics.DrawImage(sourceImage, new Rectangle(0, 0, bmpNew.Width, bmpNew.Height), new Rectangle(0, 0, bmpNew.Width, bmpNew.Height), GraphicsUnit.Pixel);
                // этот вызов не имеет НИКАКОГО смысла в данном случае и может быть удалён
                graphics.Flush();
            } // закрытием блока using, уничтожаем объект graphics. вызывается graphics.Dispose
 
            // возвращаем свежесозданное изображение
            return bmpNew;
        }
    } // BitmapEx
} // namespace ConsoleApplication10
ну и наконец, если этот материал отложился, я настоятельно рекомендую воздержаться от использования этого метода, т.к. сделан он далеко не оптимально (см. комментарии в коде)

в качестве альтернативы могу предложить такой метод (естественно, основанный на предыдущем):

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
        public static unsafe Bitmap ToNegative(this Image image) {
            var bmp = GetArgbCopy(image);
 
            var data = bmp.LockBits(
                new Rectangle(0, 0, bmp.Width, bmp.Height),
                ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb
            );
 
            var ptr = (byte*)data.Scan0;
            var mpx = data.Width * data.Height;
 
            for (int i = 0; i < mpx; i++, ptr += 4) {
                ptr[0] = (byte)~ptr[0];
                ptr[1] = (byte)~ptr[1];
                ptr[2] = (byte)~ptr[2];
            }
 
            bmp.UnlockBits(data);
            
            return bmp;
        }
        private static Bitmap GetArgbCopy(Image sourceImage) {
            var bmp = new Bitmap(sourceImage.Width, sourceImage.Height);
 
            using (var graphics = Graphics.FromImage(bmp))
                graphics.DrawImage(sourceImage, 0, 0, bmp.Width, bmp.Height);
 
            return bmp;
        }
    }
он работает примерно в три раза быстрее, как раз за счёт того, что в нём не создаются дополнительные буферы, ни под изображение, ни под пиксели. но при этом, т.к. напрямую используется указатель на исходное изображение, необходим так называемый "небезопасный контекст": включается в настройках проекта "разрешить небезопасный код" ("allow unsafe code").

Лунев, слово "прокомментировать" пишется слитно, союзы "-то", "-либо", "-нибудь" пишутся через дефис.

Добавлено через 11 минут
Лунев, там ещё, знаешь, запятые всякие.. и "если ты ... можно" - ни просьба ни утверждение... короче, читать нужно не только код, а писать грамотно обязан
8
-27 / 7 / 1
Регистрация: 19.07.2011
Сообщений: 627
27.08.2017, 20:02 3
во! чувак умеет объяснить.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
27.08.2017, 20:02

Помогите понять!!!!!
Сегодня обнаружил что сайт fonjava.com пропал из Яндекса. Написал письмо в саппорт жду ответа. Но...

Помогите понять
Привет всем! Помогите понять вот такую вещь. Я хочу продвинуть сайт по запросам &quot;Ростов&quot;,...

Помогите понять принцип
Здравствуйте я новичок в Action Script изучаю уже 5 дней:) но знаю основы AC 3.0, я владею PHP и...

Помогите понять ошибку
Не могу понять, что ему не нравится? Обычный вектор векторов: template &lt;class typeData&gt; class...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
3
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.