7

There's a great article (Sitecore 8.2 - Convert disk media to database) on converting disk media to the database, but I'm trying to do the opposite, temporarily at least. I want to optimize images (using ImageMagick), but I need them out of the database first. I just need to get the blob in the database down to a file system as a recognizable jpg or png. I know how to replace the original media in the database with the optimized image. I'm running a few thousand images through the process, so SPE seems the only reasonable approach.

  • Another option would be to use Dianoga; but only if your concern is how the media is delivered to the client - it won't do anything for your database size. – Mark Cassidy Jul 27 '17 at 15:25
  • Perhaps the code that Dianoga uses to optimize the images could be leveraged to save the optimized bitmap blob back into the database? I'm thinking of a custom button in the content editor ribbon so this can be done as needed, but save or publish event processors may also be appropriate. – Nathan Hase Jul 27 '17 at 15:32
3

While I don't know that actually writing the media library to disk is a great idea (you'll want to look at Nathan Hase's suggestion), I wrote a script that will do what you're asking.

Basically, the crux is to use the MediaItem's method GetMediaStream(), and writing that stream to a file.

You'll want to tweak $fileRootPath to point to the directory where you want to store the files on disk (Sitecore will need write access to this directory), and $mediaLibraryRootPath to point to the area of the media library you want to write. It will write to the disk with the same directory structure as in Sitecore.

You may also want to modify Include-Item to tune which items get written. You could, for instance, only deal with items with the template name Jpeg, for instance.

$fileRootPath = "C:\\media"
$mediaLibraryRootPath = "master:\sitecore\media library"

Function Write-Item([Sitecore.Data.Items.Item]$item) {
    $mediaItem = New-Object Sitecore.Data.Items.MediaItem -ArgumentList $item
    $directory = $root + $item.Parent.Paths.FullPath.Replace("/sitecore/media library", "").Replace("/", "\\")
    $fileName =  $directory + "\\" + $item.Name + "." + $item["Extension"]
    [System.IO.Directory]::CreateDirectory($directory) > $null

    New-UsingBlock ($file = [System.IO.File]::Create($fileName)) {
        $mediaStream = $mediaItem.GetMediaStream()
        $mediaStream.CopyTo($file)
    }

    Write-Host "Wrote $fileName"
}

Function Include-Item([Sitecore.Data.Items.Item]$item) {
    return $_.TemplateName -ne "Media folder" -and $_.TemplateName -ne "Node"
}

Get-ChildItem -Recurse $mediaLibraryRootPath `
| Where-Object { Include-Item($_) } `
| ForEach-Object { Write-Item $_ }

Disclaimer: This worked for me, but I can't attest to the speed, particularly if you have a large media library. I'd recommend running it against a subset of the media library first. Be especially careful, as this could result in a large amount of disk space used. I also didn't implement any error checking in this proof of concept

  • That worked beautifully, although I still have a little work to do to complete my whole solution. Thanks for all the thoughtful and timely advice. The only snag I ran into was that the New-UsingBlock wasn't recognized as a valid command. I think my SPE is pretty up-to-date, so I don't know why that is. – Christopher Jones Aug 1 '17 at 22:10
  • From what I can tell, SPE changed New-UsingBlock to a cmdlet in version 4.0, so if you're using a version older than that, it probably wouldn't work (I tested against SPE 4.6 on 8.2 Update-2). Alternatively, you could change it to $file = [System.IO.File]::Create($fileName) and $file.Close() to avoid the using. – Matthew FitzGerald-Chamberlain Aug 1 '17 at 22:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.