Platforms to show: All Mac Windows Linux Cross-Platform
/Images/LCMS2/Convert image to sRGB JPEG
Required plugins for this example: MBS Images Plugin, MBS GraphicsMagick Plugin, MBS Util Plugin
You find this example project in your Plugins Download as a Xojo project file within the examples folder: /Images/LCMS2/Convert image to sRGB JPEG
This example is the version from Fri, 29th Jan 2015.
Project "Convert image to sRGB JPEG.xojo_binary_project"
Class App Inherits Application
Const kEditClear = "&Delete"
Const kFileQuit = "&Quit"
Const kFileQuitShortcut = ""
End Class
Class wConvertImage Inherits Window
Control pbConvertImage Inherits PushButton
ControlInstance pbConvertImage Inherits PushButton
EventHandler Sub Action()
dim openDlg as OpenDialog
dim saveDlg as New SaveAsDialog
dim inputFile, outputFile as FolderItem
openDlg = New OpenDialog
openDlg.InitialDirectory = SpecialFolder.Desktop
openDlg.Title = "Select an RGB or CMYK JPEG or TIFF file"
openDlg.MultiSelect = False
inputFile = openDlg.ShowModal
if inputFile = Nil then Return
if (inputFile.NameExtensionMBS <> "jpg") and (inputFile.NameExtensionMBS <> "jpeg") _
and (inputFile.NameExtensionMBS <> "tif") and (inputFile.NameExtensionMBS <> "tiff") then
MsgBox( "This method only works with JPEG or TIFF files." )
Return
end if
saveDlg.InitialDirectory = inputFile.Parent
saveDlg.Title = "Where do you want to save your sRGB JPEG?"
saveDlg.SuggestedFileName = "Output sRGB image.jpg"
outputFile = saveDlg.ShowModal
If outputFile = Nil then Return
generateRGBJPEG( inputFile, outputFile, 500 )
End EventHandler
End Control
Sub generateRGBJPEG(inputFile as FolderItem, outputFile as FolderItem, outputSize as Integer, Optional dontScaleUp as Boolean = False, Optional outputQuality as Integer = 60)
// inputFile must be a JPEG or TIFF image in either RGB or CMYK mode. Other modes (e.g. greyscale) are not handled.
// JPEGImporterMBS is used to read JPEG files, TiffPictureMBS is used to read TIFF files
// LCMS2 is used to convert the image to the sRGB colour space
// GMImageMBS is used to resize the image, and can be expanded to add borders, watermarks, etc
// JPEGExporterMBS is used to save the JPEG, discarding the ICC profile to reduce file size
dim sourceFormat as String
dim i, rowBytes, pictureWidth, pictureHeight as Integer
dim outputPicture as Picture
dim convertProfile, sourceCMYK as Boolean
dim rawPictureData, rawPictureRowData as MemoryBlock
dim jpegImporter as JPEGImporterMBS
dim jpegExporter as JPEGExporterMBS
dim tiffImporter as TiffPictureMBS
dim gmImage as GMImageMBS
dim ct as LCMS2TransformMBS
dim sourceProfile, outputProfile as LCMS2ProfileMBS
dim inputBitmap, outputBitmap as LCMS2BitmapMBS
if inputFile = Nil then Return
if not inputFile.Exists then Return
if outputFile = Nil then Return
convertProfile = True
outputProfile = LCMS2ProfileMBS.CreateSRGBProfile
if (inputFile.NameExtensionMBS = "jpeg") or (inputFile.NameExtensionMBS = "jpg") then
sourceFormat = "JPEG"
// Use jpegImporterMBS to read the image
jpegImporter = New JPEGImporterMBS
try
jpegImporter.YieldTicks = 1
jpegImporter.ReadMarkers = True
jpegImporter.ReadProfileData = True
jpegImporter.File = inputFile
jpegImporter.Import
catch err
if err isa OutOfMemoryException then
MsgBox( "Couldn't read image from JPEG because we ran out of memory: "+inputFile.Name )
Return
end if
end try
if jpegImporter.Picture = Nil then
MsgBox( "Couldn't read image from JPEG: "+inputFile.Name )
Return
end if
pictureWidth = jpegImporter.Width
pictureHeight = jpegImporter.Height
// Read the ICC profile from the image
sourceProfile = LCMS2ProfileMBS.OpenProfileFromMemory( jpegImporter.ProfileData )
sourceCMYK = ((jpegImporter.ColorSpace = jpegImporter.ColorSpaceCMYK) or (jpegImporter.ColorSpace = jpegImporter.ColorSpaceYCCK))
if sourceCMYK then
// We have to read the TIFF into a MemoryBlock so that we can convert it from CMYK to RGB later on
jpegImporter.Mode = jpegImporter.ModeRaw
jpegImporter.Import
rawPictureData = jpegImporter.PictureData
pictureWidth = jpegImporter.Width
pictureHeight = jpegImporter.Height
rawPictureData.InvertBytesMBS( 0, rawPictureData.size ) // Swap bytes
else // Assume that the image is RGB and pass it to GraphicsMagick
gmImage = New GMImageMBS( jpegImporter.Picture )
end if
elseif (inputFile.NameExtensionMBS = "tiff") or (inputFile.NameExtensionMBS = "tif") then
sourceFormat = "TIFF"
// Use TiffPictureMBS to read the image
try
tiffImporter = New TiffPictureMBS
tiffImporter.YieldTicks = 1
if not tiffImporter.Open( inputFile ) then
MsgBox( "Unable to open TIFF: "+inputFile.Name )
Return
end if
if not tiffImporter.ReadRGB then
MsgBox( "Unable to read TIFF: "+inputFile.Name )
Return
end if
pictureWidth = tiffImporter.Width
pictureHeight = tiffImporter.Height
// Read the ICC profile from the image
sourceProfile = LCMS2ProfileMBS.OpenProfileFromMemory( tiffImporter.GetColorProfile )
if tiffImporter.SamplesPerPixel = 4 then // It looks like we've got a CMYK image
sourceCMYK = True
// We have to read the TIFF into a MemoryBlock so that we can convert it from CMYK to RGB later on
rowBytes = tiffImporter.BytesPerRow
rawPictureData = New MemoryBlock( pictureHeight * rowBytes )
for i=0 to pictureHeight -1
rawPictureRowData = tiffImporter.Scanline( i )
rawPictureData.StringValue( i * rowBytes, rowBytes ) = rawPictureRowData
next
else // Assume that the image is RGB and pass it to GraphicsMagick
gmImage = new GMImageMBS( tiffImporter.Pict )
end if
catch err
if err isa OutOfMemoryException then
MsgBox( "Couldn't read image from TIFF because we ran out of memory: "+inputFile.Name )
Return
end if
end try
else
Return // Not a file extension that we can work with.
end if
if convertProfile and (sourceProfile <> Nil) then // Convert the image to sRGB
if sourceCMYK then // Use LCMS2 with a MemoryBlock to convert the image from CMYK to an RGB image in the sRGB colourspace
rowBytes = pictureWidth * 4
// Create CMYK input picture from the MemoryBlock
inputBitmap = New LCMS2BitmapMBS( pictureWidth, pictureHeight, LCMS2MBS.kcmsSigCMYKData, rowBytes, rawPictureData )
// Create RGB output image at same size
outputBitmap = New LCMS2BitmapMBS( pictureWidth, pictureHeight, LCMS2MBS.kcmsSigRgbData )
// Transform the CMYK image to RGB
ct = LCMS2TransformMBS.CreateTransform( sourceProfile, sourceProfile.FormatterForColorspace( 1 ), outputProfile, outputProfile.FormatterForColorspace( 1 ), LCMS2MBS.kINTENT_RELATIVE_COLORIMETRIC, 0 )
if ct.Transform( inputBitmap, outputBitmap ) then
gmImage = New GMImageMBS( outputBitmap.Picture )
outputBitmap = Nil
inputBitmap = Nil
else
MsgBox( "Unable to convert colour profile: "+inputFile.Name )
end if
else // Assume RGB, so a straightforward conversion to the sRGB colourspace
ct = LCMS2TransformMBS.CreateTransform( sourceProfile, sourceProfile.FormatterForColorspace(1, false), outputProfile, outputProfile.FormatterForColorspace(1, false), 1 ) // 1 = relative colorimetric intent
outputBitmap = New LCMS2BitmapMBS( gmImage.CopyPicture )
if ct.Transform( outputBitmap ) then
gmImage = New GMImageMBS( outputBitmap.Picture )
else
MsgBox( "Unable to convert colour profile: "+inputFile.Name )
end if
end if
end if
// Resize image
if (gmImage.Height > outputSize) or (gmImage.Width > outputSize) or (not dontScaleUp) then // If the image is larger than the target size, or we're happy to scale it up, scale it down or up to the target size
gmImage.Scale( New GMGeometryMBS( outputSize, outputSize ) )
end if
outputPicture = gmImage.CopyPicture
// Set up exporter
jpegExporter = New JPEGExporterMBS
jpegExporter.File = outputFile
jpegExporter.Picture = outputPicture
jpegExporter.Quality = outputQuality
jpegExporter.Export
End Sub
End Class
MenuBar MenuBar1
MenuItem FileMenu = "&File"
MenuItem FileQuit = "#App.kFileQuit"
MenuItem EditMenu = "&Edit"
MenuItem EditUndo = "&Undo"
MenuItem UntitledMenu1 = "-"
MenuItem EditCut = "Cu&t"
MenuItem EditCopy = "&Copy"
MenuItem EditPaste = "&Paste"
MenuItem EditClear = "#App.kEditClear"
MenuItem UntitledMenu0 = "-"
MenuItem EditSelectAll = "Select &All"
End MenuBar
End Project
See also:
The items on this page are in the following plugins: MBS Images Plugin.