powered by simpleCommunicator - 2.0.53     © 2025 Programmizd 02
Форумы / Visual Basic [игнор отключен] [закрыт для гостей] / Вычисление основного цвета картинки. Не чреват ли массив очень большой размерности?
5 сообщений из 5, страница 1 из 1
Вычисление основного цвета картинки. Не чреват ли массив очень большой размерности?
    #38410580
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вот здесь темку задал:
А как вычислить "средний цвет картинки"?
Сделал сначала на .Net:
Код: vbnet
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.
      Dim list As New Dictionary(Of Integer, Integer)
      For x As Integer = 0 To bmp_Background.Width - 1
        For y As Integer = 0 To bmp_Background.Height - 1
          Dim rgb As Integer = bmp_Background.GetPixel(x, y).ToArgb()
          If (rgb > -15000000) And (rgb < -8000000) Then

            Dim added As Boolean = False
            For i As Integer = 0 To 10
              If list.ContainsKey(rgb + i) Then
                list(rgb + i) += 1
                added = True
                Exit For
              End If
              If list.ContainsKey(rgb - i) Then
                list(rgb - i) += 1
                added = True
                Exit For
              End If
            Next i
            If added = False Then list.Add(rgb, 1)
          End If
        Next y
      Next x

      Dim maxV As Integer = 0
      Dim new_color As Color
      For Each element In list
        If element.Value > maxV Then
          maxV = element.Value
          new_color = Color.FromArgb(element.Key)
        End If
      Next
      'MsgBox(new_color.ToArgb)
      Label1.BackColor = new_color


Там используется некий объект Dictionary.
В .Net Dictionary работает довольно резво.

Попытка использовать Dictionary из Microsoft Scripting Runtime в VB6,
во первых эту либу ненавижу,
во вторых за это время можно повеситься и спасти не успеют.

Я извернулся. Код стал "быстрым".
Но вот вопрос: не чревато ли использование массива
Код: vbnet
1.
Dim list_m(7900000 To 15100000) As Long


проблемами с памятью и т.п.
Чисто по ощущениям я проблем не заметил.
Массив нужен для тупого обращения к счетчику любого цвета (без перебора коллекции всех уже встречавшихся цветов для каждого пикселя),
естественно большинство его элементов всегда нули.

Или как этот алгоритм переписать с использованием еще чего-либо?
Собственно код:
Код: vbnet
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.
Private Type MyARGB
  blue As Byte
  green As Byte
  red As Byte
  alpha As Byte
End Type

Private Function CalculateMainColor(ByVal the_filename As String, _
 Optional ByVal x_start As Long = 0, Optional ByVal y_start As Long = 0, _
 Optional ByVal dx_width As Long = 0, Optional ByVal dy_height As Long = 0) As Long
  Dim m_GdipSession As Long
  Dim gpsi As GDIPlusStartupInput
  Dim bmp_Background As Long
  Dim gr As Long
  Dim hBitmap As Long
  Dim bg_width As Long
  Dim bg_height As Long
  
  With gpsi
    .GdiPlusVersion = Ver1
    .DebugEventCallback = 0
    .SuppressBackgroundThread = FALSE_BOOL
    .SuppressExternalCodecs = FALSE_BOOL
  End With
  
  If GdiplusStartup(m_GdipSession, gpsi, ByVal 0&) = OK Then
  
    If GdipExec(GdipCreateBitmapFromFile(StrPtr(the_filename), bmp_Background)) = OK Then
      GdipExec GdipGetImageWidth(bmp_Background, bg_width)
      GdipExec GdipGetImageHeight(bmp_Background, bg_height)
      
      If x_start > bg_width - 1 Then x_start = bg_width - 1
      If dx_width = 0 Then dx_width = bg_width
      If x_start + dx_width > bg_width Then dx_width = bg_width - x_start
      If y_start > bg_height - 1 Then y_start = bg_height - 1
      If dy_height = 0 Then dy_height = bg_height
      If y_start + dy_height > bg_height Then dy_height = bg_height - y_start
      'MsgBox x_start & ";" & y_start & ";" & dx_width & ";" & dy_height & ";"
      
      Dim list_m(7900000 To 15100000) As Long
      
      Dim x As Long, y As Long
      Dim maxV As Long
      Dim curV As Long
      Dim my_color As Long
      maxV = 0
      For x = x_start To dx_width - 1
        For y = y_start To dy_height - 1
          Dim rgb_v As Long
          GdipBitmapGetPixel bmp_Background, x, y, rgb_v
          If (rgb_v > -15000000) And (rgb_v < -8000000) Then
            Dim added As Boolean
            added = False
            Dim i As Long
            For i = 0 To 10
            If list_m(-rgb_v - i) > 0 Then
                curV = list_m(-rgb_v - i) + 1
                list_m(-rgb_v - i) = curV
                If curV > maxV Then
                  maxV = curV
                  my_color = rgb_v + i
                End If
                added = True
                Exit For
              End If
              If list_m(-rgb_v + i) > 0 Then
                curV = list_m(-rgb_v + i) + 1
                list_m(-rgb_v + i) = curV
                If curV > maxV Then
                  maxV = curV
                  my_color = rgb_v + i
                End If
                added = True
                Exit For
              End If
            Next i
            If added = False Then
              list_m(-rgb_v) = 1
              If maxV = 0 Then
                maxV = 1
                my_color = rgb_v
              End If
            End If
          End If

        Next y
      Next x
      Dim struct_color As MyARGB
      CopyMemory struct_color, my_color, 4
      CalculateMainColor = RGB(struct_color.red, struct_color.green, struct_color.blue)
      GdipExec GdipDisposeImage(bmp_Background)
    End If
    If CalculateMainColor = 0 Then CalculateMainColor = vbButtonShadow
    
    GdipExec GdiplusShutdown(m_GdipSession)
  End If
End Function
...
Рейтинг: 0 / 0
Вычисление основного цвета картинки. Не чреват ли массив очень большой размерности?
    #38411534
Фотография Бенедикт
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77Но вот вопрос: не чревато ли использование массива
Код: vbnet
1.
Dim list_m(7900000 To 15100000) As Long


проблемами с памятью и т.п.
Чисто по ощущениям я проблем не заметил.Особых проблем быть не должно, но если хочется иметь возможность контроля возникновения этих проблем, лучше выделять память динамически (ReDim).

