├── screenshots ├── ftjo-ss-jpo-2.0.0.1.png └── ftjo-ss-ppa-2.0.0.1.png ├── Info.lua ├── README.md ├── PluginInfoProvider.lua └── JPEGOptimizer.lua /screenshots/ftjo-ss-jpo-2.0.0.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ftischhauser/JPEGOptimizer/HEAD/screenshots/ftjo-ss-jpo-2.0.0.1.png -------------------------------------------------------------------------------- /screenshots/ftjo-ss-ppa-2.0.0.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ftischhauser/JPEGOptimizer/HEAD/screenshots/ftjo-ss-ppa-2.0.0.1.png -------------------------------------------------------------------------------- /Info.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Copyright (c) 2018 Flavio Tischhauser 3 | https://github.com/ftischhauser/JPEGOptimizer 4 | 5 | Permission is hereby granted, free of charge, to any person 6 | obtaining a copy of this software and associated documentation 7 | files (the "Software"), to deal in the Software without 8 | restriction, including without limitation the rights to use, 9 | copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 19 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 | OTHER DEALINGS IN THE SOFTWARE. 25 | --]] 26 | 27 | return { 28 | LrSdkVersion = 6.0, 29 | LrSdkMinimumVersion = 2.0, 30 | LrToolkitIdentifier = 'ftischhauser.JPEGOptimizer', 31 | LrPluginName = 'JPEG Optimizer', 32 | LrPluginInfoUrl = 'https://github.com/ftischhauser/JPEGOptimizer/', 33 | VERSION = { major=2, minor=0, revision=3, build=3}, 34 | LrPluginInfoProvider = 'PluginInfoProvider.lua', 35 | LrExportFilterProvider = { 36 | title = 'JPEG Optimizer', 37 | file = 'JPEGOptimizer.lua', 38 | id = 'JPEG Optimizer', 39 | supportsVideo = 'false' 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JPEG Optimizer Lightroom Plugin 2 | This Lightroom plugin combines the following awesome tools in a post-process action: 3 | * [exiv2](http://www.exiv2.org/) 4 | * [ImageMagick](https://www.imagemagick.org/) 5 | * [jpeg-archive](https://github.com/danielgtaylor/jpeg-archive/) 6 | * [mozjpeg](https://github.com/mozilla/mozjpeg/) 7 | 8 | It allows you to either losslessly squeeze out a few kilobytes from the JPEGs Lightroom generates, or it can take over the JPEG encoding completely and automatically set the optimal JPEG compression by measuring the perceived visual quality. 9 | 10 | ## Download 11 | You can download the latest release from [here](https://github.com/ftischhauser/JPEGOptimizer/releases). 12 | 13 | ## Installation 14 | * Extract the folder "JPEGOptimizer.lrplugin" from the ZIP file to "%APPDATA%\Adobe\Lightroom\Modules" or any other location. Go to File Menu / Plug-in Manager / Add and then browse the folder location and add the 'JPEGOptimizer.lrplugin' folder. 15 | * After that you should see a new post process action in the export dialog and the publish service settings: 16 | ![Post-Process Actions:](screenshots/ftjo-ss-ppa-2.0.0.1.png) 17 | * Select the action and click on insert: 18 | ![JPEG Optimizer](screenshots/ftjo-ss-jpo-2.0.0.1.png) 19 | 20 | ## Options 21 | 22 | ### Remove EXIF thumbnail 23 | Lightroom generates a small thumbnail that takes up 10-20kb space and is rarely used when publishing images on the web. However some desktop and mobile apps (like [FileBrowser](http://www.stratospherix.com/products/filebrowser/)) use them to quickly draw thumbnails without decoding the full images. 24 | 25 | ### Strip ALL metadata (including thumbnail) 26 | Completely removes all metadata from the image. Also handy if you want to share images anonymously. 27 | 28 | ### Progressive encoding 29 | Besides the different display behavior during the image download, progressive JPEGs are also smaller. The best lossless optimizations are achieved with this option enabled, but the files will require more CPU to decode and can cause rare compatibility issues. 30 | 31 | ### Recompress JPEG 32 | This option will switch to the external encoder [jpeg-archive](https://github.com/danielgtaylor/jpeg-archive/) and not use Lightroom for JPEG encoding anymore. As a result, the Lightroom File Settings (such as JPEG quality or file size limit) will be ingored. Instead it will force Lightroom to export a temporary TIFF file to prevent double-compression and achieve maximum quality. Keep the image format set to JPEG, the quality value will be ignored. 33 | 34 | #### Chroma subsampling 35 | Subsampling reduces the resolution of the color channels which is rarely noticeably by the human eye. The Lightroom encoder enables this for all quality settings below 54, jpeg-archive allows you to manually choose this for all quality levels. 36 | 37 | #### Quality 38 | Instead of a fixed bitrate setting, you have to choose a visual target quality. The encoder will then attempt multiple compression settings and evaluate the perceived visual quality (using one of the methods below). This will result in the smallest possible file that still looks great using a process very similar to [JPEGmini](http://www.jpegmini.com/). 39 | 40 | #### Method 41 | These are the different algorithms you can choose to do the image analysis. You can get more details from [jpeg-archive](https://github.com/danielgtaylor/jpeg-archive/), but I would generally recommend to use either SmallFry or SSIM. 42 | -------------------------------------------------------------------------------- /PluginInfoProvider.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Copyright (c) 2018 Flavio Tischhauser 3 | https://github.com/ftischhauser/JPEGOptimizer 4 | 5 | Permission is hereby granted, free of charge, to any person 6 | obtaining a copy of this software and associated documentation 7 | files (the "Software"), to deal in the Software without 8 | restriction, including without limitation the rights to use, 9 | copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 19 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 | OTHER DEALINGS IN THE SOFTWARE. 25 | --]] 26 | 27 | local LrHttp = import 'LrHttp' 28 | local LrColor = import 'LrColor' 29 | local LrView = import 'LrView' 30 | 31 | return { 32 | sectionsForTopOfDialog = function( viewFactory, propertyTable ) 33 | return { 34 | { 35 | title = 'Information', 36 | viewFactory:column { 37 | viewFactory:static_text {title = 'Author: Flavio Tischhauser '}, 38 | viewFactory:static_text {title = 'Contributors: Giles Winstanley (macOS support and other fixes)'}, 39 | viewFactory:spacer {height = 10}, 40 | viewFactory:static_text {title = 'This plugin ships with the following awesome tools:'}, 41 | viewFactory:row { 42 | viewFactory:static_text { 43 | title = 'exiv2:', 44 | width = LrView.share "FTJO_PIL_width" 45 | }, 46 | viewFactory:static_text { 47 | title = 'http://www.exiv2.org/', 48 | mouse_down = function() LrHttp.openUrlInBrowser('http://www.exiv2.org/') end, 49 | text_color = LrColor( 0, 0, 1 ) 50 | } 51 | }, 52 | viewFactory:row { 53 | viewFactory:static_text { 54 | title = 'ImageMagick:', 55 | width = LrView.share "FTJO_PIL_width" 56 | }, 57 | viewFactory:static_text { 58 | title = 'https://www.imagemagick.org/', 59 | mouse_down = function() LrHttp.openUrlInBrowser('https://www.imagemagick.org/') end, 60 | text_color = LrColor( 0, 0, 1 ) 61 | } 62 | }, 63 | viewFactory:row { 64 | viewFactory:static_text { 65 | title = 'jpeg-archive:', 66 | width = LrView.share "FTJO_PIL_width" 67 | }, 68 | viewFactory:static_text { 69 | title = 'https://github.com/danielgtaylor/jpeg-archive/', 70 | mouse_down = function() LrHttp.openUrlInBrowser('https://github.com/danielgtaylor/jpeg-archive/') end, 71 | text_color = LrColor( 0, 0, 1 ) 72 | } 73 | }, 74 | viewFactory:row { 75 | viewFactory:static_text { 76 | title = 'mozjpeg:', 77 | width = LrView.share "FTJO_PIL_width" 78 | }, 79 | viewFactory:static_text { 80 | title = 'https://github.com/mozilla/mozjpeg/', 81 | mouse_down = function() LrHttp.openUrlInBrowser('https://github.com/mozilla/mozjpeg/') end, 82 | text_color = LrColor( 0, 0, 1 ) 83 | } 84 | } 85 | } 86 | } 87 | } 88 | end 89 | } 90 | -------------------------------------------------------------------------------- /JPEGOptimizer.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Copyright (c) 2018 Flavio Tischhauser 3 | https://github.com/ftischhauser/JPEGOptimizer 4 | 5 | Permission is hereby granted, free of charge, to any person 6 | obtaining a copy of this software and associated documentation 7 | files (the "Software"), to deal in the Software without 8 | restriction, including without limitation the rights to use, 9 | copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 19 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 | OTHER DEALINGS IN THE SOFTWARE. 25 | --]] 26 | 27 | local LrView = import 'LrView' 28 | local LrPathUtils = import 'LrPathUtils' 29 | local LrTasks = import 'LrTasks' 30 | local LrHttp = import 'LrHttp' 31 | local LrColor = import 'LrColor' 32 | local LrDialogs = import 'LrDialogs' 33 | local LrFileUtils = import'LrFileUtils' 34 | local LrLogger = import 'LrLogger' 35 | 36 | local logger = LrLogger('JPEGOptimizer') 37 | logger:enable("print") 38 | 39 | quote4Win = function (cmd) 40 | if (WIN_ENV) then return '"' .. cmd .. '"' else return cmd end 41 | end 42 | 43 | outputToLog = function (msg) 44 | -- logger:trace(msg) -- Uncomment this line to enable logging 45 | end 46 | 47 | ObserveFTJO_RemovePreview = function (propertyTable) 48 | if(propertyTable.FTJO_RemovePreview) then propertyTable.FTJO_StripMetadata = false end 49 | end 50 | ObserveFTJO_StripMetadata = function (propertyTable) 51 | if(propertyTable.FTJO_StripMetadata) then propertyTable.FTJO_RemovePreview = false end 52 | end 53 | 54 | return { 55 | exportPresetFields = { 56 | {key = 'FTJO_RemovePreview', default = true}, 57 | {key = 'FTJO_StripMetadata', default = false}, 58 | {key = 'FTJO_Progressive', default = true}, 59 | {key = 'FTJO_Recompress', default = false}, 60 | {key = 'FTJO_JRCQuality', default = 'medium'}, 61 | {key = 'FTJO_JRCMethod', default = 'smallfry'}, 62 | {key = 'FTJO_JRCSubsampling', default = true} 63 | }, 64 | sectionForFilterInDialog = function(viewFactory, propertyTable) 65 | propertyTable:addObserver('FTJO_RemovePreview', ObserveFTJO_RemovePreview) 66 | propertyTable:addObserver('FTJO_StripMetadata', ObserveFTJO_StripMetadata) 67 | return { 68 | title = 'JPEG Optimizer', 69 | viewFactory:column { 70 | spacing = viewFactory:control_spacing(), 71 | viewFactory:column { 72 | viewFactory:static_text {title = 'Please visit the homepage for help with these options:'}, 73 | viewFactory:static_text { 74 | title = 'http://github.com/ftischhauser/JPEGOptimizer', 75 | mouse_down = function() LrHttp.openUrlInBrowser('http://github.com/ftischhauser/JPEGOptimizer') end, 76 | text_color = LrColor( 0, 0, 1 ) 77 | }, 78 | viewFactory:spacer {height = 10}, 79 | viewFactory:group_box { 80 | title = 'Lossless Optimizations', 81 | viewFactory:checkbox { 82 | title = 'Remove EXIF thumbnail', 83 | value = LrView.bind 'FTJO_RemovePreview', 84 | checked_value = true, 85 | unchecked_value = false 86 | }, 87 | viewFactory:checkbox { 88 | title = 'Strip ALL metadata (including thumbnail)', 89 | value = LrView.bind 'FTJO_StripMetadata', 90 | checked_value = true, 91 | unchecked_value = false 92 | }, 93 | viewFactory:checkbox { 94 | title = 'Progressive encoding (smaller)', 95 | value = LrView.bind 'FTJO_Progressive', 96 | checked_value = true, 97 | unchecked_value = false 98 | }, 99 | viewFactory:column { 100 | viewFactory:static_text { 101 | title = 'Powered by mozjpeg and exiv2:' 102 | }, 103 | viewFactory:static_text { 104 | title = 'https://github.com/mozilla/mozjpeg/', 105 | mouse_down = function() LrHttp.openUrlInBrowser('https://github.com/mozilla/mozjpeg/') end, 106 | text_color = LrColor( 0, 0, 1 ) 107 | }, 108 | viewFactory:static_text { 109 | title = 'http://www.exiv2.org/', 110 | mouse_down = function() LrHttp.openUrlInBrowser('http://www.exiv2.org/') end, 111 | text_color = LrColor( 0, 0, 1 ) 112 | } 113 | } 114 | }, 115 | viewFactory:group_box { 116 | title = 'Recompression', 117 | viewFactory:checkbox { 118 | title = 'Recompress JPEG', 119 | value = LrView.bind 'FTJO_Recompress', 120 | checked_value = true, 121 | unchecked_value = false, 122 | }, 123 | viewFactory:static_text { 124 | enabled = LrView.bind 'FTJO_Recompress', 125 | title = "Automatically sets the optimal JPEG compression by measuring the perceived visual quality." 126 | }, 127 | viewFactory:checkbox { 128 | enabled = LrView.bind 'FTJO_Recompress', 129 | title = 'Chroma subsampling (smaller)', 130 | value = LrView.bind 'FTJO_JRCSubsampling', 131 | checked_value = true, 132 | unchecked_value = false, 133 | }, 134 | viewFactory:row { 135 | viewFactory:static_text { 136 | enabled = LrView.bind 'FTJO_Recompress', 137 | title = "Quality:", 138 | width = LrView.share "FTJO_Recompress_label_width", 139 | }, 140 | viewFactory:popup_menu { 141 | enabled = LrView.bind 'FTJO_Recompress', 142 | value = LrView.bind 'FTJO_JRCQuality', 143 | width = LrView.share "FTJO_Recompress_popup_width", 144 | items = { 145 | { title = "Low", value = 'low'}, 146 | { title = "Medium", value = 'medium'}, 147 | { title = "High", value = 'high'}, 148 | { title = "Very High", value = 'veryhigh'} 149 | } 150 | } 151 | }, 152 | viewFactory:row { 153 | viewFactory:static_text { 154 | enabled = LrView.bind 'FTJO_Recompress', 155 | title = "Method:", 156 | width = LrView.share "FTJO_Recompress_label_width", 157 | }, 158 | viewFactory:popup_menu { 159 | enabled = LrView.bind 'FTJO_Recompress', 160 | value = LrView.bind 'FTJO_JRCMethod', 161 | width = LrView.share "FTJO_Recompress_popup_width", 162 | items = { 163 | { title = "MPE", value = 'mpe'}, 164 | { title = "SSIM", value = 'ssim'}, 165 | { title = "MS-SSIM", value = 'ms-ssim'}, 166 | { title = "SmallFry", value = 'smallfry'} 167 | } 168 | } 169 | }, 170 | viewFactory:column { 171 | viewFactory:static_text { 172 | title = 'Powered by jpeg-archive and ImageMagick:', 173 | enabled = LrView.bind 'FTJO_Recompress', 174 | }, 175 | viewFactory:static_text { 176 | enabled = LrView.bind 'FTJO_Recompress', 177 | title = 'https://github.com/danielgtaylor/jpeg-archive/', 178 | mouse_down = function() LrHttp.openUrlInBrowser('https://github.com/danielgtaylor/jpeg-archive/') end, 179 | text_color = LrColor( 0, 0, 1 ) 180 | }, 181 | viewFactory:static_text { 182 | enabled = LrView.bind 'FTJO_Recompress', 183 | title = 'https://www.imagemagick.org/', 184 | mouse_down = function() LrHttp.openUrlInBrowser('https://www.imagemagick.org/') end, 185 | text_color = LrColor( 0, 0, 1 ) 186 | } 187 | } 188 | } 189 | } 190 | } 191 | } 192 | end, 193 | postProcessRenderedPhotos = function(functionContext, filterContext) 194 | 195 | -- Define paths for external tools 196 | local UPexiv2 = 'exiv2' 197 | local UPImageMagick = 'ImageMagick' 198 | local UPjpegrecompress = 'jpeg-archive' 199 | local UPjpegtran = 'mozjpeg' 200 | -- Define executable names for external tools 201 | local UEexiv2 = 'exiv2' .. (WIN_ENV and '.exe' or '') 202 | local UEImageMagick = MAC_ENV and 'convert' or 'magick.exe' 203 | local UEjpegrecompress = 'jpeg-recompress' .. (WIN_ENV and '.exe' or '') 204 | local UEjpegtran = 'jpegtran' .. (WIN_ENV and '.exe' or '') 205 | -- Define platform-specific path for external tools 206 | local PlatPath = MAC_ENV and 'macOS' or 'WIN' 207 | -- Construct commands for external tools (reusing path variables) 208 | if MAC_ENV then 209 | local ExivPath = LrPathUtils.child(LrPathUtils.child(_PLUGIN.path, PlatPath), UPexiv2) 210 | UPexiv2 = 'LD_LIBRARY_PATH="' .. ExivPath .. '" "' .. LrPathUtils.child(ExivPath, UEexiv2) .. '"' 211 | else 212 | UPexiv2 = '"' .. LrPathUtils.child(LrPathUtils.child(LrPathUtils.child(_PLUGIN.path, PlatPath), UPexiv2), UEexiv2) .. '"' 213 | end 214 | UPImageMagick = '"' .. LrPathUtils.child(LrPathUtils.child(LrPathUtils.child(_PLUGIN.path, PlatPath), UPImageMagick), UEImageMagick) .. '"' 215 | UPjpegrecompress = '"' .. LrPathUtils.child(LrPathUtils.child(LrPathUtils.child(_PLUGIN.path, PlatPath), UPjpegrecompress), UEjpegrecompress) .. '"' 216 | UPjpegtran = '"' .. LrPathUtils.child(LrPathUtils.child(LrPathUtils.child(_PLUGIN.path, PlatPath), UPjpegtran), UEjpegtran) .. '"' 217 | 218 | local renditionOptions = { 219 | filterSettings = function( renditionToSatisfy, exportSettings ) 220 | if filterContext.propertyTable.FTJO_Recompress then 221 | exportSettings.LR_format = 'TIFF' 222 | exportSettings.LR_export_colorSpace = 'sRGB' 223 | exportSettings.LR_export_bitDepth = '8' 224 | exportSettings.LRtiff_compressionMethod = 'compressionMethod_None' 225 | end 226 | end, 227 | } 228 | 229 | for sourceRendition, renditionToSatisfy in filterContext:renditions(renditionOptions) do 230 | local success, pathOrMessage = sourceRendition:waitForRender() 231 | if success then 232 | if filterContext.propertyTable.LR_format ~= 'JPEG' and not filterContext.propertyTable.FTJO_Recompress then 233 | renditionToSatisfy:renditionIsDone(false, 'Lossless optimizations only work on JPEG files. Please check the image format settings or activate recompression.') 234 | break 235 | end 236 | 237 | local ExpFileName = LrPathUtils.standardizePath(pathOrMessage) 238 | if filterContext.propertyTable.FTJO_Recompress then 239 | if not filterContext.propertyTable.FTJO_StripMetadata then 240 | local CmdDumpMetadata = UPexiv2 .. ' -q -f -eX "' .. ExpFileName .. '"' 241 | outputToLog('Dump metadata: ' .. CmdDumpMetadata) 242 | if LrTasks.execute(quote4Win(CmdDumpMetadata)) ~= 0 then renditionToSatisfy:renditionIsDone(false, 'Error exporting XMP data.') end 243 | if not filterContext.propertyTable.FTJO_RemovePreview then 244 | local CmdRenderPreview = UPImageMagick .. ' "' .. ExpFileName .. '" -resize 256x256 ppm:- | ' .. UPjpegrecompress .. ' --quiet --no-progressive --method smallfry --quality low --strip --ppm - "' .. LrPathUtils.removeExtension(ExpFileName) .. '-thumb.jpg"' 245 | outputToLog('Render preview: ' .. CmdRenderPreview) 246 | if LrTasks.execute(quote4Win(CmdRenderPreview)) ~= 0 then renditionToSatisfy:renditionIsDone(false, 'Error creating EXIF thumbnail.') end 247 | end 248 | end 249 | local CmdRecompress = UPImageMagick .. ' "' .. ExpFileName .. '" ppm:- | ' .. UPjpegrecompress .. ' --quiet --accurate --method ' .. filterContext.propertyTable.FTJO_JRCMethod .. ' --quality ' .. filterContext.propertyTable.FTJO_JRCQuality .. ' --strip' 250 | if not filterContext.propertyTable.FTJO_Progressive then CmdRecompress = CmdRecompress .. ' --no-progressive' end 251 | if not filterContext.propertyTable.FTJO_JRCSubsampling then CmdRecompress = CmdRecompress .. ' --subsample disable' end 252 | CmdRecompress = CmdRecompress .. ' --ppm - "' .. ExpFileName .. '"' 253 | outputToLog('Recompress: ' .. CmdRecompress) 254 | if LrTasks.execute(quote4Win(CmdRecompress)) ~= 0 then renditionToSatisfy:renditionIsDone(false, 'Error recompressing JPEG file.') end 255 | if not filterContext.propertyTable.FTJO_StripMetadata then 256 | local CmdInsertMetadata = UPexiv2 .. ' -q -f -iX "' .. ExpFileName .. '"' .. (MAC_ENV and ' 2>/dev/null' or ' 2>nul') 257 | outputToLog('Insert metadata: ' .. CmdInsertMetadata) 258 | if LrTasks.execute(quote4Win(CmdInsertMetadata)) ~= 0 then renditionToSatisfy:renditionIsDone(false, 'Error importing XMP data.') end 259 | LrFileUtils.delete(LrPathUtils.replaceExtension(ExpFileName, 'xmp')) 260 | if not filterContext.propertyTable.FTJO_RemovePreview then 261 | local CmdInsertPreview = UPexiv2 .. ' -q -f -it "' .. ExpFileName .. '"' 262 | outputToLog('Insert preview: ' .. CmdInsertPreview) 263 | if LrTasks.execute(quote4Win(CmdInsertPreview)) ~= 0 then renditionToSatisfy:renditionIsDone(false, 'Error importing EXIF thumbnail.') end 264 | LrFileUtils.delete(LrPathUtils.removeExtension(ExpFileName) ..'-thumb.jpg') 265 | end 266 | end 267 | else 268 | if filterContext.propertyTable.FTJO_RemovePreview and not filterContext.propertyTable.FTJO_StripMetadata then 269 | local CmdRemovePreview = UPexiv2 .. ' -q -f -dt "' .. ExpFileName .. '"' 270 | outputToLog('Remove preview: ' .. CmdRemovePreview) 271 | if LrTasks.execute(quote4Win(CmdRemovePreview)) ~= 0 then renditionToSatisfy:renditionIsDone(false, 'Error removing EXIF thumbnail.') end 272 | end 273 | local CmdOptimize = filterContext.propertyTable.FTJO_StripMetadata and UPjpegtran .. ' -copy none' or UPjpegtran .. ' -copy all' 274 | if not filterContext.propertyTable.FTJO_Progressive then CmdOptimize = CmdOptimize .. ' -revert -optimize' end 275 | CmdOptimize = CmdOptimize .. ' -outfile "' .. ExpFileName .. '" "' .. ExpFileName .. '"' 276 | outputToLog('Optimize: ' .. CmdOptimize) 277 | if LrTasks.execute(quote4Win(CmdOptimize)) ~= 0 then renditionToSatisfy:renditionIsDone(false, 'Error optimizing JPEG file.') end 278 | end 279 | else 280 | renditionToSatisfy:renditionIsDone(false, pathOrMessage) 281 | end 282 | end 283 | end 284 | } 285 | --------------------------------------------------------------------------------