Access

  MS Access 2010+  |  Bitmapa *.bmp  |   VBA 7.0

• Grafika w formancie Rysunek (Image)

We wszystkich przykładach dotyczących przetwarzania bitmap, korzystał będę z nieskompresowanych bitmap o 24-bitowej głębi kolorów. Pliki takie muszą spełnić następujące warunki:

Znak Informacja dodatkowa
  • musi posiadać 14 bajtowy nagłówek BITMAPFILEHEADER,
  • ma to być plik bitmapy o sygnaturze 'BM' (&H424D),
  • musi posiadać 40 bajtowy nagłówek BITMAPINFOHEADER,
  • musi posiadać 24 bitową głębię kolorów,
  • ma być zapisany bez użycia algorytmów kompresujących,
  • kierunek bajtów w tablicy bajtów obrazu bitmapy musi być z „z dołu do góry”,

Formant ImageFormant Rysunek (Image) Formant Image (Rysunek) jest najczęściej wykorzystywany w aplikacji MS Access do prezentacji statycznej grafiki (rysunku) w formularzu lub w raporcie.
Zawartości formantu Image (Rysunek) nie można edytować jak to ma miejsce w przypadku związanej i niezwiązanej ramki obiektu, która umożliwia edytowanie obiektu pomocą aplikacji, w której prezentowany obiekt został utworzony. Główna zaletą formantu Image (Rysunek) jest o wiele większa szybkość wyświetlania prezentowanej grafiki, co jest dość istotne zwłaszcza przy prezentowaniu większych obiektów graficznych. Rozmiar i proporcje wyświetlanej grafiki w formancie Image (Rysunek) można ustawić za pomocą właściwości .SizeMode.

Właściwości SizeMode. Rozmiar i proporcje wyświetlanej grafiki.

Właściwość .SizeMode może mieć następujące ustawienia:

  • Obetnij — rozmiar obrazu nie ulega zmianie, jeśli nie mieści się wewnątrz formantu to zostaje przycięty,
  • Rozciągnij — rysunek jest skalowany tak, aby zmieścił się wewnątrz formantu. Operacja taka najczęściej prowadzi do zniekształcenia obrazu, gdy proporcje obrazu i formantu są różne,
  • Powiększ — rysunek jest wyświetlany w całości po przeskalowaniu, tak aby jego wysokość lub szerokość została dopasowana do odpowiednich wymiarów formantu. Ustawienie to nie zniekształca obrazu, ale obraz może nie wypełniać całej szerokości lub wysokości formantu.

Dokładniejszy opis formantu Image (Rysunek) znajduje się na stronie Image.PictureData, a opis właściwości Tryb Wymiarowania na stronie Właściwość SizeMode.

Właściwości PictureType (TypRysunku)

Właściwość PictureType informuje, w jaki sposób formant przechowuje grafikę, którą ma wyświetlać.
Połączony (Linked) przechowywana jest tylko ścieżkę do pliku na dysku.
Osadzony (Embedded) formant przechowuje wszystkie bajty, z których składa się rysunek.
Domyślnie technologia OLE tworzy odpowiednik obrazu w postaci mapy bitowej i rozmiar bazy danych powiększa się o rozmiar pliku rysunku, W skrajnym wypadku rozmiar może wzrosnąć kilkunastokrotnie.

Tak naprędce zrobiony przykład:

24-bitowa bitmapa 1x1 piksel zajmuje:
• na dysku 58 bajtów
• osadzona 44 bajty
  zapisana jako plik *.jpg zajmuje:
• na dysku 734 bajty
• osadzona 780 bajtów
24-bitowa bitmapa 634x473 zajmuje:
• na dysku 900 646 bajtów
• osadzona 900 632 bajty
   zapisana jako plik *.jpg zajmuje:
• na dysku      72 374 bajty
• osadzona 1 801 828 bajtów

Jak widać, na pliku *.jpg przebicie jest ok. 25-krotne, a w stosunku do bitmapy 2-krotne.

Format przechowywania właściwości obrazów

Począwszy od wersji Microsoft Access 2007+ w Menu: „Opcje programu Access”/„Bieżąca baza danych”/
„Format przechowywania właściwości obrazów” mamy do wyboru jedną z dwu opcji:

Format przechowywania obrazu

Opcje formatu przechowywania właściwości obrazów

  • Zachowaj format obrazu źródłowego (mniejszy rozmiar pliku). Graficzne pliki źródłowe będą przechowywane w ich oryginalnym formacie. Rozmiar bazy powiększy się jedynie o wielkość pliku graficznego, ale proces wyświetlania plików będzie dłuższy, gdyż MS  Access konwertował będzie za każdym razem oryginalny pliki do formatu bitmapy.
  • Konwertuj wszystkie dane obrazu na mapy bitowe (zgodne z programem Access 2003 i wcześniejszymi wersjami). MS  Access tworzy kopię oryginalnego pliku obrazu w formacie gotowym do wyświetlenia na ekranie.
    WAŻNE
    W aspekcie poruszanych przeze mnie tematów dotyczących bitmap pliki graficzne zapisane w formacie 24-bitowej bitmapy  BMP nie powodują zwiększenia wielkość bazy. Wręcz odwrotnie, dane są mniejsza o 14 bajtów (wielkość nagłówka BitmapFileHeader) dla każdego pliku graficznego w porównaniu do opcji Zachowaj format obrazu źródłowego.

Więcej informacji o właściwość PictureType (TypRysunku ), „Formacie przechowywania właściwości obrazów” oraz właściwości „PictureData” formantu Image (Rysunek) znajduje się na stronie Image.PictureData

Takie małe dywagacje.

Jeżeli plik *.bmp zajmuje na dysku 900 000 bajtów i praktycznie tyle samo (mniej o 14 bajtów) w formancie Image (Rysunek), a skompresowany plik *.jpg na dysku zajmuje zaledwie 72 000 bajty (12 x mniej) od bitmapy, ale osadzony w formancie Image (Rysunek) zajmuje 1 800 000 bajtów, czyli ok. 2 x więcej niż bitmapa.
To co jest lepsze?
Osadzenie w formancie Image (Rysunek) dużego pliku *.bmp, zajmującego 2 x mniej zasobów, czy mniejszego pliku *.jpg, zajmującego 2 x więcej zasobów ?

Właściwość „Format przechowywania właściwości obrazów”

W nowo utworzonej bazie MS Access 2007+ w formacie pliku *.accdb właściwość „Format przechowywania właściwości obrazów ” (Picture Property Storage Format) jest domyślnie ustawiona na wartość 0, „Zachowaj format obrazu źródłowego”.

Gdy utworzymy w MS Access 2007+ bazę w starszym formacie pliku *.mdb, to właściwość ta nie jest ustawiona, a raczej właściwość ta nie istnieje. Co prawda w oknie „Opcje programu Access” zaznaczone będzie pole opcji „Konwertuj wszystkie dane obrazu na mapy bitowe (zgodne z programem Access 2003 i wcześniejszymi wersjami)”, ale przy próbie pobrania właściwości „Picture Property Storage Format” wystąpi błąd wykonania nr 3270 o treści "Nie odnaleziono właściwości".

Właściwość nie istnieje

Właściwość nie istnieje

Jednak wystarczy tylko otworzyć okno „Opcje programu Access” i kliknąć przycisk „OK” by MS Access utworzył właściwość „Format przechowywania właściwości obrazów” i przypisał jej wartość 1, co odpowiada opcji „Konwertuj wszystkie dane obrazu na mapy bitowe (zgodne z programem Access 2003 i wcześniejszymi wersjami)”.

Bitmapa w formancie Image (Rysunek)

