#!/usr/bin/env python # Export with MozJPEG v0.4 # (copyLEFT) 2015-2016 Andrey "Efenstor" Pivovarov. No rights reserved # Copy freely, modify freely, spread the word and remember me in your prayers # IMPORTANT!!! # ------------ # You must edit the "cjpeg_path" variable below to point it to your cjpeg # location. This plugin REQUIRES the "cjpeg" utility from the mozjpeg library! cjpeg_path = "/opt/mozjpeg/bin/cjpeg" # INSTALLATION # ------------ # Linux: # 1. cp export_mozjpeg.py ~/.gimp-2.8/plug-ins # 2. chmod +x export_mozjpeg.py # Windows: # 1. Remove Windows # 2. Install Linux # USAGE # ----- # Method 1 (preferred): # 1. File > Export As... # 2. Enter the output file name but specify .moz as extension instead of .jpg # 3. The resulting file will still be called .jpg # NOTE: if the outfile file already exists it is overwritten without warning! # Method 2: # 1. File > Export As... # 2. Open the "Select file type" list below # 3. Select "JPEG image (MozJPEG toolkit) # 4. On the "Extension mismatch" warning click "Save" # Method 3: # Rename/remove the original JPEG plugin (file-jpeg) # Linux: # 1. cd /usr/lib/gimp/2.0/plug-ins # 2. sudo mv file-jpeg .file-jpeg # Windows: # 1. Remove Windows # 2. Install Linux # NOTES ON PRE-PROCESSING # ----------------------- # Selective smoothing: Reduces file size at the cost of some tolerable image # quality degradation, sometimes also reducing perceptual blockiness. Values # of 0-50 are usually enough for the most cases. # Ringing reduction: Smoothens the image slightly, effectively suppressing # ringing at the cost of some sharpness loss. The value of 1 is quite enough # for the most cases. # HISTORY # ------- # v0.4 - Pre-processing options ('Selective smoothing' and 'Ringing reduction') # v0.31 - Disabled arithmetic coding by default as it may be incompatible with # browsers/viewers using libjpeg for JPEG decoding (yet it gives better # quality) # v0.3 - More options added and minor fixes # v0.2 - Added the DCT coding options # v0.1 - Initial release from gimpfu import * import os.path, tempfile, subprocess from array import array def mozjpeg(img, drawable, filename, raw_filename, ignored, quality, smooth, \ progressive, grayscale, dc_coding, dc_scan_opt, trellis_tune, \ quant_table, arithmetic, preproc1, preproc2): # Initialization gimp.progress_init("Saving "+raw_filename) # Prepare the temporary files s_tmpfile = tempfile.NamedTemporaryFile(suffix=".tga", delete=False) s_tmpfile_name = s_tmpfile.name s_tmpfile.close() # Pre-processing proc_img = pdb.gimp_image_duplicate(img) proc_drawable = proc_img.active_layer if(preproc1>0): radius = round((preproc1/100.0)*10.0) pdb.plug_in_sel_gauss(proc_img, proc_drawable, radius, preproc1) if(preproc2>0): pdb.plug_in_gauss(proc_img, proc_drawable, preproc2, preproc2, 0) # Save pdb.file_tga_save(proc_img, proc_drawable, s_tmpfile_name, os.path.basename \ (s_tmpfile_name), 0, 0) # Close the processed image gimp.delete(proc_img) # Change .moz extension to .jpg (if needed) last_dot = str.rfind(filename, ".") ext = filename[last_dot:] if(ext=='.moz'): filename = filename[:last_dot] + ".jpg" # Convert args = [] args.append(cjpeg_path) args.append('-quality'); args.append(str(int(quality))) if(smooth>0): args.append('-smooth'); args.append(str(int(smooth))) if(progressive==0): args.append('-baseline') if(grayscale==1): args.append('-grayscale') args.append('-dct') if(dc_coding==0): args.append('int') elif(dc_coding==1): args.append('fast') elif(dc_coding==2): args.append('float') args.append('-dc-scan-opt'); args.append(str(dc_scan_opt)) if(trellis_tune==0): args.append('-tune-psnr') elif(trellis_tune==1): args.append('-tune-hvs-psnr') elif(trellis_tune==2): args.append('-tune-ssim') elif(trellis_tune==3): args.append('-tune-ms-ssim') args.append('-quant-table'); args.append(str(quant_table)) if(arithmetic==1): args.append('-arithmetic') args.append('-outfile'); args.append(filename) args.append(s_tmpfile_name) subprocess.call( args ) # Delete the temporary file os.remove(s_tmpfile_name) # Exit pdb.gimp_progress_end() pdb.gimp_displays_flush() def register_save(): gimp.register_save_handler("file-mozjpeg-save", "jpg,jpeg,jpe,moz", "") register( "file-mozjpeg-save", "Save as JPEG using the MozJPEG toolkit", "", "Efenstor", "(copyLEFT) 2015 Andrey \"Efenstor\" Pivovarov", "2015", "/JPEG image (MozJPEG toolkit)", "RGB*, GRAY*", [ (PF_STRING, "unknown", "Undocumented (?) compulsory parameter, set to None", None), # NOTE: Is this some kind of undocumented behaviour? It seems that the 1st parameter (actually it's the 5th) # is COMPULSORY but ignored in the GUI and must be of the PF_STRING type (not sure about this). (PF_SLIDER, "quality", "_Quality", 80, (0, 100, 1)), (PF_SLIDER, "smooth", "_Smooth", 0, (0, 100, 1)), (PF_TOGGLE, "progressive", "_Progressive", 1), (PF_TOGGLE, "grayscale", "_Grayscale", 0), (PF_OPTION, "dc-coding", "Advanced: DCT _coding", 0, ("Integer (default)", "Fast", "Float")), (PF_OPTION, "dc-scan-opt", "Advanced: _DC scan optimization mode", 1, ("One scan for all components", "One scan per component (default)", "Optimized + one scan for the remaining components")), (PF_OPTION, "trellis-tune", "Advanced: _Trellis optimization tune", 1, ("PSNR", "PSNR-HVS (default)", "SSIM", "MS-SSIM")), (PF_OPTION, "quant-table", "Advanced: _Quantization table", 4, ("JPEG Annex K", "Flat", "Tuned for MS-SSIM", "ImageMagick by N. Robidoux (default)", "Tuned for PSNR-HVS", "Klein, Silverstein and Carney")), (PF_TOGGLE, "arithmetic", "Advanced: _Arithmetic coding (incompatible with libjpeg!)", 0), (PF_SLIDER, "preproc1", "Pre-processing: Selective s_moothing", 0, (0, 100, 1)), (PF_SLIDER, "preproc2", "Pre-processing: _Ringing reduction", 0, (0, 2, 1)) ], [], mozjpeg, on_query=register_save) main()