Вместо Dictionary или подобных контейнеров для ускорения можно воспользоваться тем же массивом, см. код в спойлере, в частности Property Get Pixel (с учётом #Const PRAGMA_SAFE = False):
код (много лишнего, в оригинале для VBA)модуль:
Код: vbnet
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.
Option Explicit

Public Type POINTAPI
   X As Long
   Y As Long
End Type

Private Enum BOOL
   FALSE_BOOL = 0
   TRUE_BOOL = 1
End Enum

Private Declare Function CreateIC Lib "gdi32" Alias "CreateICA" ( _
   ByVal lpDriverName As String, ByVal lpDeviceName As String, _
   ByVal lpOutput As String, lpInitData As Any) As Long
Private Declare Function DeleteDC Lib "gdi32" (ByVal hDC As Long) As BOOL

Private Enum DeviceCapIndex
   HORZSIZE = 4           '  Horizontal size in millimeters
   VERTSIZE = 6           '  Vertical size in millimeters
   HORZRES = 8            '  Horizontal width in pixels
   VERTRES = 10           '  Vertical width in pixels
   LOGPIXELSX = 88        '  Logical pixels/inch in X
   LOGPIXELSY = 90        '  Logical pixels/inch in Y
End Enum
Private Declare Function GetDeviceCaps Lib "gdi32" ( _
   ByVal hDC As Long, ByVal nIndex As DeviceCapIndex) As Long

Private Const TWIPS_PER_INCH = 1440&

Public Function TwipsPerPixelX() As Long
 Dim hicDisplay As Long
 hicDisplay = CreateIC("DISPLAY", vbNullString, vbNullString, ByVal 0&)
 TwipsPerPixelX = TWIPS_PER_INCH \ GetDeviceCaps(hicDisplay, LOGPIXELSX)
 DeleteDC hicDisplay
End Function

Public Function TwipsPerPixelY() As Long
 Dim hicDisplay As Long
 hicDisplay = CreateIC("DISPLAY", vbNullString, vbNullString, ByVal 0&)
 TwipsPerPixelY = TWIPS_PER_INCH \ GetDeviceCaps(hicDisplay, LOGPIXELSY)
 DeleteDC hicDisplay
End Function

класс:
Код: vbnet
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.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
295.
296.
297.
298.
299.
300.
301.
302.
303.
304.
305.
306.
307.
308.
309.
310.
311.
312.
313.
314.
315.
316.
317.
318.
319.
320.
321.
322.
323.
324.
325.
326.
327.
328.
329.
330.
331.
332.
333.
334.
335.
336.
337.
338.
339.
340.
341.
342.
343.
344.
345.
346.
347.
348.
349.
350.
351.
352.
353.
354.
355.
356.
357.
358.
359.
360.
361.
362.
363.
364.
365.
366.
367.
368.
369.
370.
371.
372.
373.
374.
375.
376.
377.
378.
379.
380.
381.
382.
383.
384.
385.
386.
387.
388.
389.
390.
391.
392.
393.
394.
395.
396.
397.
398.
399.
400.
401.
402.
403.
404.
405.
406.
407.
408.
409.
410.
411.
412.
413.
414.
415.
416.
417.
418.
419.
420.
421.
422.
423.
424.
425.
426.
427.
428.
429.
430.
431.
432.
433.
434.
435.
436.
437.
438.
439.
440.
441.
442.
443.
444.
445.
446.
447.
448.
449.
450.
451.
452.
453.
454.
455.
456.
457.
458.
459.
460.
461.
462.
463.
464.
465.
466.
467.
468.
469.
470.
471.
472.
473.
474.
475.
476.
477.
478.
479.
480.
481.
482.
483.
484.
485.
486.
487.
488.
489.
490.
491.
492.
493.
494.
495.
496.
497.
498.
499.
500.
501.
502.
503.
504.
505.
506.
507.
508.
509.
510.
511.
512.
513.
514.
515.
516.
517.
518.
519.
520.
521.
522.
523.
524.
525.
526.
527.
528.
529.
530.
531.
532.
533.
534.
535.
536.
537.
538.
539.
540.
541.
542.
543.
544.
545.
546.
547.
548.
549.
550.
551.
552.
553.
554.
555.
556.
557.
558.
559.
560.
561.
562.
563.
564.
565.
566.
567.
568.
569.
570.
571.
572.
573.
574.
575.
576.
577.
578.
579.
580.
581.
582.
583.
584.
585.
586.
587.
588.
589.
590.
591.
592.
593.
594.
595.
596.
597.
598.
599.
600.
601.
602.
603.
604.
605.
606.
607.
608.
609.
610.
611.
612.
613.
614.
615.
616.
617.
618.
619.
620.
621.
622.
623.
624.
625.
626.
627.
628.
629.
630.
631.
632.
633.
634.
635.
636.
637.
638.
639.
640.
641.
642.
643.
644.
645.
646.
647.
648.
649.
650.
651.
652.
653.
654.
655.
656.
657.
658.
659.
660.
661.
662.
663.
664.
665.
666.
667.
668.
669.
670.
671.
672.
673.
674.
675.
676.
677.
678.
679.
680.
681.
682.
683.
684.
685.
686.
687.
688.
689.
690.
691.
692.
693.
694.
695.
696.
697.
698.
699.
700.
701.
702.
703.
704.
705.
706.
707.
708.
709.
710.
711.
712.
713.
714.
715.
716.
717.
718.
719.
720.
721.
722.
723.
724.
725.
726.
727.
728.
729.
730.
731.
732.
733.
734.
735.
736.
737.
738.
739.
740.
741.
742.
743.
744.
745.
746.
747.
748.
749.
750.
751.
752.
753.
754.
755.
756.
757.
758.
759.
760.
761.
762.
763.
764.
765.
766.
767.
768.
769.
770.
771.
772.
773.
774.
775.
776.
777.
778.
779.
780.
781.
782.
783.
784.
785.
786.
787.
788.
789.
790.
791.
792.
793.
794.
795.
796.
797.
798.
799.
800.
801.
802.
803.
804.
805.
806.
807.
808.
809.
810.
811.
812.
813.
814.
815.
816.
817.
818.
819.
820.
821.
822.
823.
824.
825.
826.
827.
828.
829.
830.
831.
832.
833.
834.
835.
836.
837.
838.
839.
840.
841.
842.
843.
844.
845.
846.
847.
848.
849.
850.
851.
852.
853.
854.
855.
856.
857.
858.
859.
860.
861.
862.
863.
864.
865.
866.
867.
868.
869.
870.
871.
872.
873.
874.
875.
876.
877.
878.
879.
880.
881.
882.
883.
884.
885.
886.
887.
888.
889.
890.
891.
892.
893.
894.
895.
896.
897.
898.
899.
900.
901.
902.
903.
904.
905.
906.
907.
908.
909.
910.
911.
912.
913.
914.
915.
916.
917.
918.
919.
920.
921.
922.
923.
924.
925.
926.
927.
928.
929.
930.
931.
932.
933.
934.
935.
936.
937.
938.
939.
940.
941.
942.
943.
944.
945.
946.
947.
948.
949.
950.
951.
952.
953.
954.
955.
956.
957.
958.
959.
960.
961.
962.
963.
964.
965.
966.
967.
968.
969.
970.
971.
972.
973.
974.
975.
976.
977.
978.
979.
980.
#Const PRAGMA_SAFE = False

Option Explicit


Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
   pvDest As Any, pvSource As Any, ByVal cBytes As Long)
