Issues converting Adobe Ai and Psd files using Magick - c#

I'm using Magick to convert Adobe files (Pdf, Ai, Psd) to Png images and it all works fine except that the Ai files can take over a minute to convert and Psd files lose their shape when converted, as the layers are laid out side by side instead of overlaying each other. This is the code I am using..
MagickReadSettings settings = new MagickReadSettings();
settings.Density = new Density(300);
using (MagickImageCollection images = new MagickImageCollection())
{
images.Read(file, settings);
using (MagickImage horizontal = images.AppendHorizontally())
{
file = path + "\\" + ThumbnailFolder + "\\TempThumb.Png";
horizontal.Write(path + "\\" + ThumbnailFolder + "\\TempThumb.Png");
}
}
Are there changes I can make in the Settings to fix these issues?

I've had some help to fix this issue which I want to share in case anyone has a similar problem. Firstly the .ai files are taking so long because of the detailed resolution set out in my settings, reduce the resolution and they are created faster. Secondly, the Psd files are being created as they are because I'm appending them using the Horizontal method. When I changed my code to the code below it worked.
using (MagickImageCollection images = new MagickImageCollection())
{
images.Read(file, settings);
images.Write(path + "\\" + ThumbnailFolder + "\\TempThumb.png");
}

Related

Batch Image Manipulation keeps hanging

