| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 | local gm = require 'graphicsmagick'local ffi = require 'ffi'local iproc = require 'iproc'local sRGB2014 = require 'sRGB2014'require 'pl'local image_loader = {}local clip_eps8 = (1.0 / 255.0) * 0.5 - (1.0e-7 * (1.0 / 255.0) * 0.5)local clip_eps16 = (1.0 / 65535.0) * 0.5 - (1.0e-7 * (1.0 / 65535.0) * 0.5)local background_color = 0.5function image_loader.encode_png(rgb, options)   options = options or {}   options.depth = options.depth or 8   if options.inplace == nil then      options.inplace = false   end   rgb = iproc.byte2float(rgb)   if options.depth < 16 then      if options.inplace then	 rgb:add(clip_eps8)      else	 rgb = rgb:clone():add(clip_eps8)      end      rgb:clamp(0.0, 1.0)      rgb = rgb:mul(255):floor():div(255)   else      if options.inplace then	 rgb:add(clip_eps16)      else	 rgb = rgb:clone():add(clip_eps16)      end      rgb:clamp(0.0, 1.0)      rgb = rgb:mul(65535):floor():div(65535)   end   local im   if rgb:size(1) == 4 then -- RGBA      im = gm.Image(rgb, "RGBA", "DHW")      if options.grayscale then	 im:type("GrayscaleMatte")      end   elseif rgb:size(1) == 3 then -- RGB      im = gm.Image(rgb, "RGB", "DHW")      if options.grayscale then	 im:type("Grayscale")      end   elseif rgb:size(1) == 1 then -- Y      im = gm.Image(rgb, "I", "DHW")      im:type("Grayscale")   end   if options.gamma then      im:gamma(options.gamma)   end   if options.icm and im.profile then      im:profile("icm", sRGB2014)      im:profile("icm", options.icm)   end   return im:depth(options.depth):format("PNG"):toString()endfunction image_loader.save_png(filename, rgb, options)   local blob = image_loader.encode_png(rgb, options)   local fp = io.open(filename, "wb")   if not fp then      error("IO error: " .. filename)   end   fp:write(blob)   fp:close()   return trueendfunction image_loader.decode_float(blob)   local load_image = function()      local meta = {}      local im = gm.Image()      local gamma_lcd = 0.454545            im:fromBlob(blob, #blob)      if im.profile then	 meta.icm = im:profile("icm")	 if meta.icm then	    im:profile("icm", sRGB2014)	    im:removeProfile()	 end      end      if im:colorspace() == "CMYK" then	 im:colorspace("RGB")      end      if gamma ~= 0 and math.floor(im:gamma() * 1000000) / 1000000 ~= gamma_lcd then	 meta.gamma = im:gamma()      end      local image_type = im:type()      if image_type == "Grayscale" or image_type == "GrayscaleMatte" then	 meta.grayscale = true      end      if image_type == "TrueColorMatte" or image_type == "GrayscaleMatte" then	 -- split alpha channel	 im = im:toTensor('float', 'RGBA', 'DHW')	 meta.alpha = im[4]:reshape(1, im:size(2), im:size(3))	 -- drop full transparent background	 local mask = torch.le(meta.alpha, 0.0)	 im[1][mask] = background_color	 im[2][mask] = background_color	 im[3][mask] = background_color	 local new_im = torch.FloatTensor(3, im:size(2), im:size(3))	 new_im[1]:copy(im[1])	 new_im[2]:copy(im[2])	 new_im[3]:copy(im[3])	 im = new_im      else	 im = im:toTensor('float', 'RGB', 'DHW')      end      meta.blob = blob      return {im, meta}   end   local state, ret = pcall(load_image)   if state then      return ret[1], ret[2]   else      return nil, nil   endendfunction image_loader.decode_byte(blob)   local im, meta   im, meta = image_loader.decode_float(blob)      if im then      im = iproc.float2byte(im)      -- hmm, alpha does not convert here      return im, meta   else      return nil, nil   endendfunction image_loader.load_float(file)   local fp = io.open(file, "rb")   if not fp then      error(file .. ": failed to load image")   end   local buff = fp:read("*all")   fp:close()   return image_loader.decode_float(buff)endfunction image_loader.load_byte(file)   local fp = io.open(file, "rb")   if not fp then      error(file .. ": failed to load image")   end   local buff = fp:read("*all")   fp:close()   return image_loader.decode_byte(buff)endlocal function test()   torch.setdefaulttensortype("torch.FloatTensor")   local a = image_loader.load_float("../images/lena.png")   local blob = image_loader.encode_png(a)   local b = image_loader.decode_float(blob)   assert((b - a):abs():sum() == 0)   a = image_loader.load_byte("../images/lena.png")   blob = image_loader.encode_png(a)   b = image_loader.decode_byte(blob)   assert((b:float() - a:float()):abs():sum() == 0)end--test()return image_loader
 |