'Private Declare Function GetMem4 Lib "msvbvm60" ( _
   ByVal pSrc As Long, Dst As Long) As Long
'Private Declare Function PutMem4 Lib "msvbvm60" ( _
   ByVal pDst As Long, ByVal NewValue As Long) As Long


Private Enum BOOL
   FALSE_BOOL = 0
   TRUE_BOOL = 1
End Enum

Private Type RECT
   Left As Long
   Top As Long
   Right As Long
   Bottom As Long
End Type

Private Declare Function GetClientRect Lib "user32" ( _
   ByVal hWnd As Long, lpRect As RECT) As BOOL
Private Declare Function GetWindowRect Lib "user32" ( _
   ByVal hWnd As Long, lpRect As RECT) As BOOL

Private Declare Function GetDesktopWindow Lib "user32" () As Long

Private Declare Function GetDC Lib "user32" ( _
   ByVal hWnd As Long) As Long
Private Declare Function GetWindowDC Lib "user32" ( _
   ByVal hWnd As Long) As Long
Private Declare Function ReleaseDC Lib "user32" ( _
   ByVal hWnd As Long, ByVal hDC As Long) As Long
Private Declare Function CreateIC Lib "gdi32" Alias "CreateICA" ( _
   ByVal lpDriverName As String, ByVal lpDeviceName As String, _
   ByVal lpOutput As String, lpInitData As Any) As Long
Private Declare Function CreateCompatibleDC Lib "gdi32" ( _
   ByVal hDC As Long) As Long
Private Declare Function DeleteDC Lib "gdi32" ( _
   ByVal hDC As Long) As BOOL

Private Declare Function SelectObject Lib "gdi32" ( _
   ByVal hDC As Long, ByVal hObject As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" ( _
   ByVal hObject As Long) As BOOL

Private Enum DeviceCapIndex
   HORZSIZE = 4           '  Horizontal size in millimeters
   VERTSIZE = 6           '  Vertical size in millimeters
   HORZRES = 8            '  Horizontal width in pixels
   VERTRES = 10           '  Vertical width in pixels
   LOGPIXELSX = 88        '  Logical pixels/inch in X
   LOGPIXELSY = 90        '  Logical pixels/inch in Y
End Enum
Private Declare Function GetDeviceCaps Lib "gdi32" ( _
   ByVal hDC As Long, ByVal nIndex As DeviceCapIndex) As Long


Private Type BITMAP '24 bytes
   bmType As Long
   bmWidth As Long
   bmHeight As Long
   bmWidthBytes As Long
   bmPlanes As Integer
   bmBitsPixel As Integer
   bmBits As Long
End Type

Private Enum BitmapCompressionType
   BI_RGB = 0
   BI_RLE8 = 1
   BI_RLE4 = 2
   BI_BITFIELDS = 3
   BI_JPEG = 4
   BI_PNG = 5
End Enum

Private Type BITMAPINFOHEADER '40 bytes
   biSize As Long
   biWidth As Long
   biHeight As Long
   biPlanes As Integer
   biBitCount As Integer
   biCompression As BitmapCompressionType
   biSizeImage As Long
   biXPelsPerMeter As Long
   biYPelsPerMeter As Long
   biClrUsed As Long
   biClrImportant As Long
End Type

Private Type RGBQUAD
   rgbBlue As Byte
   rgbGreen As Byte
   rgbRed As Byte
   rgbReserved As Byte
End Type

Private Type BITMAPINFO
   bmiHeader As BITMAPINFOHEADER
   bmiColors As RGBQUAD
End Type

Private Type DIBSECTION
   dsBm As BITMAP
   dsBmih As BITMAPINFOHEADER
   dsBitfields(0 To 2) As Long
   dshSection As Long
   dsOffset As Long
End Type

Private Declare Function CreateDIBSection Lib "gdi32" ( _
   ByVal hDC As Long, pbmi As BITMAPINFO, ByVal iUsage As Long, _
   pBits As Any, ByVal hSection As Long, ByVal dwOffset As Long) As Long
Private Const DIB_RGB_COLORS = 0 '  color table in RGBs


Private Declare Function SetPixel Lib "gdi32" ( _
   ByVal hDC As Long, ByVal X As Long, ByVal Y As Long, _
   ByVal crColor As Long) As Long
Private Declare Function MoveToEx Lib "gdi32" ( _
   ByVal hDC As Long, ByVal X As Long, ByVal Y As Long, lpPoint As Any) As BOOL
Private Declare Function LineTo Lib "gdi32" ( _
   ByVal hDC As Long, ByVal X As Long, ByVal Y As Long) As BOOL
Private Declare Function Rectangle Lib "gdi32" ( _
   ByVal hDC As Long, ByVal X1 As Long, ByVal Y1 As Long, _
   ByVal X2 As Long, ByVal Y2 As Long) As BOOL
Private Declare Function Ellipse Lib "gdi32" ( _
   ByVal hDC As Long, ByVal X1 As Long, ByVal Y1 As Long, _
   ByVal X2 As Long, ByVal Y2 As Long) As BOOL
Private Declare Function Polyline Lib "gdi32" ( _
   ByVal hDC As Long, lppt As POINTAPI, ByVal cPoints As Long) As BOOL

Private Const SRCCOPY = &HCC0020 ' (DWORD) dest = source
Private Declare Function BitBlt Lib "gdi32" ( _
   ByVal hdcDst As Long, ByVal xDst As Long, ByVal yDst As Long, _
   ByVal nWidth As Long, ByVal nHeight As Long, _
   ByVal hdcSrc As Long, ByVal xSrc As Long, ByVal ySrc As Long, _
   ByVal dwRop As Long) As BOOL


Public Enum PenStyle
   psSolid = 0
   psDash = 1                    '  -------
   psDot = 2                     '  .......
   psDashDot = 3                 '  _._._._
   psDashDotDot = 4              '  _.._.._
   psNull = 5
   psInsideFrame = 6
End Enum
Private Declare Function CreatePen Lib "gdi32" ( _
   ByVal nPenStyle As PenStyle, ByVal nWidth As Long, _
   ByVal crColor As Long) As Long

Private Declare Function CreateSolidBrush Lib "gdi32" ( _
   ByVal crColor As Long) As Long
Private Enum HatchBrushStyle
   HS_HORIZONTAL = 0              '  -----
   HS_VERTICAL = 1                '  |||||
   HS_FDIAGONAL = 2               '  \\\\\
   HS_BDIAGONAL = 3               '  /////
   HS_CROSS = 4                   '  +++++
   HS_DIAGCROSS = 5               '  xxxxx
End Enum
Private Declare Function CreateHatchBrush Lib "gdi32" ( _
   ByVal nIndex As HatchBrushStyle, ByVal crColor As Long) As Long
Private Declare Function CreatePatternBrush Lib "gdi32" ( _
   ByVal hBitmap As Long) As Long

Private Const NULL_BRUSH = 5
Private Declare Function GetStockObject Lib "gdi32" ( _
   ByVal nIndex As Long) As Long

