XPrintServer/XPrint.Image/Tools/CmykImageTool.cs
2025-11-16 19:33:01 +08:00

312 lines
12 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using HPPH;
using ImageMagick;
using ImageMagick.Formats;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
namespace XPrint.Image.Tools
{
public class CmykImageTool
{
private static XmpProfile? _xmpProfile = null;
static CmykImageTool()
{
string channelName = "White";
// 构建包含 Adobe 标准命名空间的 XML
var xml = $@"
<x:xmpmeta>
<rdf:RDF>
<rdf:Description rdf:about=''>
<photoshop:ChannelNames>
<rdf:Bag>
<rdf:li>Alpha</rdf:li>
<rdf:li>${channelName}</rdf:li>
</rdf:Bag>
</photoshop:ChannelNames>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>;";
var data = Encoding.UTF8.GetBytes(xml);
_xmpProfile = new XmpProfile(data);
}
public static bool IsCmykImage(string imagePath)
{
using (var image = new MagickImage(imagePath))
{
// 检查颜色空间是否为 CMYK
return image.ColorSpace == ColorSpace.CMYK;
}
}
/// <summary>
/// 分色接口
/// </summary>
/// <param name="inputPath">输入图片路径</param>
/// <param name="outputPath">输出图片路径</param>
/// <param name="iccProfileName">icc名称</param>
/// <param name="iccProfilePath">icc文件路径</param>
public static void SplitColor(string inputPath, string outputPath, string iccProfilePath = "")
{
using (var image = new MagickImage(inputPath))
{
// 配置大端字节序
var writeSettings = new TiffWriteDefines();
writeSettings.Endian = Endian.MSB;//大端模式,兼容性好些
image.MetaChannelCount = 1;
//if (!image.HasAlpha)
//{
// image.Alpha(AlphaOption.On);
//}
//var profileBim = image.Get8BimProfile();
//if (profileBim != null)
//{
// var data = profileBim.ToByteArray();
// File.WriteAllBytes(@"D:\8bim", data);
//}
//if (!string.IsNullOrWhiteSpace(iccProfileName) && !string.IsNullOrWhiteSpace(iccProfilePath))
//{
// // 加载ICC配置文件
// var profile = new ColorProfile(File.ReadAllBytes(iccProfilePath));
// image.SetProfile(profile);
//}
//else
//{
// var profile = new ExifProfile();
// profile.SetValue(ExifTag.Copyright, "Anole");
// profile.SetValue(ExifTag.ImageDescription, "");
// image.SetProfile(profile);
//}
//var value5 = profileBim.Values.ElementAt(5);
//profileBim.Values.Append(new EightBimValue { });
//foreach (var p in pro?.Values!)
//{
// Console.WriteLine(p.Name);
//}
//Console.WriteLine("ICC配置文件已成功应用");
//image.Comment = """
// <?xml version="1.0" encoding="utf-16"?>
// <ChannelNames xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
// <Channel Index="0" Name="C" />
// <Channel Index="1" Name="M" />
// <Channel Index="2" Name="Y" />
// <Channel Index="3" Name="K" />
// <Channel Index="4" Name="A" />
// <Channel Index="5" Name="W" />
// </ChannelNames>
// """;
// 添加输入和输出配置
image.SetProfile(ColorProfile.ColorMatchRGB);
//image.SetProfile(new ColorProfile(@"D:\sRGB2014.icc"));
//image.SetProfile(new ColorProfile(@"D:\JapanColor2001Coated.icc"));
if (!string.IsNullOrWhiteSpace(iccProfilePath))
{
// 加载ICC配置文件
var profile = new ColorProfile(iccProfilePath);
//var icc = imageKele.GetProfile("icc")!;
image.SetProfile(profile);
}
else
{
image.SetProfile(ColorProfile.USWebCoatedSWOP);
}
// 确保图像为CMYK模式
if (image.ColorSpace != ColorSpace.CMYK)
{
image.ColorSpace = ColorSpace.CMYK;
}
var channels = image.Channels;
ushort[] area;
var pixels = image.GetPixels();
bool hasAlpha = image.HasAlpha;
if (hasAlpha)
{
image.Alpha(AlphaOption.On);
image.MetaChannelCount = 0;
var areaAlpha = pixels.GetArea(0, 0, image.Width, image.Height)!;
image.Alpha(AlphaOption.Off);
image.MetaChannelCount = 1;
area = pixels.GetArea(0, 0, image.Width, image.Height)!;
// 遍历每个像素根据Alpha值设置White通道
for (int i = 0; i < areaAlpha.Length; i += 5)
{
// 获取原始图像的Alpha值
ushort alpha = areaAlpha[i + 4];
var c = area[i];
var m = area[i + 1];
var y = area[i + 2];
var k = area[i + 3];
if (c > 0 || m > 0 || y > 0 || k > 0)
{
// 根据Alpha值设置White通道透明区域(Alpha=0)设为黑色,不透明区域设为白色
ushort whiteValue = (ushort)(alpha == 0 ? 0 : 65535);
area[i + 4] = whiteValue;
}
else
{
area[i + 4] = 0;
}
}
}
else
{
image.Alpha(AlphaOption.Off);
area = pixels.GetArea(0, 0, image.Width, image.Height)!;
// 遍历每个像素根据Alpha值设置White通道
for (int i = 0; i < area.Length; i += 5)
{
var c = area[i];
var m = area[i + 1];
var y = area[i + 2];
var k = area[i + 3];
if (c > 0 || m > 0 || y > 0 || k > 0)
{
area[i + 4] = 65535;
}
else
{
area[i + 4] = 0;
}
}
}
if (hasAlpha)
{
image.MetaChannelCount = 1;
}
pixels.SetPixels(area);
//var channels = image.Channels;
//whiteChannel.Composite(image, CompositeOperator.Copy, Channels.CMYK);
//if (!string.IsNullOrWhiteSpace(iccProfileName) && !string.IsNullOrWhiteSpace(iccProfilePath))
//{
// // 加载ICC配置文件
// var profile = new ColorProfile(File.ReadAllBytes(iccProfilePath));
// image.SetProfile(profile);
//}
//image.SetProfile(ColorProfile.USWebCoatedSWOP);
//var bimProfile = image.Get8BimProfile();
string bimFileName = "8bim";
//if (hasAlpha)
//{
// bimFileName = "8bim_alpha";
//}
var bimData = File.ReadAllBytes(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"assets/{bimFileName}"));
var profileBim = new EightBimProfile(image, bimData);
//var profileBim = image.Get8BimProfile()!;
//profileBim.GetExifProfile()?.RemoveThumbnail();
//File.WriteAllBytes(@$"D:\{bimFileName}", profileBim.ToByteArray());
//if (bimProfile != null)
//{
// var exifProfile = bimProfile.GetExifProfile();
// var xmpProfile = bimProfile.GetXmpProfile();
// var iptcProfile = bimProfile.GetIptcProfile();
// profileBim.SetExifProfile(exifProfile);
// profileBim.SetIptcProfile(iptcProfile);
// profileBim.SetXmpProfile(xmpProfile);
//}
//image.Alpha(AlphaOption.Remove);
profileBim.SetExifProfile(image.GetExifProfile());
profileBim.SetIptcProfile(image.GetIptcProfile());
profileBim.SetXmpProfile(image.GetXmpProfile());
image.SetProfile(profileBim);
profileBim.GetExifProfile()?.CreateThumbnail();
//image.Compose = CompositeOperator.Overlay;
image.Settings.Compression = CompressionMethod.LZW;
image.SetCompression(CompressionMethod.LZW);//LZW压缩避免竖线问题
//writeSettings.Alpha = TiffAlpha.Associated;
// 保存
image.Write(outputPath);
//var channelNames = new Dictionary<int, string>
//{
// { 0, "C" }, // 假设通道索引1对应红色
// { 1, "M" },
// { 2, "Y" },
// { 3, "K" },
// { 4, "A" },
// { 5, "W" }
//};
//TiffModifier.RenameCustomChannels(@"D:\2.tiff", Path.Combine(Path.GetDirectoryName(outputPath)!, "3.tif"), channelNames);
// 创建包含 4 个自定义通道的图像
//using (System.Drawing.Image imageA = new Bitmap(new MemoryStream(image.ToByteArray())))
//{
// var items = imageA.PropertyItems;
//}
pixels.Dispose();
}
}
//private static string AddCustomXmpChannelName(string xmpXml, string channelName)
//{
// // 注意:此方法需要根据实际 XMP 结构和命名空间调整
// // 示例:添加自定义命名空间 "mychannel"
// if (!xmpXml.Contains("xmlns:mychannel"))
// {
// xmpXml = xmpXml.Replace("<rdf:RDF",
// "<rdf:RDF xmlns:mychannel=\"http://example.com/channel/\"");
// }
// // 添加或更新 ChannelName 属性
// string channelProperty = $"<mychannel:ChannelName>{channelName}</mychannel:ChannelName>";
// int insertPos = xmpXml.IndexOf("</rdf:RDF>");
// if (insertPos > 0)
// {
// xmpXml = xmpXml.Insert(insertPos, channelProperty);
// }
// return xmpXml;
//}
//public static void GenerateMultiPageCmykTiff(MagickImage[] imagePages, string outputPath)
//{
// using (var images = new MagickImageCollection())
// {
// for (int i = 0; i < imagePages.Length; i++)
// {
// //设置dpi
// //imagePages[i].Density = new Density(300.00, 300.00);
// images.Add(imagePages[i]);
// }
// // 配置大端字节序
// var writeSettings = new WriteTiffBigEndianDefines();
// // 保存多页
// images.Write(outputPath, writeSettings);
// }
//}
}
}