I use the following code to scale and crop all images in a folder.
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(file);
string fileExtension = Path.GetExtension(file);
string filePath = Path.GetDirectoryName(file);
string newFileName = string.Empty;
long fileSize = new FileInfo(file).Length;
if (fileSize > fileSizeLimit)
{
string tempFile = System.IO.Path.GetTempFileName();
File.Copy(file, tempFile, true);
Bitmap sourceImage = (Bitmap)System.Drawing.Image.FromFile(tempFile);
System.Drawing.Image imgPhoto = ScaleCrop(sourceImage, sourceImage.Width / 4, sourceImage.Height / 4, AnchorPosition.Top);
Bitmap bitImage = new Bitmap(imgPhoto);
File.Delete(file);
newFileName = filePath + "\\" + fileNameWithoutExtension + "_" + DateTime.Now.ToString("yyyyMMddHHmmss") + "_" + CoilWarehouseProcessed + fileExtension;
bitImage.Save(newFileName, System.Drawing.Imaging.ImageFormat.Jpeg);
imgPhoto.Dispose();
bitImage.Dispose();
}
If I run the application locally (in debug mode in VS2010) and point it to a network drive then all images are processed every time.
If I run it from a our local webserver the problem is that the app may process no images, it may process 5, it may process 1, it never does all of the images in a given folder, only ever some of them... then it hangs in the clients browser.
There are no events to view via the event log... the application does not crash or error in anyway... the fact that it will process an image proves it's not a permissions issue.
Any ideas why this is happening?
EDIT: Thanks to wazdev, but I ended up testing a less intrusive (and also don't like dependencies relying on 3rd party software) solution, and it all seems good so far... Basically I changed it so that when it copies the stream to produce a new image 'System.Drawing.Image imgPhoto = ...' to use a using statement to ensure that the 'temp' image is disposed of. I also moved the delete of the original (uncropped / unscaled image) file to be the last operation (In tests it has worked fine, only time will tell once more users come online and concurrency is tested):
string tempFile = System.IO.Path.GetTempFileName();
File.Copy(file, tempFile, true);
Bitmap sourceImage = (Bitmap)System.Drawing.Image.FromFile(tempFile);
System.Drawing.Image imgPhoto = ScaleCrop(sourceImage, sourceImage.Width / 4, sourceImage.Height / 4, AnchorPosition.Top);
Bitmap bitImage;
using (var bmpTemp = new Bitmap(imgPhoto))
{
bitImage = new Bitmap(bmpTemp);
}
newFileName = filePath + "\\" + fileNameWithoutExtension + "_" + DateTime.Now.ToString("yyyyMMddHHmmss") + "_" + CoilWarehouseProcessed + fileExtension;
bitImage.Save(newFileName, System.Drawing.Imaging.ImageFormat.Jpeg);
imgPhoto.Dispose();
bitImage.Dispose();
File.Delete(file);
EDIT2: It's been live now for a few days and i've tested it every day and it is working well.. Here's all that I did;
Basically inside the ScaleCrop() call there was a GC.Collect and a Wait For Pending Finalisers() call. I removed the wait for pending call and moved the GC.Collect() to after the File.Delete().
I've seen this behaviour in the past when RAM was exhausted resulting in paging to disk. I've found a great deal of success in utilising the ImageResizing.net libraries:
http://imageresizing.net/
I updated my code to use this library and have never looked back.
HTH
(I have no affiliation with imageresizing.net - I'm just a very happy user)

Web image as tile from local storage

I'm currently trying to download an image, save it to a folder within the LocalStorage container, and then use it as tile. However, everytime I try to do so, the tile is just blank. All there is the name of the app and a title.
I'm unable to test if this occurs because the image isn't saved correctly or because the URI is incorrect.
var localFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
var channelFolder = await localFolder.CreateFolderAsync(_currentChannel.Name, CreationCollisionOption.OpenIfExists);
var thumbnail = RandomAccessStreamReference.CreateFromUri(new Uri(_currentChannel.Logo));
var remoteFile = await StorageFile.CreateStreamedFileFromUriAsync("profilePicture.jpeg", new Uri(_currentChannel.Logo), thumbnail);
await remoteFile.CopyAsync(channelFolder, "profilePicture.jpeg", NameCollisionOption.ReplaceExisting);
string tileXmlString = "<tile>"
+ "<visual>"
+ "<binding template='TileSquareText04'>"
+ "<image id='1' src='ms-appdata:///local/" +_currentChannel.Name + "/profilePicture.jpeg'>" + "</image>"
+ "<text id='1'>" + "Latest Image" + "</text>"
+ "</binding>"
+ "</visual>"
+ "</tile>";
Windows.Data.Xml.Dom.XmlDocument tileDOM = new Windows.Data.Xml.Dom.XmlDocument();
tileDOM.LoadXml(tileXmlString);
TileNotification tile = new TileNotification(tileDOM);
TileUpdateManager.CreateTileUpdaterForApplication().Update(tile);
_currentChannel.Logo is a string with a url to a jpeg image.
I end up with a transparent tile every time.
After the code runs, you should be able to see if the image is in your \AppData\Microsoft\Packages\\Local folder. If not, then there's a problem downloading it. If it's there, make sure it's both 200KB or less and 1024px or smaller in both dimensions. Those are the limits for tile images which, if exceeded, will cause the image to not appear. In that case you'll need to resample the image.
You should also test your tile updating code separately with a known small image, e.g. something in the package using an ms-appx URI or a remote image with an http URI. If those don't work either, then your updating code is suspect. Check for any errors or exceptions from that section of your code.

Writing to text files using SaveFileDialog

I'm working on an Add In for Microsoft Excel in Visual Studio that records the balances for each account (or Worksheet) and saves them to a user-specified file. The ability to press a button and select a destination to save your work is an essential skill for any programmer, so I'm perplexed as to why there is so little information on how to do it. The closest thing I found was a tutorial on MSDN that saves a button icon image.
The code I'm currently using is as follows:
StringBuilder sb = new StringBuilder();
if (ThisAddIn.createdbudget)
{
string budget = "Budget = " + ThisAddIn.blake.budget;
SaveFileDialog savebudget = new SaveFileDialog();
savebudget.Filter = "Data files (*.dat)|*.dat|All files (*.*)|*.*";
savebudget.Title = "Save Budget";
savebudget.ShowDialog();
if (savebudget.FileName != "")
{
using (StreamWriter sr = new StreamWriter(savebudget.OpenFile()))
{
sb.AppendLine(budget);
}
}
}
else
{
MessageBox.Show("Control disabled. Budget does not yet exist.");
}
My objective is to allow the user to designate a file path via SaveFileDialog and save a new .dat (or .txt). The stream writer would record the account names and their respective balances line by line. Something like:
sr.WriteLine(Account1.Name + " Balance = " + Account1.Balance);
sr.WriteLine(Account2.Name + " Balance = " + Account2.Balance);
etc...
I know this sounds complicated. I have no problem saving data if I'm using a predetermined file path, but that's not very helpful. What I need to know is how to properly write files using SaveFileDialog.

How to convert PDF file pages to jpg image using imagemagick in asp.net

I'm searching for converting each page of the PDF to JPEG.
I found the below code from the following link:
http://imagemagick.codeplex.com/discussions/257915
here are two ways to convert a pdf to an image. You can either read all the images at once or just read one image. For this to work you need to have ghostscript installed.
using (ImageList imageList = new ImageList())
{
imageList.ReadImages(inputFile);
int pageIndex = 0;
foreach (Image page in imageList)
{
page.Write(outputDirectory + "\\Page." + pageIndex + ".jpg");
pageIndex++;
}
}
using (Image firstPage = new Image())
{
firstPage.Read(inputFile + "[0]");
firstPage.Write(outputDirectory + "\\FirstPage.jpg");
}
Here the imagelist class is not recognizing. I have added the DLL. Do u have any worked samples?Also Ghostscript download is an EXE file but not DLL?

Trouble playing mp3s after id3 image edit

Due to hardware restrictions, the software we produce tries to ensure that any audio file it imports into it's library (ready to be copied onto the hardware) is an acceptable bit rate.
Recently we've started using FFmpeg to convert a number of different audio types to mp3 to allow them to be imported and used on our hardware. Whilst the conversion works fine and the mp3 files work on our hardware afterwards, we're having issues specifically when adding an album art to the ID3 tags of the mp3. The track will not play audio in our software. It also seems that Windows cannot pick up the values of the ID3 tags in explorer, but Windows Media Player will still play the track.
This problem only seems to occur when changing a newly converted mp3s' ID3 tags after using FFmpeg. Changing tags on mp3s from other sources or those that have already got ID3 tag album art is fine.
The code for using FFmpeg from our software is as follows:
private const string SAMPLE_RATE = "44100";
...
//create temp file for output
outFile = Path.GetTempFileName();
outFile = Path.ChangeExtension(outFile, "mp3");
if (!File.Exists(inFile))
return false;
string metadata = (inFile.EndsWith("mp3")) ? " " : " -map_meta_data 0:0 ";
//build process
string workingDirectory = Environment.CurrentDirectory;
ProcessStartInfo FFmpegProcessInfo = new ProcessStartInfo();
FFmpegProcessInfo.WorkingDirectory = workingDirectory;
FFmpegProcessInfo.FileName = "ffmpeg.exe";
FFmpegProcessInfo.Arguments = "-i \"" + inFile + "\"" + " -ar "+SAMPLE_RATE + metadata + "\"" + outFile + "\""; //default conversion to SAMPLE_RATE
FFmpegProcessInfo.CreateNoWindow = true; //hide from user
//let us grab the output
FFmpegProcessInfo.RedirectStandardError = true;
FFmpegProcessInfo.RedirectStandardOutput = true;
FFmpegProcessInfo.UseShellExecute = false;
Process p = Process.Start(FFmpegProcessInfo);
To change the ID3 tags we have started using TagLib-Sharp and the code for changing the ID3 tags is:
public void SetId3Tags(string path, Bitmap image, IDictionary<string, string> values)
{
FileInfo fileInfo = new FileInfo(path);
fileInfo.Attributes = FileAttributes.Normal;
try
{
TagLib.File tagFile = TagLib.File.Create(path);
if (values.ContainsKey("Title"))
tagFile.Tag.Title = values["Title"];
if (values.ContainsKey("Artist"))
tagFile.Tag.Performers = new string[1] { values["Artist"] };
if (values.ContainsKey("Comments"))
tagFile.Tag.Comment = values["Comments"];
if (image != null) {
string tmpImg = Path.GetTempFileName();
image.Save(tmpImg);
IPicture newArt = new Picture(tmpImg);
tagFile.Tag.Pictures = new IPicture[1] {newArt};
}
tagFile.Save();
}
catch (Exception e)
{
_logger.Log(e);
}
}
And the code used to play the track in the software (FilgraphManager in QuartzTypeLib):
public void Play()
{
if (!_isPaused)
{
_graphManager = new FilgraphManager();
_mp3control = (IMediaControl)_graphManager;
_mp3position = (IMediaPosition)_graphManager;
_tempFile = Path.GetTempFileName();
File.Copy(_fullPath, _tempFile, true);
_mp3control.RenderFile(_tempFile);
}
else
{
_isPaused = false;
}
_mp3control.Run();
}
And the error when executing _mp3control.RenderFile(_tempFile):
{System.Runtime.InteropServices.ExternalException} = {"Exception from HRESULT: 0x80040266"}
at QuartzTypeLib.FilgraphManagerClass.RenderFile(String strFilename)
My largest problem here is that I don't know whether the fault lies with (our implementation of) FFmpeg (large library that's used fine in many other places), TagLib-Sharp or the audio playing.
Edit 1: Following J. Andrew Laughlin's advice I've been looking at the differences of the ID3 tags in the hex of each file. This is what I've found:
The initial input is ID3v2.3. After re-encoding with FFmpeg, the ID3 data is v2.4. This initial re-encoded file plays fine in media players and our software. Using TagLib# in our software to add album art keeps ID3v2.4 but the tags are only available using TagLib# to read them and it only plays in media players such as Windows Media Player. Using another tool to change the ID3 tags (in this case AudioShell Tag Editor) and add the same album art changed the ID3 version to 2.3 and meant that the mp3 played on our softwares audio player as well as other media players - However changing the tags afterwards produces an exception when saving the image.
One other thing I tried was to rip out the ID3v2.4 block completely after the re-encoding, this plays (as you'd expect) in all media players. When using the TagLib# on this untagged file, the tags were correctly applied (v2.3) and it continued to play properly in our software as well as others.
Unless anyone can suggest an elegant solution (either force TagLib# to write a new ID3v2.3 block or stop FFmpeg from writing one at all) I think I may just programmatically remove the ID3v2.4 block from the file after encoding and then write a new one.
TagLib# can be used to "downgrade" an ID3 tag from 2.4 to 2.3. I personally prefer to convert my ID3 tags to 2.3 since it is more consistently adopted across music players.
It's been a while, but I believe you can use the following in your above code:
TagLib.Id3v2.Tag id3v2tag = tagFile.GetTag(TagLib.TagTypes.Id3v2, false);
if(id3v2tag != null)
id3v2tag.Version = 3;
tagFile.Save();
Alternatively, you can force all tags to render in 2.3 by using the following code when your application initializes:
TagLib.Id3v2.Tag.DefaultVersion = 3;
TagLib.Id3v2.Tag.ForceDefaultVersion = true;
TagLib# can also remove tags completely and re-add them, but it shouldn't have to come to that.
Good luck!

Categories

Resources