Public Enum PolygonFillMode
   ALTERNATE = 1
   WINDING = 2
End Enum
Private Declare Function GetPolyFillMode Lib "gdi32" ( _
   ByVal hDC As Long) As PolygonFillMode
Private Declare Function SetPolyFillMode Lib "gdi32" ( _
   ByVal hDC As Long, ByVal nPolyFillMode As PolygonFillMode) As PolygonFillMode
Private Declare Function Polygon Lib "gdi32" ( _
   ByVal hDC As Long, lpPoint As POINTAPI, ByVal nCount As Long) As BOOL

Private Declare Function SetBkColor Lib "gdi32" ( _
   ByVal hDC As Long, ByVal crColor As Long) As Long


Private Declare Function CreateEnhMetaFile Lib "gdi32" _
   Alias "CreateEnhMetaFileA" ( _
   ByVal hdcRef As Long, ByVal lpFileName As String, lpRect As RECT, _
   ByVal lpDescription As String) As Long
Private Declare Function CloseEnhMetaFile Lib "gdi32" ( _
   ByVal hDC As Long) As Long
Private Declare Function GetEnhMetaFileBits Lib "gdi32" ( _
   ByVal hEMF As Long, ByVal cbBuffer As Long, lpbBuffer As Any) As Long

Private Enum MapMode
   MM_TEXT = 1
   MM_LOMETRIC = 2
   MM_HIMETRIC = 3
   MM_LOENGLISH = 4
   MM_HIENGLISH = 5
   MM_TWIPS = 6
   MM_ISOTROPIC = 7
   MM_ANISOTROPIC = 8 ' Map mode anisotropic
End Enum
Private Declare Function SetMapMode Lib "gdi32" ( _
   ByVal hDC As Long, ByVal nMapMode As MapMode) As MapMode

Private Declare Function SetWindowExtEx Lib "gdi32" ( _
   ByVal hDC As Long, ByVal nX As Long, ByVal nY As Long, _
   lpSize As Any) As BOOL
Private Declare Function SetViewportExtEx Lib "gdi32" ( _
   ByVal hDC As Long, ByVal nX As Long, _
   ByVal nY As Long, lpSize As Any) As BOOL


Private Type BLENDFUNCTION
   BlendOp As Byte
   BlendFlags As Byte
   SourceConstantAlpha As Byte
   AlphaFormat As Byte
End Type
Private Type BLENDFUNCTIONBYVAL
   Value As Long
End Type
Private Const AC_SRC_OVER = &H0
'Alpha format flags
Private Const AC_SRC_ALPHA = &H1
'Private Const AC_SRC_NO_PREMULT_ALPHA = &H1
'Private Const AC_SRC_NO_ALPHA = &H2
'Private Const AC_DST_NO_PREMULT_ALPHA = &H10
'Private Const AC_DST_NO_ALPHA = &H20

Private Declare Function AlphaBlend Lib "msimg32" ( _
  ByVal hdcDest As Long, _
  ByVal nXOriginDest As Long, ByVal nYOriginDest As Long, _
  ByVal nWidthDest As Long, ByVal nHeightDest As Long, _
  ByVal hdcSrc As Long, _
  ByVal nXOriginSrc As Long, ByVal nYOriginSrc As Long, _
  ByVal nWidthSrc As Long, ByVal nHeightSrc As Long, _
  ByVal lBlendFunction As Long) As BOOL


Private Enum CLIPFORMAT 'Predefined Clipboard Formats
   CF_TEXT = 1
   CF_BITMAP = 2
   CF_METAFILEPICT = 3
   CF_SYLK = 4
   CF_DIF = 5
   CF_TIFF = 6
   CF_OEMTEXT = 7
   CF_DIB = 8
   CF_PALETTE = 9
   CF_PENDATA = 10
   CF_RIFF = 11
   CF_WAVE = 12
   CF_UNICODETEXT = 13
   CF_ENHMETAFILE = 14
   CF_HDROP = 15
   CF_LOCALE = 16
   CF_MAX = 17
   CF_OWNERDISPLAY = &H80
   CF_DSPTEXT = &H81
   CF_DSPBITMAP = &H82
   CF_DSPMETAFILEPICT = &H83
   CF_DSPENHMETAFILE = &H8E
   '"Public" formats don't get GlobalFree()'d
   CF_PublicFIRST = &H200
   CF_PublicLAST = &H2FF
   '"GDIOBJ" formats do get DeleteObject()'d
   CF_GDIOBJFIRST = &H300
   CF_GDIOBJLAST = &H3FF
   'Registered formats
   CF_RegisteredFIRST = &HC000&
   CF_RegisteredLAST = &HFFFF&
End Enum


Private Type GUID
   Data1 As Long
   Data2 As Integer
   Data3 As Integer
   Data4(0 To 7) As Byte
End Type

Private Declare Function CLSIDFromString Lib "ole32" ( _
   ByVal lpsz As Long, rguid As GUID) As Long
Private Const IIDSTR_IPictureDisp$ = "{7BF80981-BF32-101A-8BBB-00AA00300CAB}"

Private Enum PICTYPE
   PICTYPE_UNINITIALIZED = -1
   PICTYPE_NONE = 0
   PICTYPE_BITMAP = 1
   PICTYPE_METAFILE = 2
   PICTYPE_ICON = 3
   PICTYPE_ENHMETAFILE = 4
End Enum

Private Type PICTDESCBMP
   cbSizeOfStruct As Long
   PictType As PICTYPE
   hBmp As Long
   hPal As Long
   Reserved As Long
End Type

Private Type PICTDESCEMF
   cbSizeOfStruct As Long
   PictType As PICTYPE
   hEMF As Long
   Reserved1 As Long
   Reserved2 As Long
End Type

Private Declare Function OleCreatePictureIndirect Lib "olepro32" ( _
   pPictDesc As Any, riid As GUID, _
   ByVal fOwn As BOOL, ppvObj As IPictureDisp) As Long


#If Not PRAGMA_SAFE Then
Private Type SAFEARRAYBOUND
   cElements As Long
   lLbound As Long
End Type
Private Const FADF_STATIC As Integer = &H2       ' An array that is statically
                                                 ' allocated.
Private Const FADF_FIXEDSIZE As Integer = &H10   ' An array that may not be
                                                 ' resized or reallocated
Private Const FADF_HAVEVARTYPE As Integer = &H80 ' An array that has a VT type.
                                                 ' When set there will be a VT
                                                 ' tag at negative offset 4 in
                                                 ' the array descriptor that
                                                 ' specifies the element type.
Private Type SAFEARRAY2DHAVEVARTYPE
   vtElementType As VbVarType ' Element type
   cDims As Integer     ' Count of dimensions in this array.
   fFeatures As Integer ' Flags used by the SafeArray
   cbElements As Long   ' Size of an element of the array.
                        ' Does not include size of
                        ' pointed-to data.
   cLocks As Long       ' Number of times the array has been
                        ' locked without corresponding unlock.
   pvData As Long       ' Pointer to the data.
   ' One bound for each dimension.
   rgsabound1 As SAFEARRAYBOUND ' Dimension 1
   rgsabound2 As SAFEARRAYBOUND ' Dimension 2
End Type

'Вместо vba6 может понадобиться другая библиотека. См. Object Browser с
'включенной опцией Show Hidden Members, где находится VarPtr().
Private Declare Function VarPtrArray Lib "vba6" Alias "VarPtr" ( _
   Arr() As Any) As Long
#End If


Public Enum PictureDataFormat
   pdDIB = CF_DIB
   pdEMF = CF_ENHMETAFILE
End Enum

Private Type TQuadBytes
   bByte(0 To 3) As Byte
End Type
Private Type TLong
   lLong As Long
End Type


Dim m_nWidth As Long, m_nHeight As Long
Dim m_DS As DIBSECTION
Dim m_bmi As BITMAPINFO
Dim m_hbmMem As Long
Dim m_hbmOld As Long
Dim m_pBits As Long
Dim m_hdcSurface As Long

#If Not PRAGMA_SAFE Then
Dim m_crPixels() As Long
Dim m_sa2vtPixels As SAFEARRAY2DHAVEVARTYPE
#End If
'Перо
Dim m_nPenWidth As Long
Dim m_nPenStyle As PenStyle
Dim m_crPenColor As Long
Dim m_hpenCur As Long
Dim m_hpenOld As Long
'Кисть
Public Enum BrushStyle
   bsSolid
   bsNull
   bsPattern
   bsBDiagonal
   bsCross
   bsDiagCross
   bsFDiagonal
   bsHorizontal
   bsVertical
End Enum
Dim m_nBrushStyle As BrushStyle
Dim m_crBrushColor As Long
Dim m_crBrushBackColor As Long
Dim m_hbmBrushPattern As Long
Dim m_hbrCur As Long
Dim m_hbrOld As Long
Dim m_crOldBrushBkClr As Long
Dim m_crPenBackColor As Long
Dim m_crOldPenBkClr As Long


'Освобождение системных ресурсов
Private Sub Class_Terminate()
 If m_hbmMem Then
#If Not PRAGMA_SAFE Then
    CopyMemory ByVal VarPtrArray(m_crPixels), 0&, 4
#End If
    DeleteObject m_hbmMem: m_hbmMem = 0
 End If
 If m_hpenCur Then DeleteObject m_hpenCur: m_hpenCur = 0
 If m_hbrCur Then DeleteObject m_hbrCur: m_hbrCur = 0
End Sub

'Инициализация
Public Function Init(ByVal Width As Long, ByVal Height As Long) As Boolean
 Class_Terminate
 
 With m_bmi.bmiHeader
    .biSize = LenB(m_bmi.bmiHeader)
    .biPlanes = 1
    .biBitCount = 32
    .biWidth = Width
    .biHeight = Height
    .biCompression = BI_RGB 'BI_BITFIELDS
 End With
 m_hbmMem = CreateDIBSection(0, m_bmi, DIB_RGB_COLORS, m_pBits, 0, 0)

#If Not PRAGMA_SAFE Then
 If m_hbmMem = 0 Then Exit Function
 With m_sa2vtPixels
    .vtElementType = vbLong
    .cbElements = 4
    .cDims = 2
    .fFeatures = FADF_STATIC Or FADF_FIXEDSIZE Or FADF_HAVEVARTYPE
    .pvData = m_pBits
    .rgsabound1.cElements = Height
    .rgsabound2.cElements = Width
 End With
 CopyMemory ByVal VarPtrArray(m_crPixels), VarPtr(m_sa2vtPixels.cDims), 4
#End If

 Init = True
End Function


Public Property Get Width() As Long
 If m_hbmMem Then Width = m_bmi.bmiHeader.biWidth
End Property

Public Property Get Height() As Long
 If m_hbmMem Then Height = m_bmi.bmiHeader.biHeight
End Property


Public Function LoadPicture( _
   ByVal picSrc As IPictureDisp, _
   Optional ByVal xDst As Long, Optional ByVal yDst As Long) As Boolean
 Dim nDstWidth As Long, nDstHeight As Long
 Const TWIPS_PER_INCH = 72 * 20
 Const HIMETRIC_PER_INCH = 2540
 If picSrc Is Nothing Then Exit Function
 If picSrc.Handle = 0 Then Exit Function
 nDstWidth = picSrc.Width * TWIPS_PER_INCH / HIMETRIC_PER_INCH / _
             TwipsPerPixelX
 nDstHeight = picSrc.Height * TWIPS_PER_INCH / HIMETRIC_PER_INCH / _
              TwipsPerPixelY
 If m_hbmMem = 0 Then _
    If Not Init(nDstWidth, nDstHeight) Then Exit Function
 picSrc.Render CLng(SelectSurface), CLng(xDst), CLng(yDst), _
               CLng(nDstWidth), CLng(nDstHeight), _
               CLng(0&), CLng(picSrc.Height), _
               CLng(picSrc.Width), CLng(-picSrc.Height), ByVal 0&
 RestoreSurface
 LoadPicture = True
End Function


Public Property Get Picture( _
   Optional ByVal Format As PictureDataFormat = pdDIB, _
   Optional ByVal bAlpha As Byte = 255) As IPictureDisp
 If (Format = pdDIB) Or (Format = pdEMF) Then
    If m_hbmMem Then
       If Format = pdDIB Then
          Set Picture = DibPicture
       Else
          Set Picture = EmfPicture(bAlpha)
       End If
    End If
 Else
    Err.Raise 5
 End If
End Property

Private Property Get DibPicture() As IPictureDisp
 Dim IID_IPictureDisp As GUID
 Dim PictDesc As PICTDESCBMP
 With PictDesc
    .cbSizeOfStruct = Len(PictDesc)
    .PictType = PICTYPE_BITMAP
    .hBmp = m_hbmMem
    .hPal = 0
 End With
 CLSIDFromString StrPtr(IIDSTR_IPictureDisp), IID_IPictureDisp
 OleCreatePictureIndirect PictDesc, IID_IPictureDisp, FALSE_BOOL, DibPicture
End Property

