在不将 cmyk 转换为 rgb 的情况下将位图 (rgb) 与 TIFF (cmyk) 连接起来
Concatenate a bitmap (rgb) with a TIFF (cmyk) without converting cmyk to rgb
我正在开发一个应用程序,用于将 RGB 格式的位图图像与 CMYK 格式的 TIFF 图像连接起来。
我试过 System.Drawing 和 System.Windows.Media 命名空间。
问题是两个库都试图在合并之前将我的 TIFF 图像转换为 RGB,这 导致图像质量下降 。
据我了解,他们总是在处理之前将图像转换为 RGB 的原因是因为这两个库以渲染意图进行转换。
我不需要渲染任何东西,只需将两张照片合并并保存到磁盘,就这样。
我应该怎么做才能实现我的目标?显然,我不想失去 TIFF 的质量,所以我认为最好不要进行任何转换,保持原始状态并进行合并。无论如何,这只是一个猜测,也可以考虑其他选择。有人可以阐明我的情况吗?
查看下面的 tiff 图像从 cmyk 转换为 rgb 前后的比较。
我不知道 TIFF 格式可以同时拥有两个不同的色彩空间。由于您处理的是 CMYK,我认为这就是您要保留的那个。
如果是这样,这样做的步骤是:
- 加载 CMYK 图像 A(使用
BitmapDecoder
)
- 加载 RGB 图像 B(使用
BitmapDecoder
)
- 将图像 B 转换为具有所需颜色配置文件的 CMYK(使用
FormatConvertedBitmap
)
- 如果需要,请确保图像 B 的像素格式与 A 匹配(使用
FormatConvertedBitmap
)
- 将两者在内存中合成为一个字节数组(使用
CopyPixels
,然后内存操作,然后从内存中获取新的位图)
- 将合成保存到新的 CMYK TIFF 文件(使用
TiffBitmapEncoder
)
WIC (System.Media) 应该可以实现。
这样做的一个例子 (github) 可以写成:
BitmapFrame LoadTiff(string filename)
{
using (var rs = File.OpenRead(filename))
{
return BitmapDecoder.Create(rs, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad).Frames[0];
}
}
// Load, validate A
var imageA = LoadTiff("CMYK.tif");
if (imageA.Format != PixelFormats.Cmyk32)
{
throw new InvalidOperationException("imageA is not CMYK");
}
// Load, validate, convert B
var imageB = LoadTiff("RGB.tif");
if (imageB.PixelHeight != imageA.PixelHeight)
{
throw new InvalidOperationException("Image B is not the same height as image A");
}
var imageBCmyk = new FormatConvertedBitmap(imageB, imageA.Format, null, 0d);
// Merge
int width = imageA.PixelWidth + imageB.PixelWidth,
height = imageA.PixelHeight,
bytesPerPixel = imageA.Format.BitsPerPixel / 8,
stride = width * bytesPerPixel;
var buffer = new byte[stride * height];
imageA.CopyPixels(buffer, stride, 0);
imageBCmyk.CopyPixels(buffer, stride, imageA.PixelWidth * bytesPerPixel);
var result = BitmapSource.Create(width, height, imageA.DpiX, imageA.DpiY, imageA.Format, null, buffer, stride);
// save to new file
using (var ws = File.Create("out.tif"))
{
var tiffEncoder = new TiffBitmapEncoder();
tiffEncoder.Frames.Add(BitmapFrame.Create(result));
tiffEncoder.Save(ws);
}
保持 CMYK 图像的颜色准确性,并使用系统颜色配置文件转换 RGB。这可以在 Photoshop 中得到验证,它表明每个字母和深黑色都保持了它们的原始值。 (请注意,imgur 确实会转换为带有可疑颜色处理的 png - check github for originals。)
图片A(CMYK):
图片 B (RGB):
结果(CMYK):
要叠加两张图片,一张图片必须具有某种透明度概念。遮罩就是其中的一个例子,您可以在其中选择特定的颜色值来表示“透明”。蒙版的缺点是蒙版不能很好地处理混叠的源图像。为此,您可能想要做一个 alpha 通道 - 但跨颜色空间混合将具有挑战性。 (Github)
// Load, validate A
var imageA = LoadTiff("CMYK.tif");
if (imageA.Format != PixelFormats.Cmyk32)
{
throw new InvalidOperationException("imageA is not CMYK");
}
// Load, validate, convert B
var imageB = LoadTiff("RGBOverlay.tif");
if (imageB.PixelHeight != imageA.PixelHeight
|| imageB.PixelWidth != imageA.PixelWidth)
{
throw new InvalidOperationException("Image B is not the same size as image A");
}
var imageBBGRA = new FormatConvertedBitmap(imageB, PixelFormats.Bgra32, null, 0d);
var imageBCmyk = new FormatConvertedBitmap(imageB, imageA.Format, null, 0d);
// Merge
int width = imageA.PixelWidth, height = imageA.PixelHeight;
var stride = width * (imageA.Format.BitsPerPixel / 8);
var bufferA = new uint[width * height];
var bufferB = new uint[width * height];
var maskBuffer = new uint[width * height];
imageA.CopyPixels(bufferA, stride, 0);
imageBBGRA.CopyPixels(maskBuffer, stride, 0);
imageBCmyk.CopyPixels(bufferB, stride, 0);
for (int i = 0; i < bufferA.Length; i++)
{
// set pixel in bufferA to the value from bufferB if mask is not white
if (maskBuffer[i] != 0xffffffff)
{
bufferA[i] = bufferB[i];
}
}
var result = BitmapSource.Create(width, height, imageA.DpiX, imageA.DpiY, imageA.Format, null, bufferA, stride);
// save to new file
using (var ws = File.Create("out_overlay.tif"))
{
var tiffEncoder = new TiffBitmapEncoder();
tiffEncoder.Frames.Add(BitmapFrame.Create(result));
tiffEncoder.Save(ws);
}
示例图片 B:
示例输出:
我正在开发一个应用程序,用于将 RGB 格式的位图图像与 CMYK 格式的 TIFF 图像连接起来。 我试过 System.Drawing 和 System.Windows.Media 命名空间。
问题是两个库都试图在合并之前将我的 TIFF 图像转换为 RGB,这 导致图像质量下降 。
据我了解,他们总是在处理之前将图像转换为 RGB 的原因是因为这两个库以渲染意图进行转换。
我不需要渲染任何东西,只需将两张照片合并并保存到磁盘,就这样。
我应该怎么做才能实现我的目标?显然,我不想失去 TIFF 的质量,所以我认为最好不要进行任何转换,保持原始状态并进行合并。无论如何,这只是一个猜测,也可以考虑其他选择。有人可以阐明我的情况吗?
查看下面的 tiff 图像从 cmyk 转换为 rgb 前后的比较。
我不知道 TIFF 格式可以同时拥有两个不同的色彩空间。由于您处理的是 CMYK,我认为这就是您要保留的那个。
如果是这样,这样做的步骤是:
- 加载 CMYK 图像 A(使用
BitmapDecoder
) - 加载 RGB 图像 B(使用
BitmapDecoder
) - 将图像 B 转换为具有所需颜色配置文件的 CMYK(使用
FormatConvertedBitmap
) - 如果需要,请确保图像 B 的像素格式与 A 匹配(使用
FormatConvertedBitmap
) - 将两者在内存中合成为一个字节数组(使用
CopyPixels
,然后内存操作,然后从内存中获取新的位图) - 将合成保存到新的 CMYK TIFF 文件(使用
TiffBitmapEncoder
)
WIC (System.Media) 应该可以实现。
这样做的一个例子 (github) 可以写成:
BitmapFrame LoadTiff(string filename)
{
using (var rs = File.OpenRead(filename))
{
return BitmapDecoder.Create(rs, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad).Frames[0];
}
}
// Load, validate A
var imageA = LoadTiff("CMYK.tif");
if (imageA.Format != PixelFormats.Cmyk32)
{
throw new InvalidOperationException("imageA is not CMYK");
}
// Load, validate, convert B
var imageB = LoadTiff("RGB.tif");
if (imageB.PixelHeight != imageA.PixelHeight)
{
throw new InvalidOperationException("Image B is not the same height as image A");
}
var imageBCmyk = new FormatConvertedBitmap(imageB, imageA.Format, null, 0d);
// Merge
int width = imageA.PixelWidth + imageB.PixelWidth,
height = imageA.PixelHeight,
bytesPerPixel = imageA.Format.BitsPerPixel / 8,
stride = width * bytesPerPixel;
var buffer = new byte[stride * height];
imageA.CopyPixels(buffer, stride, 0);
imageBCmyk.CopyPixels(buffer, stride, imageA.PixelWidth * bytesPerPixel);
var result = BitmapSource.Create(width, height, imageA.DpiX, imageA.DpiY, imageA.Format, null, buffer, stride);
// save to new file
using (var ws = File.Create("out.tif"))
{
var tiffEncoder = new TiffBitmapEncoder();
tiffEncoder.Frames.Add(BitmapFrame.Create(result));
tiffEncoder.Save(ws);
}
保持 CMYK 图像的颜色准确性,并使用系统颜色配置文件转换 RGB。这可以在 Photoshop 中得到验证,它表明每个字母和深黑色都保持了它们的原始值。 (请注意,imgur 确实会转换为带有可疑颜色处理的 png - check github for originals。)
图片A(CMYK):
图片 B (RGB):
结果(CMYK):
要叠加两张图片,一张图片必须具有某种透明度概念。遮罩就是其中的一个例子,您可以在其中选择特定的颜色值来表示“透明”。蒙版的缺点是蒙版不能很好地处理混叠的源图像。为此,您可能想要做一个 alpha 通道 - 但跨颜色空间混合将具有挑战性。 (Github)
// Load, validate A
var imageA = LoadTiff("CMYK.tif");
if (imageA.Format != PixelFormats.Cmyk32)
{
throw new InvalidOperationException("imageA is not CMYK");
}
// Load, validate, convert B
var imageB = LoadTiff("RGBOverlay.tif");
if (imageB.PixelHeight != imageA.PixelHeight
|| imageB.PixelWidth != imageA.PixelWidth)
{
throw new InvalidOperationException("Image B is not the same size as image A");
}
var imageBBGRA = new FormatConvertedBitmap(imageB, PixelFormats.Bgra32, null, 0d);
var imageBCmyk = new FormatConvertedBitmap(imageB, imageA.Format, null, 0d);
// Merge
int width = imageA.PixelWidth, height = imageA.PixelHeight;
var stride = width * (imageA.Format.BitsPerPixel / 8);
var bufferA = new uint[width * height];
var bufferB = new uint[width * height];
var maskBuffer = new uint[width * height];
imageA.CopyPixels(bufferA, stride, 0);
imageBBGRA.CopyPixels(maskBuffer, stride, 0);
imageBCmyk.CopyPixels(bufferB, stride, 0);
for (int i = 0; i < bufferA.Length; i++)
{
// set pixel in bufferA to the value from bufferB if mask is not white
if (maskBuffer[i] != 0xffffffff)
{
bufferA[i] = bufferB[i];
}
}
var result = BitmapSource.Create(width, height, imageA.DpiX, imageA.DpiY, imageA.Format, null, bufferA, stride);
// save to new file
using (var ws = File.Create("out_overlay.tif"))
{
var tiffEncoder = new TiffBitmapEncoder();
tiffEncoder.Frames.Add(BitmapFrame.Create(result));
tiffEncoder.Save(ws);
}
示例图片 B:
示例输出: