Tuesday, December 13, 2011

Photos in Outlook and Sharepoint (thumbnailphoto)

After assisting with some issues related to outlook crashing due to users uploading their own photos via software that corrupted the images, I looked around to see some of the solutions available for uploading thumbnails.  I won't go into all of the details of what the thumbnailphoto attribute is used for, but generally in newer outlook versions it will show your userphoto in the emails that people receive.  Also it ties in with sharepoint and possibly some other products that I'm not very familiar with.  The AD attribute allows for 100kb of data by default, however Outlook wants a 10kb max image and I have read the recommendations for size is 96x96.  For the solutions that are available, most will just do an upload of the image and assume you sized it correctly already.  Some others come as exe files that do it all for you, some of which are programs you have to buy (even though they suck, and its easy to build your own), and others require .NET 4.0 for something that can be done in much lower versions, etc etc.  I didn't like too many of any of them, and from what I can see of user circulated information, one of the easiest solutions was using ldp.exe to upload the file to your own user object.  But in any case, I thought it would be nice to have a self service method of uploading your photo using the recommended image size and data size.  So I threw together this powershell (v1 compatible) script to handle this.  At the moment, I didn't feel like trying to wrap a GUI around all of this, but perhaps I'll do that in the future.  The inspiration for this code goes back to the Microsoft scripting games 2011 Advanced day 8 competition which involved striping EXIF data and resizing graphics files.  At the time, I didn't have enough time to figure out how to use the WIA com objects to handle this work, so for this script I have used some of the examples of other competitors as guidance for these methods.



#Add-ADPhoto   Powershell v1 compatibile script for updating
#user thumbnailphoto attribute.  Resizes input photo to recommended
#dimensions and size.  Only updates for the currently logged in user.
#This is a script for user self service.

$infile = $args[0]
$aspect = $args[1]

function usage {
    write-host "Usage: Add-ADPhoto filename [aspect]"
    write-host "   Provide the name of an image file in your current directory."
    write-host "   If you wish to preserve the aspect ratio of the image, type"
    write-host "   1 after your file name.  Images are resized to the recommended"
    write-host "   96x96, converted to JPG and set to 70% quality to limit size."
    exit 

}
$imagefile = (pwd).path + "\" + $infile
$imagefileout = (pwd).path + "\adout.jpg"

##############################################################################
#Check to see if the argument for filename was provided, and that it exists###
##############################################################################
if ([string]::isnullorempty($infile) -or -not (test-path $imagefile)) {
    &usage
}


###############################
#Remove any old converted file#
###############################
if (test-path $imagefileout) {
    del -path $imagefileout -ErrorAction "silentlycontinue"
}

$Image = New-Object -ComObject Wia.ImageFile
$ImageProcessor = New-Object -ComObject Wia.ImageProcess


##########################################################
#Try loading the file, if its not an image this will fail#
##########################################################
$Image.LoadFile($ImageFile)

if (-not $?) { &usage }


#############################################################
#Create filters, set aspect ratio setting, change dimensions#
#to max 96pixels, convert to JPG and set quality            #
#############################################################
$Scale = $ImageProcessor.FilterInfos.Item("Scale").FilterId
$ImageProcessor.Filters.Add($Scale)
$Qual = $ImageProcessor.FilterInfos.Item("Convert").FilterID
$ImageProcessor.Filters.Add($qual)

if ([string]::isnullorempty($aspect) -or [string]$aspect -ne "1") {
    $ImageProcessor.Filters.Item(1).Properties.Item("PreserveAspectRatio") = $false
} else {
    $ImageProcessor.Filters.Item(1).Properties.Item("PreserveAspectRatio") = $true
}

$ImageProcessor.Filters.Item(1).Properties.Item("MaximumHeight") = 96
$ImageProcessor.Filters.Item(1).Properties.Item("MaximumWidth") = 96
$ImageProcessor.Filters.Item(2).Properties.Item("FormatID") = "{B96B3CAE-0728-11D3-9D7B-0000F81EF32E}"

####################################################################
#Drop image quality until it meets the size recommendation of 10kb #
####################################################################
$quality = 80
do {
    Remove-Item -path $imagefileout -ErrorAction "silentlycontinue"
    $ImageProcessor.Filters.Item(2).Properties.Item("Quality") = $quality
    $Image = $ImageProcessor.Apply($Image)
    $Image.SaveFile($ImageFileOut)
    [byte[]]$imagedata = get-content $imagefileout -encoding byte
    $quality -= 10
} while ($imagedata.length -gt 10kb)


#####################################################################
#Find domain, and Account distinguished name.  Open user object, add#
#thumbnailphoto data and save.
#####################################################################
$de = new-object directoryservices.directoryentry("LDAP://" + $env:logonserver.substring(2))
$ds = new-object directoryservices.directorysearcher($de)
$ds.filter = "(&(objectclass=user)(samaccountname=" + $env:username + "))"
$myaccount = $ds.findone()
$de = new-object directoryservices.directoryentry($myaccount.path)
$de.properties["Thumbnailphoto"].clear()
$de.properties["Thumbnailphoto"].add($imagedata) |out-null
$de.setinfo()
Write-Host "Photo has been uploaded"

No comments:

Post a Comment