Private Property Get EmfPicture( _
   Optional ByVal bAlpha As Byte = 255) As IPictureDisp
 Dim hicRef As Long
 Dim iWidthMM As Long
 Dim iHeightMM As Long
 Dim iWidthPels As Long
 Dim iHeightPels As Long
 Dim iDPIX As Long
 Dim iDPIY As Long
 Dim rc As RECT
 Dim hdcMeta As Long
 Dim iWEX As Long, iWEY As Long
 Dim iVEX As Long, iVEY As Long
 Dim iGCD As Long
 Dim hdcMem As Long
 Dim hbmpOld As Long
 Dim hEMF As Long
 Dim bfBlend As BLENDFUNCTION
 Dim bfvBlend As BLENDFUNCTIONBYVAL
 Dim IID_IPictureDisp As GUID
 Dim PictDesc As PICTDESCEMF
 
 hicRef = CreateIC("DISPLAY", vbNullString, vbNullString, ByVal 0&)
 iWidthMM = GetDeviceCaps(hicRef, HORZSIZE)
 iHeightMM = GetDeviceCaps(hicRef, VERTSIZE)
 iWidthPels = GetDeviceCaps(hicRef, HORZRES)
 iHeightPels = GetDeviceCaps(hicRef, VERTRES)
 iDPIX = GetDeviceCaps(hicRef, LOGPIXELSX)
 iDPIY = GetDeviceCaps(hicRef, LOGPIXELSY)
 
 'Размеры в сотых долях миллиметра
 rc.Right = Int(m_bmi.bmiHeader.biWidth * 2540 / iDPIX + 0.5)
 rc.Bottom = Int(m_bmi.bmiHeader.biHeight * 2540 / iDPIY + 0.5)
 
 'Создаём "усовершенствованный" метафайл в памяти и на диске, если дано имя
 hdcMeta = CreateEnhMetaFile(hicRef, vbNullString, rc, vbNullString)
 
 iWEX = m_bmi.bmiHeader.biWidth * iWidthMM * iDPIX * 10
 iWEY = m_bmi.bmiHeader.biHeight * iHeightMM * iDPIY * 10
 iVEX = m_bmi.bmiHeader.biWidth * iWidthPels * 254
 iVEY = m_bmi.bmiHeader.biHeight * iHeightPels * 254
 iGCD = GCD(GCD(GCD(iWEX, iWEY), iVEX), iVEY)
 SetMapMode hdcMeta, MM_ANISOTROPIC
 SetWindowExtEx hdcMeta, iWEX \ iGCD, iWEY \ iGCD, ByVal 0&
 SetViewportExtEx hdcMeta, iVEX \ iGCD, iVEY \ iGCD, ByVal 0&
 
 hdcMem = CreateCompatibleDC(hicRef)
 DeleteDC hicRef: hicRef = 0
 hbmpOld = SelectObject(hdcMem, m_hbmMem)

 bfBlend.BlendOp = AC_SRC_OVER
 bfBlend.BlendFlags = 0
 bfBlend.SourceConstantAlpha = bAlpha
 bfBlend.AlphaFormat = 0 'AC_SRC_ALPHA
 LSet bfvBlend = bfBlend
 AlphaBlend hdcMeta, 0, 0, m_bmi.bmiHeader.biWidth, m_bmi.bmiHeader.biHeight, _
            hdcMem, 0, 0, m_bmi.bmiHeader.biWidth, m_bmi.bmiHeader.biHeight, _
            bfvBlend.Value

 SelectObject hdcMem, hbmpOld: hbmpOld = 0
 DeleteDC hdcMem: hdcMem = 0
    
 hEMF = CloseEnhMetaFile(hdcMeta): hdcMeta = 0
 
 With PictDesc
    .cbSizeOfStruct = Len(PictDesc)
    .PictType = PICTYPE_ENHMETAFILE
    .hEMF = hEMF
 End With
 CLSIDFromString StrPtr(IIDSTR_IPictureDisp), IID_IPictureDisp
 OleCreatePictureIndirect PictDesc, IID_IPictureDisp, TRUE_BOOL, _
                          EmfPicture
 hEMF = 0
End Property

Public Property Get PictureData( _
   Optional ByVal Format As PictureDataFormat = pdDIB, _
   Optional ByVal bAlphaEMF As Byte = 255) As Byte()
 Dim picSrc As IPictureDisp
 Dim cbSize As Long, cbCopied As Long
 Dim bData() As Byte
 If (Format = pdDIB) Or (Format = pdEMF) Then
    If m_hbmMem = 0 Then Exit Property
    If Format = pdDIB Then
       With m_bmi.bmiHeader
          cbSize = .biSizeImage
          If cbSize = 0 Then cbSize = .biWidth * .biHeight * 4
          ReDim bData(0 To .biSize + cbSize - 1) As Byte
          CopyMemory bData(0), m_bmi.bmiHeader, .biSize
          CopyMemory bData(.biSize), ByVal m_pBits, cbSize
       End With
    Else
       Set picSrc = EmfPicture(bAlphaEMF)
       If picSrc Is Nothing Then Exit Property
       cbSize = GetEnhMetaFileBits(picSrc.Handle, 0, ByVal 0&)
       ReDim bData(0 To cbSize + 7) As Byte
       PutPicDataLong bData, cbCopied, CF_ENHMETAFILE
       PutPicDataLong bData, cbCopied, picSrc.Handle
       cbCopied = GetEnhMetaFileBits(picSrc.Handle, cbSize, bData(cbCopied))
    End If
    PictureData = bData
 Else
    Err.Raise 5
 End If
End Property

Private Function GCD(ByVal a As Long, ByVal b As Long) As Long
 Do While (a <> 0) And (b <> 0)
    If a >= b Then a = a Mod b Else b = b Mod a
 Loop
 GCD = a + b
End Function

Private Sub PutPicDataLong(bData() As Byte, nPos As Long, ByVal lValue As Long)
 Dim L As TLong
 Dim QB As TQuadBytes
 L.lLong = lValue
 LSet QB = L
 bData(nPos + 0) = QB.bByte(0)
 bData(nPos + 1) = QB.bByte(1)
 bData(nPos + 2) = QB.bByte(2)
 bData(nPos + 3) = QB.bByte(3)
 nPos = nPos + 4
End Sub


'Перо
Public Property Get PenWidth() As Long
 PenWidth = m_nPenWidth
End Property

Public Property Let PenWidth(ByVal Width As Long)
 m_nPenWidth = Width
End Property

Public Property Get PenStyle() As PenStyle
 PenStyle = m_nPenStyle
End Property

Public Property Let PenStyle(ByVal Style As PenStyle)
 m_nPenStyle = Style
End Property

Public Property Get PenColor() As Long
 PenColor = m_crPenColor
End Property

Public Property Let PenColor(ByVal Color As Long)
 m_crPenColor = Color
End Property

Public Property Get PenBackColor() As Long
 PenColor = m_crPenBackColor
End Property

Public Property Let PenBackColor(ByVal Color As Long)
 m_crPenBackColor = Color
End Property

Private Function SelectPen(ByVal hDC As Long) As Long
 m_hpenCur = CreatePen(m_nPenStyle, m_nPenWidth, m_crPenColor)
 m_hpenOld = SelectObject(hDC, m_hpenCur)
 SelectPen = m_hpenOld
 m_crOldPenBkClr = SetBkColor(hDC, m_crPenBackColor)
End Function

Private Function RestorePen(ByVal hDC As Long) As Long
 RestorePen = SelectObject(hDC, m_hpenOld): m_hpenOld = 0
 DeleteObject m_hpenCur: m_hpenCur = 0
 SetBkColor hDC, m_crOldPenBkClr
