<

More Fun with Really Large, High Fidelity Images in Access Reports

Published on
13,177 Points
2,277 Views
4 Endorsements
Last Modified:
Awarded
In my article "Printing many large images in MS Access reports" I demonstrated techniques to dynamically resize large images that Access has trouble rendering down to a size that Access can print. Which is all well and fine.

Right up until you have a really large image with fine detail (like say printing) on it that you need to be able to zoom in on when you render the report as a PDF.  And then, grinding the image down to 96 DPI doesn't work out quite so well.  And yes, I suppose you could break out good, old MSPaint (or Paint.NET or any other image editing software) and break your image down into a few segments, and add THOSE images to your report instead of the very large original.

Of course, that would get REALLY old if you had to do it repeatedly. It would be a lot nicer if Access, even if it can't render the original of the image you'd like, could do the scutwork of breaking the image down to chunks and displaying those. And, very fortunately, with some WIA code and some restructuring of the report, it can.  

And it would be REALLY good if you could have some flexibility in deciding, right at the time you add the picture's path to the database, how many segments you'd like to break the image into, how much overlap each of the segments should have, how big the control that displays them on the report should be, and how many DPI the images should be rendered in. You know, all the good stuff. So, let's do that.

Ok, download and open the attached files. (You will likely need to check and change paths to the image to reflect where you place the files. That'll be needful in the table, and in any of the reports besides rptDisplayMain. Try placing them in C:\PrintIt for best effect). Now open rptBigImage in Design View. So, I've built this report by putting the image on the report. But at first it tried to render on multiple pages. By the time I resized the control to fit on a single page, while the image shows in design view, it won't preview and it won't print. Darn.

Alright, Let's get an unbound image control on a report, and we'll use the Detail's OnFormat event to point it at the BigImage.jpg. That report is rptLinkedImage. Go ahead and preview it. It looks good! Great! Print it. No joy. The image displays but it is unwilling to be printed to paper or rendered to PDF. Now what? We want that big image, and we want it at a high resolution. That's where the WIA 2.0 library, which is installed by default on all Vista and later machines comes in (it is getting very hard to find the official download for XP).

In the previous article, we used WIA's Scale filter to resize an image. We'll use that again, but what we are also going to use is WIA's crop filter to create images that are portions of a larger image. First though, let's select an image and display some EXIF information about it, as well as dimensions. This code comes from the frmSelectImages form in the attached sample.
Option Compare Database
Option Explicit

'need a reference to the MS Office Objects XX.0 (11.0 12.0, 14.0 whichever) library
'need a reference to MS Windows Image Acquisition 2.0 library

Private Sub cmdSelect_Click()
'Declare a variable as a FileDialog object.
Dim fd As FileDialog

'Create a FileDialog object as a File Picker dialog box.
Set fd = Application.FileDialog(msoFileDialogFilePicker)
'Declare a variable to contain the path
'of the selected item. Even though the path is a String,
'the variable must be a Variant because the For Each...Next
'routines only work with Variants and Objects.
Dim vrtSelectedItem As Variant

Dim EXIFProperties As String
Dim p As WIA.Property
Dim Img As WIA.ImageFile
Dim IP As WIA.ImageProcess
Dim v As WIA.Vector

Set Img = CreateObject("WIA.ImageFile")
Set IP = CreateObject("WIA.ImageProcess")
Set v = CreateObject("WIA.Vector")

'Use a With...End With block to reference the FileDialog object.
With fd
    .InitialView = msoFileDialogViewThumbnail 'nice for images, for files use msoFileDialogViewDetails
    .Title = "Image Selector"
    .InitialFileName = Application.CurrentProject.Path 'let's point at the folder we're in to start
    .ButtonName = "Select"
    .AllowMultiSelect = False ' uh uh, only one at a time buckwheat

    'Use the Show method to display the File Picker dialog box and return the user's action.
    'The user pressed the action button.
    If .Show = True Then
        'check that only one file was picked
        If .SelectedItems.Count > 1 Then
            MsgBox "You may only select one item.  Try again!"
            Exit Sub
        Else
            vrtSelectedItem = .SelectedItems(1)
        End If
        
        'Now what?  We've got a file selected
        'Let's stuff its path into the textbox
        Me.txtPath = vrtSelectedItem
        'Let's load the image in WIA and get some properties
        Img.LoadFile vrtSelectedItem

        For Each p In Img.Properties
            Select Case p.PropertyID
                Case 271 'camera maker
                Case 272 'camera model
                Case 274 'orientation 1 normal, 3 flip, 6 clockwise 90º, 8 clockwise 270º
                Case 306 'datetime
                Case Else
                    'the rest may interest you, but I am skipping them
                    'comment out the GoTo to see all the properties EXIF has about a file
                    GoTo skip
            End Select
        
            EXIFProperties = EXIFProperties & p.Name & "(" & p.PropertyID & ") = "
            If p.IsVector Then
                EXIFProperties = EXIFProperties & "[vector data not emitted]" & vbCrLf
            ElseIf p.Type = RationalImagePropertyType Then
                EXIFProperties = EXIFProperties & p.Value.Numerator & "/" & p.Value.Denominator & vbCrLf
            ElseIf p.Type = StringImagePropertyType Then
                EXIFProperties = EXIFProperties & """" & p.Value & """" & vbCrLf
            Else
                EXIFProperties = EXIFProperties & p.Value & vbCrLf
            End If
skip:
        Next
        EXIFProperties = EXIFProperties & "Width: " & Img.Width & vbCrLf
        EXIFProperties = EXIFProperties & "Height: " & Img.Height
    End If
End With

Me.txtEXIF = EXIFProperties
End Sub

Open in new window

Ok, so we have some code to select the big images and tell us something about them. Now what? Well, if it was me -- and it is -- I'd like to decide how many fragments I'd like to split the original into (1,2,4,9), how much overlap each fragment should have with its neighbor, what target DPI I'd like all the fragments to have, and how big an image control I intend to display the fragments in. And if you look on frmSelectImages, you'll see all those options. Now, look at the code behind cmdCommit. You may be saying 'hold the phone, there's nothing going on there, you're just writing a record to the database.' Exactly!  Here's the code behind cmdCommit
Private Sub cmdCommit_Click()
Dim db As Database
Dim rs As Recordset

Set db = CurrentDb
Set rs = db.OpenRecordset("select * from tblPictures where 1=2;", dbOpenDynaset, dbSeeChanges)
With rs
    .AddNew
    !picpath = Me.txtPath.Value
    !fragments = Me.txtFragments.Value
    !Overlap = Me.txtOverlap.Value
    !desireddpi = Me.txtDPI.Value
    !DesiredWidth = Me.txtWidth.Value
    !comment = Me.txtComment.Value
    .Update
End With
MsgBox "Done!"
    
End Sub

Open in new window

After all, I said we wanted to do things dynamically. If I'd have put the code behind the cmdCommit, then it would have been one-off. The split-down files would have been created and need saving. And that's not the idea. The idea is to have the report do the heavy lifting. So, what do we need?

Well, since the idea is to be able to save the original, and display the fragments, we'll have to adjust the report.  Instead of an image control on the main report, the image control will go on a subreport.  The process of creating the fragments needs to populate a table of temporary data to associate the newly created fragments with the original image.  The fundamentals of the techniques of temporary data are discussed in my article here.

Once we've got the table structure knocked into shape, we can work out the child/master relationship between the subreport and the main report. Some code to create the fragments and the needed temporary records and we're close to being in business.  Here's the code behind the main report
Option Compare Database
Option Explicit
'reference to Microsoft Windows Image Acqusitiion Library 2.0 is required
'***use the code as desired
'***please maintain a reference to Nick67 of Experts Exchange as the author

Private Sub Report_Open(Cancel As Integer)
Dim myfolder As Object
Dim myfile As Object
Dim success As Boolean
Dim fs As Object 'our friend the filesystemobject
Set fs = CreateObject("Scripting.FileSystemObject")

Dim TempPath As String
TempPath = CurrentProject.Path & "\Resized\" ' a place to store dynamically generated images

If fs.folderexists(TempPath) = False Then
    fs.createfolder (TempPath)
Else
    'clean out resized folder
    Set myfolder = fs.getfolder(TempPath)
    For Each myfile In myfolder.Files
        fs.DeleteFile myfile.Path, True 'whack the file, force it to die
    Next myfile
End If

'let's empty tblTempPics
Application.SetOption "Confirm Action Queries", False
DoCmd.RunSQL ("delete * from tblTempPics;")
Application.SetOption "Confirm Action Queries", True

'variables for a recordset in tblPictures which stores the path to the images
Dim db As Database
Dim rs As Recordset

Set db = CurrentDb
Set rs = db.OpenRecordset("SELECT * FROM [tblPictures]", dbOpenDynaset, dbSeeChanges)
'there's only one at the moment, in production, you'll need to pare that down

'completely with the recordset so there's no oddities
rs.MoveLast
rs.MoveFirst

Do Until rs.EOF 'walk it through
    success = SplitEm(rs!PicPath, rs!PictureID)
    'splitem, and it calls shrinkem
    rs.MoveNext
Loop
End Sub

Private Function SplitEm(PicPath As String, PictureID As Long)
'yes you could combine spliting and shrinking into one operation
'but what if you only want to split in certain circumstances?
'so I built a separate sub
Dim s As String
Dim BuiltPath As String
Dim TempPath As String
Dim x As Integer
Dim Img As WIA.ImageFile
Dim myfolder As Object
Dim myfile As Object
Dim db As Database
Dim rs As Recordset

Dim IP As ImageProcess
Set IP = CreateObject("WIA.ImageProcess")

IP.Filters.Add IP.FilterInfos("Crop").FilterID
            
BuiltPath = PicPath 'rs!Path 'where the original is
TempPath = CurrentProject.Path & "\Resized\" ' a place to store dynamically generated images

Set db = CurrentDb
Set rs = db.OpenRecordset("SELECT * FROM [tblPictures] where PictureID = " & PictureID, dbOpenDynaset, dbSeeChanges)

Dim DesiredDPI As Integer
Dim DesiredWidth As Single
Dim Fragments As Integer
Dim Overlap As Single

DesiredDPI = rs!DesiredDPI ' from the table
DesiredWidth = rs!DesiredWidth
Fragments = rs!Fragments
Overlap = rs!Overlap

Select Case Fragments
    Case 1
        'don't need to split, just need to scale
        Set Img = CreateObject("WIA.ImageFile")
        Img.LoadFile (BuiltPath) 'load the stored jpg in WIA
        s = TempPath & PictureID & "-" & x & "-crop.jpg"
        Img.SaveFile (s)
        Set Img = Nothing
        Call ShrinkEm(s, PictureID) 'original path
    Case 2
        'ok, I'm going to create 4 images
        'each of them will be 50% + overlap of the originals, oriented on the top corners
        'crop works by specifying how many pixels in from the location of the four corners you want to the crop points to be
        For x = 1 To 2
            Set Img = CreateObject("WIA.ImageFile")
            Img.LoadFile (BuiltPath) 'load the stored jpg in WIA
            Select Case x
                Case 1 'top left
                    IP.Filters(1).Properties("Left") = 0
                    IP.Filters(1).Properties("Top") = 0
                    IP.Filters(1).Properties("Right") = Img.Width * (0.5 - Overlap)
                    IP.Filters(1).Properties("Bottom") = 0 'Img.Height
                Case 2 'top right
                    IP.Filters(1).Properties("Left") = Img.Width * (0.5 - Overlap)
                    IP.Filters(1).Properties("Top") = 0
                    IP.Filters(1).Properties("Right") = 0
                    IP.Filters(1).Properties("Bottom") = 0 'Img.Height
            End Select
        
            Set Img = IP.Apply(Img)
            s = TempPath & PictureID & "-" & x & "-crop.jpg"
            Img.SaveFile (s)
            Set Img = Nothing
            Call ShrinkEm(s, PictureID)
        Next x
    Case 4
        'ok, I'm going to create 4 images
        'each of them will be 65% of the originals, oriented on each of the four corners
        For x = 1 To 4
            Set Img = CreateObject("WIA.ImageFile")
            Img.LoadFile (BuiltPath) 'load the stored jpg in WIA
            Select Case x
                Case 1 'top left
                    IP.Filters(1).Properties("Left") = 0
                    IP.Filters(1).Properties("Top") = 0
                    IP.Filters(1).Properties("Right") = Img.Width * (0.5 - Overlap)
                    IP.Filters(1).Properties("Bottom") = Img.Height * (0.5 - Overlap)
                Case 2 'top right
                    IP.Filters(1).Properties("Left") = Img.Width * (0.5 - Overlap)
                    IP.Filters(1).Properties("Top") = 0
                    IP.Filters(1).Properties("Right") = 0
                    IP.Filters(1).Properties("Bottom") = Img.Height * (0.5 - Overlap)
                Case 3 'bottom left
                    IP.Filters(1).Properties("Left") = 0
                    IP.Filters(1).Properties("Top") = Img.Height * (0.5 - Overlap)
                    IP.Filters(1).Properties("Right") = Img.Width * (0.5 - Overlap)
                    IP.Filters(1).Properties("Bottom") = 0
                Case 4 'bottom right
                    IP.Filters(1).Properties("Left") = Img.Width * (0.5 - Overlap)
                    IP.Filters(1).Properties("Top") = Img.Height * (0.5 - Overlap)
                    IP.Filters(1).Properties("Right") = 0
                    IP.Filters(1).Properties("Bottom") = 0
            End Select
            Set Img = IP.Apply(Img)
            s = TempPath & PictureID & "-" & x & "-crop.jpg"
            Img.SaveFile (s)
            Set Img = Nothing
            Call ShrinkEm(s, PictureID)
        Next x
    Case 9
        For x = 1 To 9
            Set Img = CreateObject("WIA.ImageFile")
            Img.LoadFile (BuiltPath) 'load the stored jpg in WIA
            Select Case x
                Case 1 'top left
                    IP.Filters(1).Properties("Left") = 0 'left edge
                    IP.Filters(1).Properties("Top") = 0 'top edge
                    IP.Filters(1).Properties("Right") = Img.Width * (0.66 - Overlap)
                    IP.Filters(1).Properties("Bottom") = Img.Height * (0.66 - Overlap)
                Case 2 'middle right
                    IP.Filters(1).Properties("Left") = Img.Width * (0.33 - Overlap / 2) 'go right one third of the width and left half the overlap
                    IP.Filters(1).Properties("Top") = 0 'top edge
                    IP.Filters(1).Properties("Right") = Img.Width * (0.33 - Overlap / 2) 'go left one third of the width and right half the overlap
                    IP.Filters(1).Properties("Bottom") = Img.Height * (0.66 - Overlap) 'come up two thirds of the way  and down the overlap
                Case 3 'top right
                    IP.Filters(1).Properties("Left") = Img.Width * (0.66 - Overlap)
                    IP.Filters(1).Properties("Top") = 0
                    IP.Filters(1).Properties("Right") = 0
                    IP.Filters(1).Properties("Bottom") = Img.Height * (0.66 - Overlap)
                Case 4
                    IP.Filters(1).Properties("Left") = 0 'left edge
                    IP.Filters(1).Properties("Top") = Img.Height * (0.33 - Overlap) 'come down one thirds of the way and up half the overlap
                    IP.Filters(1).Properties("Right") = Img.Width * (0.66 - Overlap)
                    IP.Filters(1).Properties("Bottom") = Img.Height * (0.33 - Overlap) 'come down one thirds of the way and up half the overlap
                Case 5
                    IP.Filters(1).Properties("Left") = Img.Width * (0.33 - Overlap / 2) 'go right one third of the width and left half the overlap
                    IP.Filters(1).Properties("Top") = Img.Height * (0.33 - Overlap) 'come down one thirds of the way and up half the overlap
                    IP.Filters(1).Properties("Right") = Img.Width * (0.33 - Overlap / 2) 'go left one third of the width and right half the overlap
                    IP.Filters(1).Properties("Bottom") = Img.Height * (0.33 - Overlap) 'come down one thirds of the way and up half the overlap
                Case 6
                    IP.Filters(1).Properties("Left") = Img.Width * (0.66 - Overlap)
                    IP.Filters(1).Properties("Top") = Img.Height * (0.33 - Overlap) 'come down one thirds of the way and up half the overlap
                    IP.Filters(1).Properties("Right") = 0
                    IP.Filters(1).Properties("Bottom") = Img.Height * (0.33 - Overlap) 'come down one thirds of the way and up half the overlap
                Case 7 'bottom left
                    IP.Filters(1).Properties("Left") = 0
                    IP.Filters(1).Properties("Top") = Img.Height * (0.66 - Overlap)
                    IP.Filters(1).Properties("Right") = Img.Width * (0.33 - Overlap)
                    IP.Filters(1).Properties("Bottom") = 0
                Case 8 'bottom middle
                    IP.Filters(1).Properties("Left") = Img.Width * (0.33 - Overlap / 2) 'go right one third of the width and left half the overlap
                    IP.Filters(1).Properties("Top") = Img.Height * (0.66 - Overlap)
                    IP.Filters(1).Properties("Right") = Img.Width * (0.33 - Overlap / 2) 'go left one third of the width and right half the overlap
                    IP.Filters(1).Properties("Bottom") = 0
                Case 9 'bottom right
                    IP.Filters(1).Properties("Left") = Img.Width * (0.66 - Overlap)
                    IP.Filters(1).Properties("Top") = Img.Height * (0.66 - Overlap)
                    IP.Filters(1).Properties("Right") = 0
                    IP.Filters(1).Properties("Bottom") = 0
                    
            End Select
            Set Img = IP.Apply(Img)
            s = TempPath & PictureID & "-" & x & "-crop.jpg"
            Img.SaveFile (s)
            Set Img = Nothing
            Call ShrinkEm(s, PictureID)
        Next x
    
    End Select
End Function

Private Sub ShrinkEm(PicPath As String, PictureID As Long)
Dim s As String
Dim BuiltPath As String
Dim TempPath As String
Dim x As Integer
Dim Img As WIA.ImageFile

Dim DesiredDPI As Integer
Dim DesiredWidth As Single
Dim Fragments As Integer
Dim Overlap As Single

Dim IP As ImageProcess
Set IP = CreateObject("WIA.ImageProcess")

Dim fs As Object 'our friend the filesystemobject
Set fs = CreateObject("Scripting.FileSystemObject")

IP.Filters.Add IP.FilterInfos("Scale").FilterID
'IP.Filters(1).Properties("MaximumWidth") = 1600 'you can hand code an exact size
'IP.Filters(1).Properties("MaximumHeight") = 1200 'you can hand code an exact size
           
'variables for a recordset in tblTempPictures which stores the path to the new images
Dim db As Database
Dim rs As Recordset
Dim rs1 As Recordset

Set db = CurrentDb
Set rs = db.OpenRecordset("SELECT * FROM [tbltempPics]", dbOpenDynaset, dbSeeChanges)

BuiltPath = PicPath 'rs!Path 'where the original is
TempPath = CurrentProject.Path & "\Resized\" ' a place to store dynamically generated images

'no longer needed, set as public variable in SplitEm
'DesiredDPI = Nz(Forms!frmOpenReports!txtDesiredDPI, 96) ' from the form

Set Img = CreateObject("WIA.ImageFile")
Img.LoadFile (BuiltPath) 'load the stored jpg in WIA

Set rs1 = db.OpenRecordset("SELECT * FROM [tblPictures] where PictureID = " & PictureID, dbOpenDynaset, dbSeeChanges)

DesiredDPI = rs1!DesiredDPI ' from the table
DesiredWidth = rs1!DesiredWidth
Fragments = rs1!Fragments
Overlap = rs1!Overlap

IP.Filters(1).Properties("MaximumWidth") = DesiredWidth * DesiredDPI '96 or whatever dpi * control width / twips per inch
IP.Filters(1).Properties("MaximumHeight") = DesiredWidth * DesiredDPI  '96 or whatever dpi * control height /twips per inch

'Dim up a WIA.property
Dim prpty As WIA.Property

'Add the second filter
IP.Filters.Add IP.FilterInfos("RotateFlip").FilterID

'and then set the rotation according to what it finds
For Each prpty In Img.Properties
     If prpty.PropertyID = 274 Then
         Select Case prpty.Value
             Case 1
                 IP.Filters(2).Properties("RotationAngle") = 0 'do nothing
             Case 3
                 IP.Filters(2).Properties("RotationAngle") = 180 'flip
             Case 6
                 IP.Filters(2).Properties("RotationAngle") = 90 'twist 90
             Case 8
                 IP.Filters(2).Properties("RotationAngle") = 270 'twist 270
         End Select
     End If
 Next

Set Img = IP.Apply(Img)
s = Left(PicPath, Len(PicPath) - 4) & "-small.jpg"
If fs.FileExists(s) = False Then
    Img.SaveFile (s)
End If

With rs
    .AddNew
    !OriginalPicID = PictureID
    !Path = s
    .Update
End With
Set Img = Nothing

End Sub

Open in new window


The subreport needs some code to resize the controls to our desired sizes and to set the path for the pictures. That code is here
Option Compare Database
Option Explicit

Private Sub Detail_Format(Cancel As Integer, FormatCount As Integer)
If FormatCount > 1 Then Exit Sub
Dim theHeight As Single
'ok, maybe we've got a non-standard shaped image
Dim IP As ImageProcess
Set IP = CreateObject("WIA.ImageProcess")
Set Img = CreateObject("WIA.ImageFile")
Img.LoadFile (Me.Path) 'load the stored jpg in WIA
'now, we now the desired width
Me.ImageFrame.Width = Me.DesiredWidth * 1440

'the desired height should be the existing width/height ratio of the image
'scaled to our desired control size
theHeight = Img.Height / Img.Width * Me.DesiredWidth * 1440
'make the detail section big enough to hold it
'and the existing control
Me.Detail.Height = theHeight + 100

Me.ImageFrame.Height = theHeight
Me.ImageFrame.Picture = Me.Path.Value
'suck any whitespace out
'note that trying for Me.Detail.Height = 0 will explode anything later than A2003
'That bug was report 7 years ago, and is still not fixed in Access 2013
Me.Detail.Height = 7
End Sub

Open in new window


That oughta do 'er.

Now, the caveats.

1.

The attached sample is NOT intended to be changed into production code.  I haven't built any error handling or validation code.

2.

The variables you put into the form are not checked for sanity.

3.

Overlap needs to be a fraction between 0 and .999999. Width is expected to be in inches -- and if you put something in wider that Access will accept, expect problems. The main one to watch is DPI. The farther beyond 96 DPI you go, the more problems you can expect.

4.

Access's limitations show up with 'the total amount of image futzing by Access itself' done. In testing, I found that Access would barf around the 8th or 9th fragment of the large image if I tried for 400 DPI.  300 DPI was a successful value. I've left it at 400 DPI for you to see.

5.

Much depends upon the horsepower of the machine.  My dual processor, quad-core Xeon server will render a report that will make an Atom or Core2Duo barf.  Your mileage may vary.
Using similar techniques, I have reports that print with 265 or more 1600 x 1200 @ 200 DPI images in 3" controls. The techniques demonstrated work for any version of Access from 2003 onward on Windows 7. If you can source and install wiaaut.dll and register it, they will work on WinXP as well. They may work for versions of Access prior to 2003, but that is untested. Win 8 variants are also untested.

I cannot get 1000 images to render. Where the upper limit is, I don't know -- yet. And I am working on techniques to get around even that upper limit. Stay tuned for another article if I am successful. You may decide that you'd prefer to split the images at the point of adding the records to the table, and forego doing that dynamically in the report. Your reports would render more quickly, but you'd lose the flexibility to change the DPI, overlap, width and fragments afterward. It's up to you to decide what works best.

In this sample, we have used WIA Scale, Crop, and FlipRotate filters to manipulate images that Access would not print on its own. We've used WIA Properties to display EXIF data, height, and width and used them to alter the orientation of images. Someone once said that using Access for this kind of work is like delivering shingles with a Prius. Nope. Access is a very capable pickup truck. Have the Resized folder open when opening the report. Watch how quickly the cropped and resized images get created. Nothing Prius-like about that! You can buy and pay for other, perhaps more capable tools -- but automating them to the degree that you can by using the WIA library and MS Access VBA to get your reports done would be very difficult indeed.

Nick67
BigImage.jpg
PrintIt.mdb
4
Comment
Author:Nick67
2 Comments
 
 

Administrative Comment

by:Eric AKA Netminder
Nick67,

Congratulations! Your article has been published, and has been selected as EE-Approved.

ericpete
Page Editor
0
 
LVL 47

Expert Comment

by:aikimark
I was looking forward to this article, Nick.  Very nice.  Thank you.
0

Featured Post

Ultimate Tool Kit for Technology Solution Provider

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy now.

Join & Write a Comment

Add bar graphs to Access queries using Unicode block characters. Graphs appear on every record in the color you want. Give life to numbers. Hopes this gives you ideas on visualizing your data in new ways ~ Create a calculated field in a query: …
A query can call a function, and a function can call Excel, even though we are in Access. This is Part 2, and steps you through the VBA that "wraps" Excel functionality so we can use its worksheet functions in Access. The declaration statement de…

Keep in touch with Experts Exchange

Tech news and trends delivered to your inbox every month