How to execute external program from custom directory in Silverlight 5 - c#

In order to execute external applications from Silverlight app, you need to:
Run out-of-browser
Have elevated trust permissions
To execute such applications, you can do something like this
public static void EjecutaEXE(string ruta)
{
using (dynamic shell = AutomationFactory.CreateObject("WScript.Shell"))
{
shell.Run(#ruta);
}
}
I have found that I am only able to run such application from the Windows directory, Am I missing something? seems pointless such limitation.
This WORKS:
EjecutaEXE("C:/Windows/myAwesomeApp.exe")
This does NOT WORK:
EjecutaEXE("C:/myfolder/myAwesomeApp.exe")
There are no errors or exceptions, it just does nothing.

I have no experience With the code you presented, but as an alternative this should work:
public enum ShowCommands : int
{
SW_HIDE = 0,
SW_SHOWNORMAL = 1,
SW_NORMAL = 1,
SW_SHOWMINIMIZED = 2,
SW_SHOWMAXIMIZED = 3,
SW_MAXIMIZE = 3,
SW_SHOWNOACTIVATE = 4,
SW_SHOW = 5,
SW_MINIMIZE = 6,
SW_SHOWMINNOACTIVE = 7,
SW_SHOWNA = 8,
SW_RESTORE = 9,
SW_SHOWDEFAULT = 10,
SW_FORCEMINIMIZE = 11,
SW_MAX = 11
}
[DllImport("shell32.dll")]
static extern IntPtr ShellExecute(
IntPtr hwnd,
string lpOperation,
string lpFile,
string lpParameters,
string lpDirectory,
ShowCommands nShowCmd);
public static void ExecuteMyCode(string filePath)
{
IntPtr retval = ShellExecute(System.IntPtr.Zero, string.Empty, filePath, string.Empty, string.Empty, ShowCommands.SW_NORMAL);
}

Related

Passing uint array to Dll to be populated (Nvidia NVML library)

I'm attempting to pass a uint array into the NVML function nvmlDeviceGetAccountingPids(Doc here) from C#, here's a minimum working sample of what I have so far:
{
public const string NVMLDLL = "nvml.dll";
public static class Constants
{
public const int NVML_DEVICE_INFOROM_VERSION_BUFFER_SIZE = 16;
public const int NVML_DEVICE_NAME_BUFFER_SIZE = 64;
public const int NVML_DEVICE_NAME_V2_BUFFER_SIZE = 96;
public const int NVML_DEVICE_PART_NUMBER_BUFFER_SIZE = 80;
public const int NVML_DEVICE_SERIAL_BUFFER_SIZE = 30;
public const int NVML_DEVICE_UUID_BUFFER_SIZE = 80;
public const int NVML_DEVICE_UUID_V2_BUFFER_SIZE = 96;
public const int NVML_DEVICE_VBIOS_VERSION_BUFFER_SIZE = 32;
public const int NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE = 80;
public const int NVML_SYSTEM_NVML_VERSION_BUFFER_SIZE = 80;
public const int NVML_INIT_FLAG_NO_ATTACH = 2;
public const int NVML_INIT_FLAG_NO_GPUS = 1;
}
public enum nvmlReturn_t
{
NVML_SUCCESS = 0, // The operation was successful.
NVML_ERROR_UNINITIALIZED = 1, // NVML was not first initialized with nvmlInit().
NVML_ERROR_INVALID_ARGUMENT = 2, // A supplied argument is invalid.
NVML_ERROR_NOT_SUPPORTED = 3, // The requested operation is not available on target device.
NVML_ERROR_NO_PERMISSION = 4, // The current user does not have permission for operation.
NVML_ERROR_ALREADY_INITIALIZED = 5, // Deprecated: Multiple initializations are now allowed through ref counting.
NVML_ERROR_NOT_FOUND = 6, // A query to find an object was unsuccessful.
NVML_ERROR_INSUFFICIENT_SIZE = 7, // An input argument is not large enough.
NVML_ERROR_INSUFFICIENT_POWER = 8, // A device's external power cables are not properly attached.
NVML_ERROR_DRIVER_NOT_LOADED = 9, // NVIDIA driver is not loaded.
NVML_ERROR_TIMEOUT = 10, // User provided timeout passed.
NVML_ERROR_IRQ_ISSUE = 11, // NVIDIA Kernel detected an interrupt issue with a GPU.
NVML_ERROR_LIBRARY_NOT_FOUND = 12, // NVML Shared Library couldn't be found or loaded.
NVML_ERROR_FUNCTION_NOT_FOUND = 13, // Local version of NVML doesn't implement this function.
NVML_ERROR_CORRUPTED_INFOROM = 14, // infoROM is corrupted
NVML_ERROR_GPU_IS_LOST = 15, // The GPU has fallen off the bus or has otherwise become inaccessible.
NVML_ERROR_RESET_REQUIRED = 16, // The GPU requires a reset before it can be used again.
NVML_ERROR_OPERATING_SYSTEM = 17, // The GPU control device has been blocked by the operating system/cgroups.
NVML_ERROR_LIB_RM_VERSION_MISMATCH = 18, // RM detects a driver/library version mismatch.
NVML_ERROR_IN_USE = 19, // An operation cannot be performed because the GPU is currently in use.
NVML_ERROR_MEMORY = 20, // Insufficient memory.
NVML_ERROR_NO_DATA = 21, // No data.
NVML_ERROR_VGPU_ECC_NOT_SUPPORTED = 22, // The requested vgpu operation is not available on target device, becasue ECC is enabled.
NVML_ERROR_INSUFFICIENT_RESOURCES = 23, // Ran out of critical resources, other than memory.
NVML_ERROR_FREQ_NOT_SUPPORTED = 24, // Ran out of critical resources, other than memory.
NVML_ERROR_UNKNOWN = 999 // An internal driver error occurred.
}
[DllImport(NVMLDLL)]
private static extern nvmlReturn_t nvmlInit_v2();
[DllImport(NVMLDLL)]
private static extern nvmlReturn_t nvmlShutdown();
[DllImport(NVMLDLL)]
private static extern nvmlReturn_t nvmlDeviceGetCount_v2(out uint deviceCount);
[DllImport(NVMLDLL)]
private static extern nvmlReturn_t nvmlDeviceGetHandleByIndex_v2(int index, out IntPtr handle);
[DllImport(NVMLDLL)]
private static extern nvmlReturn_t nvmlDeviceGetName(IntPtr device, [MarshalAs(UnmanagedType.LPStr)] StringBuilder deviceName, uint length);
[DllImport(NVMLDLL)]
private static extern nvmlReturn_t nvmlDeviceGetAccountingPids(IntPtr device, ref uint count, [In, Out] uint[] pids);
static void Main(string[] args)
{
if (nvmlInit_v2() == nvmlReturn_t.NVML_SUCCESS)
{
nvmlDeviceGetCount_v2(out uint deviceCount);
for (int i = 0; i < deviceCount; i++)
{
StringBuilder name = new();
nvmlDeviceGetHandleByIndex_v2(i, out IntPtr _device);
nvmlDeviceGetName(_device, name, Constants.NVML_DEVICE_NAME_V2_BUFFER_SIZE);
// arbitrary number for now
uint count = 5;
uint[] pids = new uint[count];
nvmlDeviceGetAccountingPids(_device, ref count, pids);
foreach(uint ui in pids) Console.WriteLine(ui);
}
nvmlShutdown();
}
}
}
and so far it's returning the correct # of processes that are utilizing the gpu, but the PID array keeps returning all 0's. I'm not particularly experienced with C# so if someone could show me the proper syntax for this(or lemme know if I have to resort to IntPtr's), the original function has this signature:
nvmlReturn_t nvmlDeviceGetAccountingPids ( nvmlDevice_t device, unsigned int* count, unsigned int* pids )
Parameters
device
The identifier of the target device
count
Reference in which to provide the pids array size, and to return the number of elements ready to be queried
pids
Reference in which to return list of process ids
If anyone knows that magic combo I'd sure appreciate it, thank you for your time =)
Sometimes I think I only type things to work them out ^_^
static void Main(string[] args)
{
if (nvmlInit_v2() == nvmlReturn_t.NVML_SUCCESS)
{
nvmlDeviceGetCount_v2(out uint deviceCount);
for (int i = 0; i < deviceCount; i++)
{
StringBuilder name = new();
nvmlDeviceGetHandleByIndex_v2(i, out IntPtr _device);
nvmlDeviceGetName(_device, name, Constants.NVML_DEVICE_NAME_V2_BUFFER_SIZE);
// arbitrary number for now
uint count = 0;
nvmlDeviceGetAccountingPids(_device, ref count, null);
uint[] pids = new uint[count];
if (nvmlDeviceGetAccountingPids(_device, ref count, pids) == nvmlReturn_t.NVML_SUCCESS)
{
foreach (uint ui in pids) Console.WriteLine(ui);
}
}
nvmlShutdown();
}
so it turns out that when passing the count to the function it wants the same number as the size of the array in order to populate the pids list(which makes sense I suppose). This is retrieved by just setting count to "0" and passing a null array to the function and it will set count to the size of the array. Create a new uint array with that size, pass the array/count and BAM, it returns the pids as desired.
Thanks for reading SO!
If anyone has some constructive criticism in terms of syntax/practices please do comment so I can improve this code as I go. Have a wonderful day 👍

Get handle of top window (Sort windows by Z index)

I am trying to write a method which takes List of window handles and returns handle of the window which has highest z index among others. But in vain. Can anybody give me a suggestion how to do that?
I'll help you out:
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr GetWindow(IntPtr hWnd, GetWindow_Cmd uCmd);
enum GetWindow_Cmd : uint
{
GW_HWNDFIRST = 0,
GW_HWNDLAST = 1,
GW_HWNDNEXT = 2,
GW_HWNDPREV = 3,
GW_OWNER = 4,
GW_CHILD = 5,
GW_ENABLEDPOPUP = 6
}
private IntPtr GetTopmostHwnd(List<IntPtr> hwnds)
{
var topmostHwnd = IntPtr.Zero;
if (hwnds != null && hwnds.Count > 0)
{
var hwnd = hwnds[0];
while (hwnd != IntPtr.Zero)
{
if (hwnds.Contains(hwnd))
{
topmostHwnd = hwnd;
}
hwnd = GetWindow(hwnd, GetWindow_Cmd.GW_HWNDPREV);
}
}
return topmostHwnd;
}

Convert RGB value to CMYK using an ICC profile? c# [duplicate]

this question seems posted at many places over the interwebs and SO, but I could not find a satisfactory answer :(
How can I convert a RGB value to a CMYK value using an ICC profile?
The closest answer I have is there, where it explains how to convert from CMYK to RGB but not the other way around, which is what I need.
(http://stackoverflow.com/questions/4920482/cmyk-to-rgb-formula-of-photoshop/5076731#5076731)
float[] colorValues = new float[4];
colorValues[0] = c / 255f;
colorValues[1] = m / 255f;
colorValues[2] = y / 255f;
colorValues[3] = k / 255f;
System.Windows.Media.Color color = Color.FromValues(colorValues,
new Uri(#"C:\Users\me\Documents\ISOcoated_v2_300_eci.icc"));
System.Drawing.Color rgbColor = System.Drawing.Color.FromArgb(color.R, color.G, color.B);
I guess I should be using some classes/structures/methods from the System.Windows.Media namespace.
The System.Windows.Media.Color structure contains a method FromRgb, but I can't get CMYK values after, out of that System.Windows.Media.Color!
Many thanks
I don't know of any C# API or library that can achieve this. However, if you have enough C/C++ knowledge to build a wrapper for C#, I see two options:
Windows Color System (WCS) (part of Windows)
LittleCMS
The System.Windows.Media namespace is very limited. There's probably a powerful engine (WCS?) behind it, but just a small part is made available.
Update:
Here's some C# code to do the conversion using WCS. It certainly could use a wrapper that would make it easier to use:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace ICM
{
public class WindowsColorSystem
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public class ProfileFilename
{
public uint type;
[MarshalAs(UnmanagedType.LPTStr)]
public string profileData;
public uint dataSize;
public ProfileFilename(string filename)
{
type = ProfileFilenameType;
profileData = filename;
dataSize = (uint)filename.Length * 2 + 2;
}
};
public const uint ProfileFilenameType = 1;
public const uint ProfileMembufferType = 2;
public const uint ProfileRead = 1;
public const uint ProfileReadWrite = 2;
public enum FileShare : uint
{
Read = 1,
Write = 2,
Delete = 4
};
public enum CreateDisposition : uint
{
CreateNew = 1,
CreateAlways = 2,
OpenExisting = 3,
OpenAlways = 4,
TruncateExisting = 5
};
public enum LogicalColorSpace : uint
{
CalibratedRGB = 0x00000000,
sRGB = 0x73524742,
WindowsColorSpace = 0x57696E20
};
public enum ColorTransformMode : uint
{
ProofMode = 0x00000001,
NormalMode = 0x00000002,
BestMode = 0x00000003,
EnableGamutChecking = 0x00010000,
UseRelativeColorimetric = 0x00020000,
FastTranslate = 0x00040000,
PreserveBlack = 0x00100000,
WCSAlways = 0x00200000
};
enum ColorType : int
{
Gray = 1,
RGB = 2,
XYZ = 3,
Yxy = 4,
Lab = 5,
_3_Channel = 6,
CMYK = 7,
_5_Channel = 8,
_6_Channel = 9,
_7_Channel = 10,
_8_Channel = 11,
Named = 12
};
public const uint IntentPerceptual = 0;
public const uint IntentRelativeColorimetric = 1;
public const uint IntentSaturation = 2;
public const uint IntentAbsoluteColorimetric = 3;
public const uint IndexDontCare = 0;
[StructLayout(LayoutKind.Sequential)]
public struct RGBColor
{
public ushort red;
public ushort green;
public ushort blue;
public ushort pad;
};
[StructLayout(LayoutKind.Sequential)]
public struct CMYKColor
{
public ushort cyan;
public ushort magenta;
public ushort yellow;
public ushort black;
};
[DllImport("mscms.dll", SetLastError = true, EntryPoint = "OpenColorProfileW", CallingConvention = CallingConvention.Winapi)]
static extern IntPtr OpenColorProfile(
[MarshalAs(UnmanagedType.LPStruct)] ProfileFilename profile,
uint desiredAccess,
FileShare shareMode,
CreateDisposition creationMode);
[DllImport("mscms.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
static extern bool CloseColorProfile(IntPtr hProfile);
[DllImport("mscms.dll", SetLastError = true, EntryPoint = "GetStandardColorSpaceProfileW", CallingConvention = CallingConvention.Winapi)]
static extern bool GetStandardColorSpaceProfile(
uint machineName,
LogicalColorSpace profileID,
[MarshalAs(UnmanagedType.LPTStr), In, Out] StringBuilder profileName,
ref uint size);
[DllImport("mscms.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
static extern IntPtr CreateMultiProfileTransform(
[In] IntPtr[] profiles,
uint nProfiles,
[In] uint[] intents,
uint nIntents,
ColorTransformMode flags,
uint indexPreferredCMM);
[DllImport("mscms.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
static extern bool DeleteColorTransform(IntPtr hTransform);
[DllImport("mscms.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
static extern bool TranslateColors(
IntPtr hColorTransform,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2), In] RGBColor[] inputColors,
uint nColors,
ColorType ctInput,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2), Out] CMYKColor[] outputColors,
ColorType ctOutput);
public static void Test()
{
bool success;
StringBuilder profileName = new StringBuilder(256);
uint size = (uint)profileName.Capacity * 2;
success = GetStandardColorSpaceProfile(0, LogicalColorSpace.sRGB, profileName, ref size);
ProfileFilename sRGBFilename = new ProfileFilename(profileName.ToString());
IntPtr hSRGBProfile = OpenColorProfile(sRGBFilename, ProfileRead, FileShare.Read, CreateDisposition.OpenExisting);
ProfileFilename isoCoatedFilename = new ProfileFilename(#"C:\Users\me\Documents\ISOcoated_v2_300_eci.icc");
IntPtr hIsoCoatedProfile = OpenColorProfile(isoCoatedFilename, ProfileRead, FileShare.Read, CreateDisposition.OpenExisting);
IntPtr[] profiles = new IntPtr[] { hSRGBProfile, hIsoCoatedProfile };
uint[] intents = new uint[] { IntentPerceptual };
IntPtr transform = CreateMultiProfileTransform(profiles, 2, intents, 1, ColorTransformMode.BestMode, IndexDontCare);
RGBColor[] rgbColors = new RGBColor[1];
rgbColors[0] = new RGBColor();
CMYKColor[] cmykColors = new CMYKColor[1];
cmykColors[0] = new CMYKColor();
rgbColors[0].red = 30204;
rgbColors[0].green = 4420;
rgbColors[0].blue = 60300;
success = TranslateColors(transform, rgbColors, 1, ColorType.RGB, cmykColors, ColorType.CMYK);
success = DeleteColorTransform(transform);
success = CloseColorProfile(hSRGBProfile);
success = CloseColorProfile(hIsoCoatedProfile);
}
}
}
None of the answers here seem to satisfactorily address the need to use an ICC profile.
I found an MS Connect issue page that has some sample code using Windows Imaging Components to convert an RBG JPEG to CMYK using an ICC profile.
If you have your ICC file and a sample JPEG file, you can set-up a console app to use this code very quickly.
I have saved the ICC profile in a folder called "Profiles" and have set the "Copy to Output Directory" value to "Always".
The JPEG is saved to a folder called "Images", and I have set its "Build Action" value to "Embedded Resource".
The console app project needs references to the following modules:
PresentationCore
System.Xaml
WindowsBase
The console app in full (named CMYKConversion) :
Program.cs:
using System;
namespace CMYKConversion
{
class Program
{
static void Main(string[] args)
{
Converter c = new Converter();
c.Convert();
Console.ReadKey();
}
}
}
Converter.cs:
using System;
using System.IO;
using System.Reflection;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace CMYKConversion
{
public class Converter
{
public void Convert()
{
var rgbJpeg = BitmapFrame.Create(GetStreamFromResource("CMYKConversion.Images.Desert.jpg"));
var iccCmykJpeg = new ColorConvertedBitmap(
rgbJpeg,
new ColorContext(PixelFormats.Default),
new ColorContext(GetProfilePath("Profiles/1010_ISO_Coated_39L.icc")),
PixelFormats.Cmyk32
);
var jpegBitmapEncoder = new JpegBitmapEncoder();
jpegBitmapEncoder.Frames.Add(BitmapFrame.Create(iccCmykJpeg));
var iccCmykJpegStream = new MemoryStream();
jpegBitmapEncoder.Save(iccCmykJpegStream);
iccCmykJpegStream.Flush();
SaveMemoryStream(iccCmykJpegStream, "C:\\desertCMYK.jpg");
iccCmykJpegStream.Close();
}
private Stream GetStreamFromResource(string name)
{
return typeof(Program).Assembly.GetManifestResourceStream(name);
}
private Uri GetProfilePath(string name)
{
string folder = Path.GetDirectoryName(Assembly.GetAssembly(typeof(Program)).CodeBase);
return new Uri(Path.Combine(folder, name));
}
private void SaveMemoryStream(MemoryStream ms, string fileName)
{
FileStream outStream = File.OpenWrite(fileName);
ms.WriteTo(outStream);
outStream.Flush();
outStream.Close();
}
}
}
According to an MVP GDI+ can read CMYK but can't encode it (Source: http://www.pcreview.co.uk/forums/convert-rgb-image-cmyk-t1419911.html). They go on to say that using TIF as an intermediation format may be the way to go.
Other than that, you might try Graphics Mill imaging SDK for .NET at http://imaging.aurigma.com/ (I'm not affiliated with this company).
I know this isn't much of an answer, but hopefully it sheds some light and points you in the right direction.
You could have a look at this: Convert RGB color to CMYK?
Although this conversion is fairly subjective, hence the need for the ICC profile, it may be that you can extract that "factor" from the ICC and adjust the formula?
What is the context is which you need to convert the RGB values to CMYK?

C# convert RGB value to CMYK using an ICC profile?

this question seems posted at many places over the interwebs and SO, but I could not find a satisfactory answer :(
How can I convert a RGB value to a CMYK value using an ICC profile?
The closest answer I have is there, where it explains how to convert from CMYK to RGB but not the other way around, which is what I need.
(http://stackoverflow.com/questions/4920482/cmyk-to-rgb-formula-of-photoshop/5076731#5076731)
float[] colorValues = new float[4];
colorValues[0] = c / 255f;
colorValues[1] = m / 255f;
colorValues[2] = y / 255f;
colorValues[3] = k / 255f;
System.Windows.Media.Color color = Color.FromValues(colorValues,
new Uri(#"C:\Users\me\Documents\ISOcoated_v2_300_eci.icc"));
System.Drawing.Color rgbColor = System.Drawing.Color.FromArgb(color.R, color.G, color.B);
I guess I should be using some classes/structures/methods from the System.Windows.Media namespace.
The System.Windows.Media.Color structure contains a method FromRgb, but I can't get CMYK values after, out of that System.Windows.Media.Color!
Many thanks
I don't know of any C# API or library that can achieve this. However, if you have enough C/C++ knowledge to build a wrapper for C#, I see two options:
Windows Color System (WCS) (part of Windows)
LittleCMS
The System.Windows.Media namespace is very limited. There's probably a powerful engine (WCS?) behind it, but just a small part is made available.
Update:
Here's some C# code to do the conversion using WCS. It certainly could use a wrapper that would make it easier to use:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace ICM
{
public class WindowsColorSystem
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public class ProfileFilename
{
public uint type;
[MarshalAs(UnmanagedType.LPTStr)]
public string profileData;
public uint dataSize;
public ProfileFilename(string filename)
{
type = ProfileFilenameType;
profileData = filename;
dataSize = (uint)filename.Length * 2 + 2;
}
};
public const uint ProfileFilenameType = 1;
public const uint ProfileMembufferType = 2;
public const uint ProfileRead = 1;
public const uint ProfileReadWrite = 2;
public enum FileShare : uint
{
Read = 1,
Write = 2,
Delete = 4
};
public enum CreateDisposition : uint
{
CreateNew = 1,
CreateAlways = 2,
OpenExisting = 3,
OpenAlways = 4,
TruncateExisting = 5
};
public enum LogicalColorSpace : uint
{
CalibratedRGB = 0x00000000,
sRGB = 0x73524742,
WindowsColorSpace = 0x57696E20
};
public enum ColorTransformMode : uint
{
ProofMode = 0x00000001,
NormalMode = 0x00000002,
BestMode = 0x00000003,
EnableGamutChecking = 0x00010000,
UseRelativeColorimetric = 0x00020000,
FastTranslate = 0x00040000,
PreserveBlack = 0x00100000,
WCSAlways = 0x00200000
};
enum ColorType : int
{
Gray = 1,
RGB = 2,
XYZ = 3,
Yxy = 4,
Lab = 5,
_3_Channel = 6,
CMYK = 7,
_5_Channel = 8,
_6_Channel = 9,
_7_Channel = 10,
_8_Channel = 11,
Named = 12
};
public const uint IntentPerceptual = 0;
public const uint IntentRelativeColorimetric = 1;
public const uint IntentSaturation = 2;
public const uint IntentAbsoluteColorimetric = 3;
public const uint IndexDontCare = 0;
[StructLayout(LayoutKind.Sequential)]
public struct RGBColor
{
public ushort red;
public ushort green;
public ushort blue;
public ushort pad;
};
[StructLayout(LayoutKind.Sequential)]
public struct CMYKColor
{
public ushort cyan;
public ushort magenta;
public ushort yellow;
public ushort black;
};
[DllImport("mscms.dll", SetLastError = true, EntryPoint = "OpenColorProfileW", CallingConvention = CallingConvention.Winapi)]
static extern IntPtr OpenColorProfile(
[MarshalAs(UnmanagedType.LPStruct)] ProfileFilename profile,
uint desiredAccess,
FileShare shareMode,
CreateDisposition creationMode);
[DllImport("mscms.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
static extern bool CloseColorProfile(IntPtr hProfile);
[DllImport("mscms.dll", SetLastError = true, EntryPoint = "GetStandardColorSpaceProfileW", CallingConvention = CallingConvention.Winapi)]
static extern bool GetStandardColorSpaceProfile(
uint machineName,
LogicalColorSpace profileID,
[MarshalAs(UnmanagedType.LPTStr), In, Out] StringBuilder profileName,
ref uint size);
[DllImport("mscms.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
static extern IntPtr CreateMultiProfileTransform(
[In] IntPtr[] profiles,
uint nProfiles,
[In] uint[] intents,
uint nIntents,
ColorTransformMode flags,
uint indexPreferredCMM);
[DllImport("mscms.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
static extern bool DeleteColorTransform(IntPtr hTransform);
[DllImport("mscms.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
static extern bool TranslateColors(
IntPtr hColorTransform,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2), In] RGBColor[] inputColors,
uint nColors,
ColorType ctInput,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2), Out] CMYKColor[] outputColors,
ColorType ctOutput);
public static void Test()
{
bool success;
StringBuilder profileName = new StringBuilder(256);
uint size = (uint)profileName.Capacity * 2;
success = GetStandardColorSpaceProfile(0, LogicalColorSpace.sRGB, profileName, ref size);
ProfileFilename sRGBFilename = new ProfileFilename(profileName.ToString());
IntPtr hSRGBProfile = OpenColorProfile(sRGBFilename, ProfileRead, FileShare.Read, CreateDisposition.OpenExisting);
ProfileFilename isoCoatedFilename = new ProfileFilename(#"C:\Users\me\Documents\ISOcoated_v2_300_eci.icc");
IntPtr hIsoCoatedProfile = OpenColorProfile(isoCoatedFilename, ProfileRead, FileShare.Read, CreateDisposition.OpenExisting);
IntPtr[] profiles = new IntPtr[] { hSRGBProfile, hIsoCoatedProfile };
uint[] intents = new uint[] { IntentPerceptual };
IntPtr transform = CreateMultiProfileTransform(profiles, 2, intents, 1, ColorTransformMode.BestMode, IndexDontCare);
RGBColor[] rgbColors = new RGBColor[1];
rgbColors[0] = new RGBColor();
CMYKColor[] cmykColors = new CMYKColor[1];
cmykColors[0] = new CMYKColor();
rgbColors[0].red = 30204;
rgbColors[0].green = 4420;
rgbColors[0].blue = 60300;
success = TranslateColors(transform, rgbColors, 1, ColorType.RGB, cmykColors, ColorType.CMYK);
success = DeleteColorTransform(transform);
success = CloseColorProfile(hSRGBProfile);
success = CloseColorProfile(hIsoCoatedProfile);
}
}
}
None of the answers here seem to satisfactorily address the need to use an ICC profile.
I found an MS Connect issue page that has some sample code using Windows Imaging Components to convert an RBG JPEG to CMYK using an ICC profile.
If you have your ICC file and a sample JPEG file, you can set-up a console app to use this code very quickly.
I have saved the ICC profile in a folder called "Profiles" and have set the "Copy to Output Directory" value to "Always".
The JPEG is saved to a folder called "Images", and I have set its "Build Action" value to "Embedded Resource".
The console app project needs references to the following modules:
PresentationCore
System.Xaml
WindowsBase
The console app in full (named CMYKConversion) :
Program.cs:
using System;
namespace CMYKConversion
{
class Program
{
static void Main(string[] args)
{
Converter c = new Converter();
c.Convert();
Console.ReadKey();
}
}
}
Converter.cs:
using System;
using System.IO;
using System.Reflection;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace CMYKConversion
{
public class Converter
{
public void Convert()
{
var rgbJpeg = BitmapFrame.Create(GetStreamFromResource("CMYKConversion.Images.Desert.jpg"));
var iccCmykJpeg = new ColorConvertedBitmap(
rgbJpeg,
new ColorContext(PixelFormats.Default),
new ColorContext(GetProfilePath("Profiles/1010_ISO_Coated_39L.icc")),
PixelFormats.Cmyk32
);
var jpegBitmapEncoder = new JpegBitmapEncoder();
jpegBitmapEncoder.Frames.Add(BitmapFrame.Create(iccCmykJpeg));
var iccCmykJpegStream = new MemoryStream();
jpegBitmapEncoder.Save(iccCmykJpegStream);
iccCmykJpegStream.Flush();
SaveMemoryStream(iccCmykJpegStream, "C:\\desertCMYK.jpg");
iccCmykJpegStream.Close();
}
private Stream GetStreamFromResource(string name)
{
return typeof(Program).Assembly.GetManifestResourceStream(name);
}
private Uri GetProfilePath(string name)
{
string folder = Path.GetDirectoryName(Assembly.GetAssembly(typeof(Program)).CodeBase);
return new Uri(Path.Combine(folder, name));
}
private void SaveMemoryStream(MemoryStream ms, string fileName)
{
FileStream outStream = File.OpenWrite(fileName);
ms.WriteTo(outStream);
outStream.Flush();
outStream.Close();
}
}
}
According to an MVP GDI+ can read CMYK but can't encode it (Source: http://www.pcreview.co.uk/forums/convert-rgb-image-cmyk-t1419911.html). They go on to say that using TIF as an intermediation format may be the way to go.
Other than that, you might try Graphics Mill imaging SDK for .NET at http://imaging.aurigma.com/ (I'm not affiliated with this company).
I know this isn't much of an answer, but hopefully it sheds some light and points you in the right direction.
You could have a look at this: Convert RGB color to CMYK?
Although this conversion is fairly subjective, hence the need for the ICC profile, it may be that you can extract that "factor" from the ICC and adjust the formula?
What is the context is which you need to convert the RGB values to CMYK?

How to group Windows API constants

When defining Windows API const values, is it better to have them as const
public const int SW_HIDE = 0;
public const int SW_SHOWNORMAL = 1;
public const int SW_NORMAL = 1;
public const int SW_SHOWMINIMIZED = 2;
public const int SW_SHOWMAXIMIZED = 3;
public const int SW_MAXIMIZE = 3;
public const int SW_SHOWNOACTIVATE = 4;
public const int SW_SHOW = 5;
public const int SW_MINIMIZE = 6;
public const int SW_SHOWMINNOACTIVE = 7;
public const int SW_SHOWNA = 8;
public const int SW_RESTORE = 9;
public const int SW_SHOWDEFAULT = 10;
public const int SW_MAX = 10;
[DllImport( "user32.dll" )]
public static extern bool ShowWindow( HandleRef hWnd, int nCmdShow );
or to group them together as an enum.
public enum SW {
SW_HIDE = 0,
SW_SHOWNORMAL = 1,
SW_NORMAL = 1,
SW_SHOWMINIMIZED = 2,
SW_SHOWMAXIMIZED = 3,
SW_MAXIMIZE = 3,
SW_SHOWNOACTIVATE = 4,
SW_SHOW = 5,
SW_MINIMIZE = 6,
SW_SHOWMINNOACTIVE = 7,
SW_SHOWNA = 8,
SW_RESTORE = 9,
SW_SHOWDEFAULT = 10,
SW_MAX = 10
}
[DllImport( "user32.dll" )]
public static extern bool ShowWindow( HandleRef hWnd, SW nCmdShow );
Group them as enums.
Why? Ints are used all over the place and you can pass them where, for example, a size is necessary as well.. That led to the frickin hungarian notation (szSomething..) in the first place. The type system was lacking and they tried to "fix" it using the variable naming scheme. You're now better off, with a better type system; use it.
Define enums, group them in a sensible way and you won't Thread.Sleep(WM_User) someday (Yes, I'm not completely serious with this example, but I think you get the point).
Except for code maintainability, it doesn't matter at all.
I recommend using an enum; this allows you to use IntelliSense when calling the function, and can help prevent mistakes.
However, you should give your enum a meaningful name, such as WindowShowType.
Also, you might want to remove the prefixes, and perhaps standardize the names to CamelCase.

Categories