End Function


'Кисть
Public Property Get BrushStyle() As BrushStyle
 BrushStyle = m_nBrushStyle
End Property

Public Property Let BrushStyle(ByVal Style As BrushStyle)
 m_nBrushStyle = Style
End Property

Public Property Get BrushColor() As Long
 BrushColor = m_crBrushColor
End Property

Public Property Let BrushColor(ByVal Color As Long)
 m_crBrushColor = Color
End Property

Public Property Get BrushBackColor() As Long
 BrushBackColor = m_crBrushBackColor
End Property

Public Property Let BrushBackColor(ByVal Color As Long)
 m_crBrushBackColor = Color
End Property

Public Property Get BrushPattern() As Long
 If m_nBrushStyle = bsPattern Then BrushPattern = m_hbmBrushPattern
End Property

Public Property Let BrushPattern(ByVal hbmPattern As Long)
 If hbmPattern Then
    m_nBrushStyle = bsPattern
 ElseIf m_nBrushStyle = bsPattern Then
    m_nBrushStyle = bsSolid
 End If
 m_hbmBrushPattern = hbmPattern
End Property

Private Function SelectBrush(ByVal hDC As Long) As Long
 Select Case m_nBrushStyle
 Case bsSolid:
    m_hbrCur = CreateSolidBrush(m_crBrushColor)
    m_hbrOld = SelectObject(hDC, m_hbrCur)
 Case bsNull:
    m_hbrCur = GetStockObject(NULL_BRUSH)
    m_hbrOld = SelectObject(hDC, m_hbrCur)
 Case bsPattern:
    m_hbrCur = CreatePatternBrush(m_hbmBrushPattern)
    m_hbrOld = SelectObject(hDC, m_hbrCur)
 Case bsBDiagonal:
    m_hbrCur = CreateHatchBrush(HS_BDIAGONAL, m_crBrushColor)
    m_hbrOld = SelectObject(hDC, m_hbrCur)
    m_crOldBrushBkClr = SetBkColor(hDC, m_crBrushBackColor)
 Case bsCross:
    m_hbrCur = CreateHatchBrush(HS_CROSS, m_crBrushColor)
    m_hbrOld = SelectObject(hDC, m_hbrCur)
    m_crOldBrushBkClr = SetBkColor(hDC, m_crBrushBackColor)
 Case bsDiagCross:
    m_hbrCur = CreateHatchBrush(HS_DIAGCROSS, m_crBrushColor)
    m_hbrOld = SelectObject(hDC, m_hbrCur)
    m_crOldBrushBkClr = SetBkColor(hDC, m_crBrushBackColor)
 Case bsFDiagonal:
    m_hbrCur = CreateHatchBrush(HS_FDIAGONAL, m_crBrushColor)
    m_hbrOld = SelectObject(hDC, m_hbrCur)
    m_crOldBrushBkClr = SetBkColor(hDC, m_crBrushBackColor)
 Case bsHorizontal:
    m_hbrCur = CreateHatchBrush(HS_HORIZONTAL, m_crBrushColor)
    m_hbrOld = SelectObject(hDC, m_hbrCur)
    m_crOldBrushBkClr = SetBkColor(hDC, m_crBrushBackColor)
 Case bsVertical:
    m_hbrCur = CreateHatchBrush(HS_VERTICAL, m_crBrushColor)
    m_hbrOld = SelectObject(hDC, m_hbrCur)
    m_crOldBrushBkClr = SetBkColor(hDC, m_crBrushBackColor)
 End Select
End Function

Private Function RestoreBrush(ByVal hDC As Long) As Long
 Select Case m_nBrushStyle
 Case bsBDiagonal, bsCross, bsDiagCross, bsFDiagonal, bsHorizontal, bsVertical:
    SetBkColor hDC, m_crOldBrushBkClr
 End Select
 RestoreBrush = SelectObject(hDC, m_hbrOld): m_hbrOld = 0
 If m_nBrushStyle <> bsNull Then
    DeleteObject m_hbrCur: m_hbrCur = 0
 End If
End Function


'Примитивы отрисовки
Private Function SelectSurface() As Long
 m_hdcSurface = CreateCompatibleDC(0)
 m_hbmOld = SelectObject(m_hdcSurface, m_hbmMem)
 SelectSurface = m_hdcSurface
End Function

Private Function RestoreSurface() As BOOL
 SelectObject m_hdcSurface, m_hbmOld: m_hbmOld = 0
 RestoreSurface = DeleteDC(m_hdcSurface): m_hdcSurface = 0
End Function


'Точка
Public Sub DrawPixel(ByVal X As Long, ByVal Y As Long, ByVal Color As Long)
 SetPixel SelectSurface, X, Y, Color
 RestoreSurface
End Sub

Private Function SwapRB(ByVal Color As Long) As Long
 SwapRB = ((Color And &HFF&) * &H10000) Or (Color And &HFF00&) Or _
          ((Color And &HFF0000) \ &H10000)
End Function

Public Property Let Pixel(ByVal X As Long, ByVal Y As Long, ByVal Color As Long)
#If PRAGMA_SAFE Then
 If (X >= 0) And (X < m_bmi.bmiHeader.biWidth) And _
    (Y >= 0) And (Y < m_bmi.bmiHeader.biHeight) Then
    CopyMemory ByVal m_pBits + (m_bmi.bmiHeader.biWidth * _
               (m_bmi.bmiHeader.biHeight - 1 - Y) + X) * 4, _
               SwapRB(Color), 4
    'PutMem4 ByVal m_pBits + (m_bmi.bmiHeader.biWidth * _
            (m_bmi.bmiHeader.biHeight - 1 - Y) + X) * 4, SwapRB(Color)
 Else
    'Err.Raise 9
 End If
#Else
 m_crPixels(X, m_bmi.bmiHeader.biHeight - 1 - Y) = SwapRB(Color)
#End If
End Property

Public Property Get Pixel(ByVal X As Long, ByVal Y As Long) As Long
#If PRAGMA_SAFE Then
 Dim Color As Long
 If (X >= 0) And (X < m_bmi.bmiHeader.biWidth) And _
    (Y >= 0) And (Y < m_bmi.bmiHeader.biHeight) Then
    CopyMemory Color, _
               ByVal m_pBits + (m_bmi.bmiHeader.biWidth * _
               (m_bmi.bmiHeader.biHeight - 1 - Y) + X) * 4, _
               4
    'GetMem4 ByVal m_pBits + (m_bmi.bmiHeader.biWidth * _
            (m_bmi.bmiHeader.biHeight - 1 - Y) + X) * 4, _
            Color
    Pixel = SwapRB(Color)
 Else
    Err.Raise 9
 End If
#Else
 Pixel = SwapRB(m_crPixels(X, m_bmi.bmiHeader.biHeight - 1 - Y))
#End If
End Property

