private void SaveHelper(TextureFormat format, byte[] rawBytes, int texwidth, int texheight, bool convertTo16,
                            ChannelsPerMap exportChannels, string imagePath, FREE_IMAGE_FORMAT destFormat, FREE_IMAGE_SAVE_FLAGS saveFlags)
    {
        int             bytesPerPixel = 4;
        FREE_IMAGE_TYPE imageType     = FREE_IMAGE_TYPE.FIT_BITMAP;

        switch (format)
        {
        case TextureFormat.RGBAHalf:
            imageType     = FREE_IMAGE_TYPE.FIT_RGBA16;
            bytesPerPixel = 8;
            break;

        case TextureFormat.RGBAFloat:
            imageType     = FREE_IMAGE_TYPE.FIT_RGBAF;
            bytesPerPixel = 16;
            break;

        case TextureFormat.ARGB32:
            imageType     = FREE_IMAGE_TYPE.FIT_BITMAP;
            bytesPerPixel = 4;
            //tex.GetPixels32();
            //ConvertBGRAtoARGBScanline(dib);
            // convert back to ARGB
            if (FreeImage.IsLittleEndian())
            {
                for (int j = 0; j < rawBytes.Length; j += 4)
                {
                    // convert BGRA to ARGB
                    var a = rawBytes[j];
                    var r = rawBytes[j + 1];
                    rawBytes[j]     = rawBytes[j + 3];
                    rawBytes[j + 1] = rawBytes[j + 2];
                    rawBytes[j + 2] = r;
                    rawBytes[j + 3] = a;
                }
            }
            break;

        case TextureFormat.RGB24:
            imageType     = FREE_IMAGE_TYPE.FIT_BITMAP;
            bytesPerPixel = 3;
            if (FreeImage.IsLittleEndian())
            {
                // convert back to RGB
                for (int i = 0; i < rawBytes.Length; i += 3)
                {
                    // convert BGR to RGB
                    var r = rawBytes[i];
                    rawBytes[i]     = rawBytes[i + 2];
                    rawBytes[i + 2] = r;
                }
            }
            break;
        }



        FIBITMAP dib = FreeImage.ConvertFromRawBits(rawBytes, imageType, texwidth, texheight, texwidth * bytesPerPixel, (uint)bytesPerPixel * 8, 0, 0, 0, false);

        if (dib.IsNull)
        {
            Debug.LogError("Dib is NULL!!!");
        }
        rawBytes = null;
        GC.Collect();
        if (convertTo16)
        {
            dib    = FreeImage.ConvertToType(dib, FREE_IMAGE_TYPE.FIT_RGBA16, false);
            format = TextureFormat.RGBAHalf;
        }

        switch (exportChannels)
        {
        case ChannelsPerMap.RGB:
            // remove alpha channel
            switch (format)
            {
            case TextureFormat.RGBAFloat:
                dib = FreeImage.ConvertToRGBF(dib);
                break;

            case TextureFormat.RGBAHalf:
                dib = FreeImage.ConvertToType(dib, FREE_IMAGE_TYPE.FIT_RGB16, false);
                break;

            case TextureFormat.ARGB32:
                dib = FreeImage.ConvertTo24Bits(dib);
                break;
            }
            break;

        case ChannelsPerMap.R:
            dib = FreeImage.GetChannel(dib, FREE_IMAGE_COLOR_CHANNEL.FICC_RED);
            break;

        // if already RGBA don't need to do any conversion
        default:
            break;
        }

        try
        {
            using (FileStream saveStream = new FileStream(imagePath, FileMode.OpenOrCreate, FileAccess.Write))
            {
                Debug.Log("FreeImage::FileSaveSuccess: " + imagePath + " :" + FreeImage.SaveToStream(ref dib, saveStream, destFormat, saveFlags, true));
            }
        }
        catch (Exception e)
        {
            Debug.LogException(e);
            //progressBar.DoneProgress();
            FreeImage.UnloadEx(ref dib);
            throw;
        }
        //if (progressBar != null)
        //{
        //    UnityThreadHelper.Dispatcher.Dispatch(() =>
        //    {
        //        progressBar.Increment();
        //    });
        //}
    }