Vosk settings to set script - .net-core

I am using below code block for Vosk speech-to-text from their example. Is there a way to set all text so the recognition became more accurate and maybe faster? I could not find any solid document on that one but found 2 things recognizer.Aligment and recognizer.SetKeywords but none of it is loaded from the .Net Core Vosk library I am using. Are they additional libraries or belonged to versions and are not supported now?
public static void DemoBytes(Model model)
{
// Demo byte buffer
VoskRecognizer rec = new VoskRecognizer(model, 16000.0f);
rec.SetMaxAlternatives(5);
rec.SetWords(true);
using(Stream source = File.OpenRead("test.wav")) {
byte[] buffer = new byte[4096];
int bytesRead;
while((bytesRead = source.Read(buffer, 0, buffer.Length)) > 0) {
if (rec.AcceptWaveform(buffer, bytesRead)) {
Console.WriteLine(rec.Result());
} else {
Console.WriteLine(rec.PartialResult());
}
}
}
Console.WriteLine(rec.FinalResult());
}

Related

Android 10 - unable to take PersistableUriPermission on a file that I created in getExternalFilesDir()

Using the below code snippet, we created a file in Android 10, in a sub-folder under getExternalFilesDir(). However, immediately after creation, if we try to take persistableUriPermission, it throws an exception "No such permission exists....".
We need that check to know if that file will be available for read later in a common utility, else we have to make a copy. Please let us know what we might be doing wrong and how to fix this. Appreciate your help.
ParcelFileDescriptor filePFD =
cxt.getContentResolver().openFileDescriptor(Uri.parse(pathFileToSend), "r");
FileDescriptor fd = filePFD.getFileDescriptor();
FileInputStream fIn = new FileInputStream(fd);
File fileBaseFolder = new File(Utils.GetRootDirectory().getAbsolutePath(), Utils.DESTINATION);
if (!fileBaseFolder.exists())
fileBaseFolder.mkdirs();
if (fileBaseFolder.exists()) {
File copyFile = new File(fileBaseFolder.getAbsolutePath(), nameOfFile);
FileOutputStream fOut = new FileOutputStream(copyFile);
byte data[] = new byte[4096];
long total = 0;
int count;
while ((count = fIn.read(data)) != -1) {
total += count;
fOut.write(data, 0, count);
}
fOut.close();
Uri copiedFileUri =
FileProvider.getUriForFile(cxt,
cxt.getString(R.string.file_provider_authority),
copyFile);
if (null != copiedFileUri)
{
try {
/*At this line, an exception is thrown - No persistable permissions exist.. */
cxt.getContentResolver().takePersistableUriPermission(copiedFileUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
} catch (Exception e) {
e.printStackTrace();
}
}
takePersistableUriPermission() is for Uri values that you get from the Storage Access Framework (e.g., ACTION_OPEN_DOCUMENT). It will not work for FileProvider. And, you do not need permissions to work with getExternalFilesDir() on Android 4.4 and higher.

Setting default TWAIN data source without using API UI menu

Using the twaindotnet library in C#, I'm wondering if there's a way to set the default datasource using the library.
As a feeble attempt, I've tried adding a SetDefault method to the DataSource class of twaindonet, like this
public static void SetDefault(Identity applicationId, IWindowsMessageHook messageHook, DataSource newDataSource)
{
var defaultSourceId = newDataSource.SourceId;
// Attempt to get information about the system default source
var result = Twain32Native.DsmIdentity(
applicationId,
IntPtr.Zero,
DataGroup.Control,
DataArgumentType.Identity,
Message.Set,
defaultSourceId);
if (result != TwainResult.Success)
{
var status = DataSourceManager.GetConditionCode(applicationId, null);
throw new TwainException("Error getting information about the default source: " + result, result, status);
}
}
which is called from the DataSourceManage class like this
public void SelectSource(DataSource dataSource)
{
DataSource.Dispose();
DataSource.SetDefault(ApplicationId, _messageHook, dataSource);
}
But when I try to use SetDefault, Twain32Native.DsmIdentity always results in Failure being returned.
I basically copied from SetDefault the setDefaultDataSource method from TWAIN sample Data Source and Application
pTW_IDENTITY TwainApp::setDefaultDataSource(unsigned int _index)
{
if(m_DSMState < 3)
{
cout << "You need to open the DSM first." << endl;
return NULL;
}
else if(m_DSMState > 3)
{
PrintCMDMessage("A source has already been opened, please close it first\n");
return NULL;
}
if(_index >= 0 && _index < m_DataSources.size())
{
m_pDataSource = &(m_DataSources[_index]);
// set the specific data source
TW_UINT16 twrc;
twrc = _DSM_Entry(
&m_MyInfo,
0,
DG_CONTROL,
DAT_IDENTITY,
MSG_SET,
(TW_MEMREF) m_pDataSource);
switch (twrc)
{
case TWRC_SUCCESS:
break;
case TWRC_FAILURE:
printError(0, "Failed to get the data source info!");
break;
}
}
else
{
return NULL;
}
return m_pDataSource;
}
Any help would be greatly appreciated.
The possible cause is that the version of your TWAIN DSM is too low. Only DSM 2.0 or above supports setting default TWAIN data source.

Encrypted mp3 streaming to Flash SWF

I have an asp.net web site that serves sample MP3 files to client Flash Players (SWF).
These files are downloadable by tons of download tools.
Although only registered members can access the high quality mp3 samples, my client wants to prevent these low quality MP3 files to be downloaded by download tools.
So I thought about this solution:
Convert these MP3 files to bytearrays on server side (ASP.NET)
Do some bitwise XOR operations (Simple encryption)
Write this array to aspx' responsestream
Modify Flash (.fla) to request to this new file/page/aspx
Do some bitwise XOR operations on Flash and convert it to the original MP3 as byte array. (Simple decryption)
Play the MP3
I was able to succeed till step 6. I cannot convert this byte array to a Sound object that Flash can play. I did a bit by bit comparison of the resulting array on the flash and the source array on ASP.NET. They are equal.
I'm open to completely different approaches. But I cannot use Flash Media Server. I need to be using Flash as3 and ASP.NET.
Also very important! The .mp3 must be downloaded/decrypted and played asynchronously (which I coud not succeed in doing)
I agree with Peter Elliot that authentication probably is the easiest way to restrict access to the files. However, if you still need to explore the route of encrypting the files, I thought I'd expand a bit on Alex Vlad's answer.
What you need to do in order to be able to stream the audio file, decrypt it on the fly, and play it asynchronously is to use the URLStream class (docs) in conjunction with the Sound class (docs) and keeping a buffer of the partially downloaded content.
Some pseudocode to illustrate:
class AsyncEncryptedSoundPlayer extends Sound {
var buffer:ByteArray;
var stream:URLStream;
var currSoundPosition:uint = 0;
public function AsyncEncryptedSoundPlayer(url:String) {
buffer = new ByteArray();
stream = new URLStream();
stream.addEventListener(ProgressEvent.PROGRESS, onProgress);
stream.load(new URLRequest(url));
addEventListener(SampleDataEvent.SAMPLE_DATA, onSampleDataRequested);
}
function onProgress(e:ProgressEvent):void {
var tmpData:ByteArray;
stream.readBytes(tmpData, buffer.length, stream.bytesAvailable - buffer.length);
var decryptedData:ByteArray = decryptData(tmpData); // Decrypt loaded data
buffer.writeBytes(decryptedData, buffer.length, decryptedData.length); // Add decrypted data to buffer
}
function onSampleDataRequested(e:ProgressEvent):void {
// Feed samples from the buffer to the Sound instance
// You may have to pause the audio to increase the buffer it the download speed isn't high enough
event.data.writeBytes(buffer, currSoundPosition, 2048);
currSoundPosition += 2048;
}
function decryptedData(data:ByteArray):void {
// Returns decrypted data
}
}
This is obviously a very rough outline of a class, but I hope it will point you in the right direction.
#walkietokyo, thanks a lot for pointing me to the right direction. I succeeded in doing what I wanted. The keyword here was the loadCompressedDataFromByteArray function.
After tens of trial and errors I found out that loadCompressedDataFromByteArray was working in a differential manner.
It appends anything that it converts to the end of the sound object data.
Another issue: sound object doesn't continue playing the parts appended by loadCompressedDataFromByteArray after its play function is called.
So I implemented a sort of double buffering. Where I use 2 sound objects interchangeably.
My final (test) version is listed below. With the encryption (obfuscation) method I used (a simple XOR) no download manager or grabber or sniffer that I tested was able to play the Mp3s.
Flash (Client) side:
import flash.events.DataEvent;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.OutputProgressEvent;
import flash.events.ProgressEvent;
import flash.net.URLRequest;
import flash.net.URLStream;
import flash.utils.ByteArray;
import flashx.textLayout.formats.Float;
var buffer:ByteArray;
var stream:URLStream;
var bufferReadPosition:uint = 0;
var bufferWritePosition:uint = 0;
var url:String = "http://www.blablabla.com/MusicServer.aspx?" + (new Date());
buffer = new ByteArray();
stream = new URLStream();
stream.addEventListener(ProgressEvent.PROGRESS, onProgress);
stream.load(new URLRequest(url));
var s1:Sound = new Sound();
var s2:Sound = new Sound();
var channel1:SoundChannel;
var channel2:SoundChannel;
var pausePosition:int = 0;
var aSoundIsPlaying:Boolean = false;
var lastLoadedS1:Boolean = false;
var lastS1Length:int = 0;
var lastS2Length:int = 0;
function onProgress(e:ProgressEvent):void {
var tmpData:ByteArray = new ByteArray();
stream.readBytes(tmpData, 0, stream.bytesAvailable);
var decryptedData:ByteArray = decryptData(tmpData); // Decrypt loaded data
buffer.position = bufferWritePosition;
buffer.writeBytes(decryptedData, 0, decryptedData.length); // Add decrypted data to buffer
bufferWritePosition += decryptedData.length;
if(lastLoadedS1)
{
buffer.position = lastS2Length;
s2.loadCompressedDataFromByteArray(buffer, buffer.length - lastS2Length);
lastS2Length = buffer.length;
}
else
{
buffer.position = lastS1Length;
s1.loadCompressedDataFromByteArray(buffer, buffer.length - lastS1Length);
lastS1Length = buffer.length;
}
if(!aSoundIsPlaying)
{
DecidePlay();
}
}
function channel1Completed(e:Event):void
{
DecidePlay();
}
function channel2Completed(e:Event):void
{
DecidePlay();
}
function DecidePlay():void
{
aSoundIsPlaying = false;
if(lastLoadedS1)
{
channel1.stop();
if(s2.length - s1.length > 10000)
{
//At least a 10 second buffer
channel2 = s2.play(s1.length);
channel2.addEventListener(Event.SOUND_COMPLETE, channel2Completed);
lastLoadedS1 = false;
aSoundIsPlaying = true;
}
}
else
{
if(channel2 != null)
{
channel2.stop();
}
if(s1.length - s2.length > 10000)
{
//At least a 10 second buffer
channel1 = s1.play(s2.length);
channel1.addEventListener(Event.SOUND_COMPLETE, channel1Completed);
lastLoadedS1 = true;
aSoundIsPlaying = true;
}
}
}
function decryptData(data:ByteArray):ByteArray {
for(var i:int = 0;i<data.length;i++)
{
//Here put in your bitwise decryption code
}
return data;
}
ASP.NET server side (MusicServer.aspx):
protected void Page_Load(object sender, EventArgs e)
{
CopyStream(Mp3ToStream(Server.MapPath("blabla.mp3")), Response.OutputStream);
this.Response.AddHeader("Content-Disposition", "blabla.mp3");
this.Response.ContentType = "audio/mpeg";
this.Response.End();
}
public static void CopyStream(Stream input, Stream output)
{
byte[] buffer = new byte[32768];
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
for (int i = 0; i < read; i++)
{
//Here put in your bitwise encryption code
}
output.Write(buffer, 0, read);
}
}
public Stream Mp3ToStream(string filePath)
{
using (FileStream fileStream = File.OpenRead(filePath))
{
MemoryStream memStream = new MemoryStream();
memStream.SetLength(fileStream.Length);
fileStream.Read(memStream.GetBuffer(), 0, (int)fileStream.Length);
return memStream;
}
}
what might be simpler than encrypting the data coming back from your service is instead authenticating requests so that only your swf can request the files.
You can accomplish this in the same way that say, the Amazon APIs work: build a request that includes a number of parameters, including a timestamp. hash all of these arguments together in an HMAC (HMAC-SHA256 is available in the as3crypto library) along with a private key embedded in your swf. Your server end authenticates this request, ensuring that the hash is valid and that it is close enough to the timestamp. Any requests with a bad hash, or using a request with a timestamp too far in the past (replay attack) are denied.
This is certainly not perfect security. Any sufficiently motivated user could disassemble your swf and pull out your auth key, or grab the mp3 from their browser cache. But then again, any mechanism you are going to use will have those issues. This removes the overhead of having to encrypt and decrypt all of your files, instead moving the work over to the request generation phase.
Flash Sound supports only streaming mp3 playing that is you can play only mp3 by direct link. But you can send swf file with embeded mp3 withing it and this swf can be encrypted in the same way as you encrypt mp3.
as3 code for embedding and using mp3:
public class Sounds
{
[Embed(source="/../assets/sounds/sound1.mp3")]
private static const sound1:Class;
}
after loading this swf by the Loader you can access to the sound in this way:
var domain:ApplicationDomain = ApplicationDomain.currentDomain; // <-- ApplicationDomain where you load sounds.swf
var soundClass:Class = domain.getDefinition("Sounds_sound1");
var sound:Sound = new soundClass();
sound.play();
Be sure, that you do at least one of the follows:
give different names for sound class (sound1)
give different name for holder class (Sounds)
or load sound.swf into different application domains
to prevent class names overlapping.
Unfortunate this approach doesn't allow you to streaming play sound, you have to load whole swf, decrypt it and only after that you will be able to play sound.
please have a look here:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/events/SampleDataEvent.html
and here:
http://help.adobe.com/en_US/as3/dev/WSE523B839-C626-4983-B9C0-07CF1A087ED7.html

Raven DB DocumentStore - throws out of memory exception

I have code like this:
public bool Set(IEnumerable<WhiteForest.Common.Entities.Projections.RequestProjection> requests)
{
var documentSession = _documentStore.OpenSession();
//{
try
{
foreach (var request in requests)
{
documentSession.Store(request);
}
//requests.AsParallel().ForAll(x => documentSession.Store(x));
documentSession.SaveChanges();
documentSession.Dispose();
return true;
}
catch (Exception e)
{
_log.LogDebug("Exception in RavenRequstRepository - Set. Exception is [{0}]", e.ToString());
return false;
}
//}
}
This code gets called many times. After i get to around 50,000 documents that have passed through it i get an OutOfMemoryException.
Any idea why ? perhaps after a while i need to declare a new DocumentStore ?
thank you
**
UPDATE:
**
I ended up using the Batch/Patch API to perform the update I needed.
You can see the discussion here: https://groups.google.com/d/topic/ravendb/3wRT9c8Y-YE/discussion
Basically since i only needed to update 1 property on my objects, and after considering ayendes comments about re-serializing all the objects back to JSON, i did something like this:
internal void Patch()
{
List<string> docIds = new List<string>() { "596548a7-61ef-4465-95bc-b651079f4888", "cbbca8d5-be45-4e0d-91cf-f4129e13e65e" };
using (var session = _documentStore.OpenSession())
{
session.Advanced.DatabaseCommands.Batch(GenerateCommands(docIds));
}
}
private List<ICommandData> GenerateCommands(List<string> docIds )
{
List<ICommandData> retList = new List<ICommandData>();
foreach (var item in docIds)
{
retList.Add(new PatchCommandData()
{
Key = item,
Patches = new[] { new Raven.Abstractions.Data.PatchRequest () {
Name = "Processed",
Type = Raven.Abstractions.Data.PatchCommandType.Set,
Value = new RavenJValue(true)
}}});
}
return retList;
}
Hope this helps ...
Thanks alot.
I just did this for my current project. I chunked the data into pieces and saved each chunk in a new session. This may work for you, too.
Note, this example shows chunking by 1024 documents at a time, but needing at least 2000 before we decide it's worth chunking. So far, my inserts got the best performance with a chunk size of 4096. I think that's because my documents are relatively small.
internal static void WriteObjectList<T>(List<T> objectList)
{
int numberOfObjectsThatWarrantChunking = 2000; // Don't bother chunking unless we have at least this many objects.
if (objectList.Count < numberOfObjectsThatWarrantChunking)
{
// Just write them all at once.
using (IDocumentSession ravenSession = GetRavenSession())
{
objectList.ForEach(x => ravenSession.Store(x));
ravenSession.SaveChanges();
}
return;
}
int numberOfDocumentsPerSession = 1024; // Chunk size
List<List<T>> objectListInChunks = new List<List<T>>();
for (int i = 0; i < objectList.Count; i += numberOfDocumentsPerSession)
{
objectListInChunks.Add(objectList.Skip(i).Take(numberOfDocumentsPerSession).ToList());
}
Parallel.ForEach(objectListInChunks, listOfObjects =>
{
using (IDocumentSession ravenSession = GetRavenSession())
{
listOfObjects.ForEach(x => ravenSession.Store(x));
ravenSession.SaveChanges();
}
});
}
private static IDocumentSession GetRavenSession()
{
return _ravenDatabase.OpenSession();
}
Are you trying to save it all in one call?
The DocumentSession need to turn all of the objects that you pass it into a single request to the server. That means that it may allocate a lot of memory for the write to the server.
Usually we recommend on batches of about 1,024 items in you are doing bulks saves.
DocumentStore is a disposable class, so I worked around this problem by disposing the instance after each chunk. I highly doubt this is the most efficient way to run operations, but it will prevent significant memory overhead from happening.
I was running a sort of "delete all" operation like so. You can see the using blocks disposing both the DocumentStore and the IDocumentSession objects after each chunk.
static DocumentStore GetDataStore()
{
DocumentStore ds = new DocumentStore
{
DefaultDatabase = "test",
Url = "http://localhost:8080"
};
ds.Initialize();
return ds;
}
static IDocumentSession GetDbInstance(DocumentStore ds)
{
return ds.OpenSession();
}
static void Main(string[] args)
{
do
{
using (var ds = GetDataStore())
using (var db = GetDbInstance(ds))
{
//The `Take` operation will cap out at 1,024 by default, per Raven documentation
var list = db.Query<MyClass>().Skip(deleteSum).Take(5000).ToList();
deleteCount = list.Count;
deleteSum += deleteCount;
foreach (var item in list)
{
db.Delete(item);
}
db.SaveChanges();
list.Clear();
}
} while (deleteCount > 0);
}

How to identify CMYK images in ASP.NET using C#

Does anybody know how to properly identify CMYK images in ASP.NET using C#? When I check the Flags attribute of a Bitmap instance, I get incorrect results.
I have created three images to test this: cmyk.jpg, rgb.jpg and gray.jpg. These are respectively CMYK, RGB and Grayscale images.
This is my test code:
static void Main(string[] args)
{
Bitmap bmpCMYK = new Bitmap("cmyk.jpg");
Bitmap bmpRGB = new Bitmap("rgb.jpg");
Bitmap bmpGray = new Bitmap("gray.jpg");
Console.WriteLine("\t\tRgb\tCmyk\tGray\tYcbcr\tYcck\tPixelFormat");
Console.WriteLine("cmyk.jpg\t{0}\t{1}\t{2}\t{3}\t{4}\t{5}",
IsSet(bmpCMYK, System.Drawing.Imaging.ImageFlags.ColorSpaceRgb),
IsSet(bmpCMYK, System.Drawing.Imaging.ImageFlags.ColorSpaceCmyk),
IsSet(bmpCMYK, System.Drawing.Imaging.ImageFlags.ColorSpaceGray),
IsSet(bmpCMYK, System.Drawing.Imaging.ImageFlags.ColorSpaceYcbcr),
IsSet(bmpCMYK, System.Drawing.Imaging.ImageFlags.ColorSpaceYcck),
bmpCMYK.PixelFormat);
Console.WriteLine("rgb.jpg\t\t{0}\t{1}\t{2}\t{3}\t{4}\t{5}",
IsSet(bmpRGB, System.Drawing.Imaging.ImageFlags.ColorSpaceRgb),
IsSet(bmpRGB, System.Drawing.Imaging.ImageFlags.ColorSpaceCmyk),
IsSet(bmpRGB, System.Drawing.Imaging.ImageFlags.ColorSpaceGray),
IsSet(bmpRGB, System.Drawing.Imaging.ImageFlags.ColorSpaceYcbcr),
IsSet(bmpRGB, System.Drawing.Imaging.ImageFlags.ColorSpaceYcck),
bmpRGB.PixelFormat);
Console.WriteLine("gray.jpg\t{0}\t{1}\t{2}\t{3}\t{4}\t{5}",
IsSet(bmpGray, System.Drawing.Imaging.ImageFlags.ColorSpaceRgb),
IsSet(bmpGray, System.Drawing.Imaging.ImageFlags.ColorSpaceCmyk),
IsSet(bmpGray, System.Drawing.Imaging.ImageFlags.ColorSpaceGray),
IsSet(bmpGray, System.Drawing.Imaging.ImageFlags.ColorSpaceYcbcr),
IsSet(bmpGray, System.Drawing.Imaging.ImageFlags.ColorSpaceYcck),
bmpGray.PixelFormat);
bmpCMYK.Dispose();
bmpRGB.Dispose();
bmpGray.Dispose();
Console.ReadLine();
}
private static bool IsSet(Bitmap bitmap, System.Drawing.Imaging.ImageFlags flag)
{
return (bitmap.Flags & (int)flag) == (int)flag;
}
This produces the following output:
I have checked the actual images and cmyk.jpg really is a CMYK image.
Apparently, this is a "known issue". Alex Gil had the same problem in WPF (see this question: How to identify CMYK images using C#) and he managed to solve it by using a BitmapDecoder class to load the images. I'm a bit uncomfortable using that solution in ASP.NET because it requires me to add references to WindowsBase.dll and PresentationCore.dll and I'm not sure I want those in a web project.
Does anyone know of any other pure .NET solutions to check if an image is in the CMYK format that I can safely use in ASP.NET?
I use a combination of the ImageFlags and PixelFormat values. Note that PixelFormat.Forma32bppCMYK is missing from .NET - I grabbed it out of GdiPlusPixelFormats.h in the Windows SDK.
The trick is that Windows 7 and Server 2008 R2 returns the correct pixel format but is missing the image flags. Vista and Server 2008 return an invalid pixel format but the correct image flags. Insanity.
public ImageColorFormat GetColorFormat(this Bitmap bitmap)
{
const int pixelFormatIndexed = 0x00010000;
const int pixelFormat32bppCMYK = 0x200F;
const int pixelFormat16bppGrayScale = (4 | (16 << 8);
// Check image flags
var flags = (ImageFlags)bitmap.Flags;
if (flags.HasFlag(ImageFlags.ColorSpaceCmyk) || flags.HasFlag(ImageFlags.ColorSpaceYcck))
{
return ImageColorFormat.Cmyk;
}
else if (flags.HasFlag(ImageFlags.ColorSpaceGray))
{
return ImageColorFormat.Grayscale;
}
// Check pixel format
var pixelFormat = (int)bitmap.PixelFormat;
if (pixelFormat == pixelFormat32bppCMYK)
{
return ImageColorFormat.Cmyk;
}
else if ((pixelFormat & pixelFormatIndexed) != 0)
{
return ImageColorFormat.Indexed;
}
else if (pixelFormat == pixelFormat16bppGrayScale)
{
return ImageColorFormat.Grayscale;
}
// Default to RGB
return ImageColorFormat.Rgb;
}
public enum ImageColorFormat
{
Rgb,
Cmyk,
Indexed,
Grayscale
}
An idea: If you dont want to reference those dll's in your web project, you could do the processing outside the web project, in a service, which may be better anyway?
You might check out FreeImage which is a win32 DLL but has a .NET wrapper, I am using it in a production enviroment and it's great.
I would be surprised if it couldn't provide this information.
(edit) I didn't notice before you asked for pure .NET solutions - so maybe this won't work - but I have found it a useful supplement to the limitations of the .NET framework for image manipulation.
Another idea, if you only need to identify the format, is to extract that directly from the file. I have no idea how complex the specification for the JPEG format might be, but hey, it's only 29 pages!
As previously answered, the most reliable way will be to parse the file's header to retrieve this data.
So here is how I solved the issue you were having which was the same as what I was having. Everything in csharp looks to return rgb info when you know it's a 100% a cymk image. So what to do, well go to the root and read the file. Here is what I had done and tested to work well and should cover all OS's, and 50 for 50 imgs tested right. This is 2.0 too just in case.
public bool isByteACMYK(Stream image)
{
using (StreamReader sr = new StreamReader(image))
{
string contents = sr.ReadToEnd();
if (contents.ToLower().Contains("cmyk"))
{
return true;
}
}
return false;
}
public bool isFileACMYKJpeg(System.Drawing.Image image)
{
System.Drawing.Imaging.ImageFlags flagValues = (System.Drawing.Imaging.ImageFlags)Enum.Parse(typeof(System.Drawing.Imaging.ImageFlags), image.Flags.ToString());
if (flagValues.ToString().ToLower().IndexOf("ycck") == -1)
{
// based on http://www.maxostudio.com/Tut_CS_CMYK.cfm
bool ret = false;
try{
int cmyk = (image.Flags & (int)ImageFlags.ColorSpaceCmyk);
int ycck = (image.Flags & (int)ImageFlags.ColorSpaceYcck);
ret = ((cmyk > 0) || (ycck > 0));
} catch (Exception ex){
}
return ret;
}
return true;
}
// my upload test .. but you could turn a file to stream and do the same
public void UpdatePool(HttpPostedFile newimage)
{
if (newimage.ContentLength != 0)
{
Stream stream = newimage.InputStream;
MemoryStream memoryStream = new MemoryStream();
CopyStream(stream,memoryStream);
memoryStream.Position = 0;
stream = memoryStream;
System.Drawing.Image processed_image = null;
processed_image = System.Drawing.Image.FromStream(newimage.InputStream);
if (imageService.isFileACMYKJpeg(processed_image) || imageService.isByteACMYK(stream))
{
Flash["error"] = "You have uploaded a CMYK image. Please conver to RGB first.";
RedirectToReferrer();
return;
}
}
}
cheers - Jeremy
I was under the assumption that everything in .NET was based on RGB, aRGB and grayscale (as grayscale is RGB(128, 128, 128)).
If my assumption is correct then you will have to go the third party route.

Resources