'Линия
Public Sub DrawLine(ByVal X0 As Long, ByVal Y0 As Long, _
                    ByVal X1 As Long, ByVal Y1 As Long)
 Dim hDC As Long
 hDC = SelectSurface()
 SelectPen hDC
 
 MoveToEx hDC, X0, Y0, ByVal 0&
 LineTo hDC, X1, Y1
 
 RestorePen hDC
 RestoreSurface
End Sub

'Прямоугольник
Public Sub DrawRectangle(ByVal X0 As Long, ByVal Y0 As Long, _
                         ByVal X1 As Long, ByVal Y1 As Long)
 Dim hDC As Long
 hDC = SelectSurface()
 SelectPen hDC
 SelectBrush hDC
 
 Rectangle hDC, X0, Y0, X1, Y1
 
 RestoreBrush hDC
 RestorePen hDC
 RestoreSurface
End Sub

'Эллипс
Public Sub DrawEllipse(ByVal X0 As Long, ByVal Y0 As Long, _
                       ByVal X1 As Long, ByVal Y1 As Long)
 Dim hDC As Long
 hDC = SelectSurface()
 SelectPen hDC
 SelectBrush hDC
 
 Ellipse hDC, X0, Y0, X1, Y1
 
 RestoreBrush hDC
 RestorePen hDC
 RestoreSurface
End Sub

'Ломаная
Friend Sub DrawPolyline(Points() As POINTAPI, Optional ByVal Count As Long)
 Dim hDC As Long
 hDC = SelectSurface()
 SelectPen hDC

 If Count = 0 Then Count = UBound(Points) - LBound(Points) + 1
 Polyline hDC, Points(LBound(Points)), Count
 
 RestorePen hDC
 RestoreSurface
End Sub

'Многоугольник
Friend Sub DrawPolygon(Points() As POINTAPI, Optional ByVal Count As Long, _
                       Optional FillMode As PolygonFillMode)
 Dim hDC As Long
 Dim nFillMode As PolygonFillMode
 hDC = SelectSurface()
 SelectPen hDC
 SelectBrush hDC
 If FillMode Then
    nFillMode = GetPolyFillMode(hDC)
    SetPolyFillMode hDC, FillMode
 End If
 
 If Count = 0 Then Count = UBound(Points) - LBound(Points) + 1
 Polygon hDC, Points(LBound(Points)), Count
 
 If FillMode Then SetPolyFillMode hDC, nFillMode
 RestoreBrush hDC
 RestorePen hDC
 RestoreSurface
End Sub


Public Function CaptureWindow( _
   ByVal hWnd As Long, _
   Optional ByVal Left As Long, Optional ByVal Top As Long, _
   Optional ByVal Width As Long, Optional ByVal Height As Long, _
   Optional ByVal NonClient As Boolean) As IPictureDisp
 Dim rcSrc As RECT
 Dim hdcSrc As Long
 Dim hdcDst As Long
 Dim hbmDstOld As Long
 Dim bRes As BOOL
 
 Do
    If NonClient Then
       If GetWindowRect(hWnd, rcSrc) = FALSE_BOOL Then Exit Do
       hdcSrc = GetWindowDC(hWnd)
    Else
       If GetClientRect(hWnd, rcSrc) = FALSE_BOOL Then Exit Do
       hdcSrc = GetDC(hWnd)
    End If
    If hdcSrc = 0 Then Exit Do
    
    If (Left Or Top Or Width Or Height) = 0 Then
       Width = rcSrc.Right - rcSrc.Left
       Height = rcSrc.Bottom - rcSrc.Top
    End If
    
    If Init(Width, Height) Then
       hdcDst = CreateCompatibleDC(hdcSrc)
       If hdcDst Then
          hbmDstOld = SelectObject(hdcDst, m_hbmMem)
          
          bRes = BitBlt(hdcDst, 0, 0, Width, Height, hdcSrc, Left, Top, SRCCOPY)
       
          SelectObject hdcDst, hbmDstOld: hbmDstOld = 0
          DeleteDC hdcDst: hdcDst = 0
       End If
    End If
    
    ReleaseDC hWnd, hdcSrc: hdcSrc = 0
    
    If bRes = FALSE_BOOL Then Exit Do
    
    'Штатный выход
    Set CaptureWindow = Picture
    Exit Function
 Loop While False
 
 'Выход при ошибке
 Class_Terminate
End Function

Public Function CaptureScreen( _
   Optional ByVal Left As Long, Optional ByVal Top As Long, _
   Optional ByVal Width As Long, Optional ByVal Height As Long) As IPictureDisp
 Set CaptureScreen = CaptureWindow(GetDesktopWindow, Left, Top, Width, Height)
End Function

...
Рейтинг: 0 / 0
Вычисление основного цвета картинки. Не чреват ли массив очень большой размерности?
    #38412374
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Бенедикт,

OK, посмотрю позже. С ходу не выловил суть из этого кода.
...
Рейтинг: 0 / 0
Вычисление основного цвета картинки. Не чреват ли массив очень большой размерности?
    #38412612
Фотография Бенедикт
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77,

суть в том, что создаётся SAFEARRAY, у которого pvData указывает на биты (тело) битмапа. В результате к пикселям можно обращаться как к элементам двумерного массива.
...
Рейтинг: 0 / 0
Вычисление основного цвета картинки. Не чреват ли массив очень большой размерности?
    #38413312
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
БенедиктДмитрий77,

суть в том, что создаётся SAFEARRAY, у которого pvData указывает на биты (тело) битмапа. В результате к пикселям можно обращаться как к элементам двумерного массива.

Бенедикт, вот этот цикл итак работает достаточно быстро
Код: vbnet
1.
2.
3.
4.
5.
      For x = x_start To dx_width - 1
        For y = y_start To dy_height - 1
          Dim rgb_v As Long
          GdipBitmapGetPixel bmp_Background, x, y, rgb_v
          If (rgb_v > -15000000) And (rgb_v < -8000000) Then


Если предлагаешь здесь что-то съкономить здесь через SAFEARRAY, ничего особо не даст.

Я просто считаю количество пикселей каждого цвета (точность цвета +/-10)

А огромный массив я использую чтоб с ходу воткнуться в "счетчик данного цвета" (цвет - номер элемента массива) -без перебора уже добавленных цветов для каждого пикселя (для VB Dictionary это задница полная, но .Net-овский Dictionary работает быстро).
Вот с этим что можно оптимизировать?

Еще что думаешь по поводу оценки
Код: vbnet
1.
If (rgb_v > -15000000) And (rgb_v < -8000000) 


Мне нужен цвет, на котором белые буквы будут хорошо видны.

Сюда смотрел (начало рассуждений)?

А как вычислить "средний цвет картинки"?
...
Рейтинг: 0 / 0
5 сообщений из 5, страница 1 из 1
Форумы / Visual Basic [игнор отключен] [закрыт для гостей] / Вычисление основного цвета картинки. Не чреват ли массив очень большой размерности?
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]