Informacja o ”Formacie przechowywania właściwości obrazów” w odniesieniu do 24-bitowej bitmapy jest potrzebna, by wiedzieć czy właściwość Image.PictureData zawiera 14 bajtowy nagłówek BITMAPFILEHEADER,

  • dla wartości 0
    „Zachowaj format obrazu źródłowego” formant Image (rysunek) we właściwości .PictureData przechowuje 14 bajtowy nagłówek BITMAPFILEHEADER.
  • dla wartości 1
    Konwertuj wszystkie dane obrazu na mapy bitowe” właściwość Image.PictureData nie zawiera 14 bajtowego nagłówka BITMAPFILEHEADER.

Aby dowiedzieć się jak MS Access przechowuje pliki graficzne, musimy pobrać wartość właściwości „Picture Property Storage Format (Format przechowywania właściwości obrazów” za pomocą funkcji dbsPictureStorageFormat(...), która:

⊗ Public Function bmpPictureStorageFormat( _
                Optional lPictStorageFormat As Long _
                         = cPrpStorageNotChange) As Long
  • 'Pobiera numer wersji Ms Access za pomocą funkcji Numer wersji MS Access (...). Jeżeli MS Access jest w wersji 2003 lub niższej, funkcja zwraca wartość cPrpStorageNotFound = - 1. Chociaż właściwość „Picture Property Storage Format” nie istnieje, ale wersje niższe MS Access konwertują pliki graficzne na mapy bitowe zgodne programem Access 2003 i wcześniejszymi wersjami, czyli faktycznie zwrócona wartość odpowiada wartości stałej cPrpStorageConvert = 1
    'Gdy MS Access jest w wersji 2007 i wyższej, funkcja próbuje pobrać właściwość „Format przechowywania właściwości obrazów”. Jeżeli właściwość ta istnieje, pobierana jest jej wartość. Dla wartości argumentu lPictStorageFormat = 0 lub = 1 ustawia nową wartość i równocześnie ją zwraca. Dla wartości argumentu lPictStorageFormat = cPrpStorageNotChange zwraca jedynie wartość właściwości. Jeżeli właściwość nie istnieje, występuje błąd wykonania nr 3270 o treści "Nie odnaleziono właściwości". Dzięki instrukcji On Error Resume Next kontynuowane jest wykonywania kodu bez względu na występujące ewentualne błędy. Wygenerowany błąd zostaje przechwycony i w zależności od wartości argumentu lPictStorageFormat zostaje utworzona właściwość „Picture Property Storage Format” o wartości lPictStorageFormat, która zostaje zwrócona, bądź funkcja zwraca wartość cPrpStorageNotFound = - 1.
  • argumenty:
    • lPictStorageFormat
    • opcjonalny argument określający nową wartość właściwości „Formatu przechowywania właściwości obrazów”. Dla wartości domyślnej cPrpStorageNotChange = - 2 wartość właściwości zostaje tylko pobrana (wartość właściwość nie ulega zmienianie).
  • zwraca:
  • Przy powodzeniu zwraca wartość właściwości „Format przechowywania właściwości obrazów”
    •  0 - Zachowaj format obrazu źródłowego (dla wersji MS Access 2007 i wyższe)
    •  1 - Konwertuj wszystkie dane obrazu na mapy bitowe (zgodne
             z programem Access 2003 i wcześniejszymi wersjami)
    • -1 Właściwość nie jest ustawionej (dla wersji MS Access 2007 i wyższej)
    • -3 errOthUnexpected wartość zwracana przy niepowodzeniu
  • autor: Zbigniew Bratko
  • data: 04.02.2019
Public Function bmpPictureStorageFormat( _
                Optional lPictStorageFormat As Long _
                         = cPrpStorageNotChange) As Long

Dim dbs            As DAO.Database
Dim prp            As DAO.Property
Dim lStorageFormat As Long
Dim lErrNumber     As Long
Dim strErrDscription  As String
Const cProcName       As String = "Funkcja bmpPictureStorageFormat(...)"

	' ustaw domyślną zwracaną wartość
	bmpPictureStorageFormat = cPrpStorageUnknown

	'sprawdź poprawność argumentu: <= 1
	If lPictStorageFormat  > cPrpStorageConvert Then
		bmpPictureStorageFormat = errArgFailValue
		Err.Raise errArgFailValue, cProcName, _
							errBmpDescription(errArgFailValue)
	End If

	'sprawdź wersję MS Access
	If vbaVersionAccess < cAccVersion2007 Then
		'Access jest w wersji 2003 lub niższej, (właściwość nie występuje)
		bmpPictureStorageFormat = cPrpStorageNotFound
		Exit Function
	End If

	Set dbs = CurrentDb
		With dbs
			On Error Resume Next
				' ponieważ właściwość może być nieustawiona, włącz pułapkowanie błędu
				' i spróbuj pobrać format przechowywania obrazów
				lStorageFormat = .Properties(cPrpStoragePictureName)
				If Err.Number = 0 Then
					'właściwość jest ustawiona, zapisz wartość
					bmpPictureStorageFormat = lStorageFormat
					If lPictStorageFormat  >= 0 Then
						' ustaw właściwość, jeżeli wartość jest inna niż przekazana
						If lPictStorageFormat < > lStorageFormat Then
							.Properties(cPrpStoragePictureName) = lPictStorageFormat
							' zwróć wartość właściwości
							bmpPictureStorageFormat = .Properties(cPrpStoragePictureName)
						End If
					End If
				Else
					' właściwość nie jest ustawiona
					If Err.Number = cAccPrpNotFound Then
						' i nie jest wymagana zmiana, zwróć brak
						' właściwości cPrpStorageNotFound = (-1)
						If lPictStorageFormat < 0 Then
							bmpPictureStorageFormat = cPrpStorageNotFound
						Else
							'utwórz właściwość i przypisz jej wartość
							Set prp = .CreateProperty( _
								cPrpStoragePictureName, _
										dbLong, lPictStorageFormat)
										.Properties.Append prp
								.Properties.Refresh
								bmpPictureStorageFormat = _
										.Properties(cPrpStoragePictureName)
							Set prp = Nothing
						End If
					Else
						'nieprzewidziany błąd, włącz obsługę błędów i wygeneruj błąd
						On Error GoTo 0
						Err.Raise Err.Number, cProcName, Err.Description
					End If
				End If
			On Error GoTo 0
		End With
	Set dbs = Nothing

End Function
Option Compare Database
Option Explicit

Public Const cAccVersion2007   As Long = 12      'numer wersji MS Access 2007

'+-----------------------------------------------+
'|              Const - Bitmap                   |
'+-----------------------------------------------+
Public Const cBmpIntSignature  As Integer = &H4D42   'sygnatura bitmapy "BM" jako liczba Integer
Public Const cBmpSignatureBM   As String = "BM"      'sygnatura bitmapy "BM" jako ciąg znaków
Public Const cBmpBfhSize       As Long = 14          'wielkość nagłówka BitmaFileHeader
Public Const cBmpBihSize       As Long = 40          'wielkość nagłówka BitmapInfoHeader
Public Const cBmpBfOffBits     As Long = 54          'przesunięcie do bajtów obrazu bitmapy
Public Const cBmpBitCount24    As Long = 24          'głębia kolorów - bitów na piksel
Public Const cBmpBitCount32    As Long = 32          'głębia kolorów - bitów na piksel
Public Const cBmpNotCompressed As Long = 0           'nieskompresowana bitmapa BI_RGB = 0&
Public Const cBmpMinSize       As Long = 58          'minimalny rozmiar bitmapy 24bit 14+40+4

'+-----------------------------------------------+
'| Const - PictureStorageFormat MS Access 2007+  |
'+-----------------------------------------------+
' nr błędu "Nie odnaleziono właściwości"
Public Const cAccPrpNotFound        As Long = 3270
' Nazwa właściwości "Format przechowywania właściwości obrazów"
Public Const cPrpStoragePictureName As String = "Picture Property Storage Format"
' Zachowaj format obrazu źródłowego, domyślnie dla nowej bazy w formacie .accdb
Public Const cPrpStoragePreserve    As Long = 0
' Konwertuj wszystkie dane obrazu na mapy bitowe
Public Const cPrpStorageConvert     As Long = 1
' przy tworzeniu nowej bazy MS Access 2007+ w starszym formacie .mdb,
' opcja jest zaznaczona jako 1, ale właściwość ta nie jest ustawiona,
' zgłaszany jest błąd nr 3270 "Nie odnaleziono właściwości"
Public Const cPrpStorageNotFound    As Long = -1
' tylko odczyt właściwości
Public Const cPrpStorageNotChange   As Long = -2
' nieprzewidziany błąd
Public Const cPrpStorageUnknown     As Long = -3
Option Compare Database
Option Explicit

'+-----------------------------------------------+
'|   Errors - własna obsługa niektórych błędów   |
'+-----------------------------------------------+

'inny, nieprzewidziany błąd
Public Const errOthUnexpected       As Long = vbObjectError + 1
'-----------------------------------------------------------------
'dolna granica zakresu numerów błędów dotyczących plików
Private Const errFileError          As Long = vbObjectError + 100
'nazwa pliku zawiera nieprawidłowe znaki
Public Const errFileBadName         As Long = errFileError + 1
'plik istnieje na dysku
Public Const errFileExist           As Long = errFileError + 3
'plik nie istnieje na dysku
Public Const errFileNotExist        As Long = errFileError + 4
'--------------------------------------------------------------------
'dolna granica zakresu numerów błędów dotyczących argumentów funkcji
Private Const errArgsError          As Long = vbObjectError + 200
'argument musi być tablicą
Public Const errArgIsNotArray       As Long = errArgsError + 1
'tablica jest niezainicjowana
Public Const errArrayNotInitialized As Long = errArgsError + 2
'nieprawidłowa wartość argumentu
Public Const errArgFailValue        As Long = errArgsError + 3
'--------------------------------------------------------------------
'dolna granica zakresu numerów błędów dotyczących bitmap
Private Const errBmpError           As Long = vbObjectError + 300
'błąd formatu pliku (nieprawidłowa sygnatura pliku)
Public Const errBmpFailSignature    As Long = errBmpError + 1
'błąd formatu nagłówka BitmapInfoHeader
Public Const errBihFailFormat       As Long = errBmpError + 2
'błąd formatu nagłówka BitmapInfoHeader
Public Const errBihFailSize         As Long = errBmpError + 3
'brak nagłówka BitmapInfoHeader
Public Const errBihNotExist         As Long = errBmpError + 4
'nagłówek musi być tablicą jednowymiarową
Public Const errBihOneDimension     As Long = errBmpError + 5
'obsługiwana jest tylko 24 i 32-bitowa głębia kolorów
Public Const errBmpBitCount         As Long = errBmpError + 6
'obsługiwana jest tylko 24 głębia kolorów
Public Const errBmpOnlyBitCount24   As Long = errBmpError + 7
'obsługiwana jest tylko 24 głębia kolorów
Public Const errBmpIsCompressed     As Long = errBmpError + 8
'obsługiwana jest tylko bitmapa z 'dołu do góry'
Public Const errBmpIsTopDown        As Long = errBmpError + 9
'Plik bitmapy jest zbyt mały (min. 58 bajtów)
Public Const errBmpTooSmall         As Long = errBmpError + 10
'--------------------------------------------------------------------
'dolna granica zakresu numerów błędów dotyczących Właściwości
Private Const errPrpError           As Long = vbObjectError + 1000
'nie można ustawić właściwości „Picture Property Storage Format”
'(Format przechowywania właściwości obrazów)
Public Const errPropertyStorage     As Long = errPrpError + 1
'nieoczekiwany błąd ustawienia właściwości Format przechowywania
'właściwości obrazów (Picture Property Storage Format)"
Public Const errPropertyStorageFail As Long = errPrpError + 2


' zwraca opis błędu własnego o numerze lErrNo
Public Function errBmpDescription(lErrNo As Long) As String
Dim sErrDscr As String

	Select Case lErrNo
	'------------------------- errFileError = vbObjectError + 100
	Case errFileBadName
		sErrDscr = "Pełna nazwa pliku zawiera nieprawidłowy znak"
	Case errFileExist
		sErrDscr = "Plik docelowy istnieje."
	Case errFileNotExist
		sErrDscr = "Plik nie istnieje na dysku."
	'------------------------- errArgsError = vbObjectError + 200
	Case errArgIsNotArray
		 sErrDscr = "Argumentem funkcji musi być tablicą."
	Case errArrayNotInitialized
		 sErrDscr = "Tablica nie jest zainicjowana."
	Case errArgFailValue
		 sErrDscr = "Nieprawidłowa wartość argumentu."
	'------------------------- errBmpError = vbObjectError + 300
		Case errBmpFailSignature
			sErrDscr = "Niewłaściwa sygnatura pliku bitmapy."
		Case errBihFailFormat
			sErrDscr = "Błąd formatu nagłówka BitmapInfoHeader"
		Case errBihFailSize
			sErrDscr = "Nagłówek BitmapInfoHeader musi mieć wielkość 40 bajtów"""
		Case errBihNotExist
			sErrDscr = "Niezainicjowany nagłówek BitmapInfoHeader bitmapy."
		Case errBihOneDimension
			sErrDscr = "Nagłówek BitmapInfoHeader " & _
								 "musi być tablicą jednowymiarową."
		Case errBmpBitCount
			sErrDscr = "Obsługiwana jest tylko bitmapa" & vbNewLine & _
								 "o 24 lub 32-bitowej głębi kolorów."
		Case errBmpOnlyBitCount24
			sErrDscr = "Obsługiwana jest tylko bitmapa" & vbNewLine & _
								 "o 24-bitowej głębi kolorów."
		Case errBmpIsCompressed
			sErrDscr = "Bitmapa skompresowana nie jest obsługiwana."
		Case errBmpIsTopDown
			sErrDscr = "obsługiwana jest tylko bitmapa z 'dołu do góry'."
		Case errBmpTooSmall
			sErrDscr = "Plik jest zbyt mały." & vbNewLine & _
								 "Minimalna wielkość to " & cBmpMinSize & " bajtów"
		Case Else
			sErrDscr = "Nieprzewidziany błąd Aplikacji." & vbNewLine & _
								 "Zanotuj nr błędu i opis" & vbNewLine & _
								 "i skontaktuj się z Administratorem."
	End Select

	errBmpDescription = sErrDscr

End Function
' Public Function vbaVersionAccess() As Integer
' Wykorzystując funkcję SysCmd z argumentem acSysCmdAccessVer pobiera do zmiennej
' typu Variant wersję programu MS Access i konwertuje zwracaną wartość na typ Integer.
'   argumenty:
'     nie pobiera argumentów
'   zwraca:
'     Przy powodzeniu zwraca nr wersji MS Access. Przy niepowodzeniu zwraca ZERO.
' autor: Zbigniew Bratko
' data: 08.02.2019

Public Function vbaVersionAccess() As Integer
Dim varVersion As Variant
 
	varVersion = Nz(Application.SysCmd(acSysCmdAccessVer), 0)
	If IsNumeric(varVersion) Then
		vbaVersionAccess = CInt(varVersion)
	Else
		vbaVersionAccess = Val(varVersion)
	End If

End Function