Hearing Clipping after using NAudio MixingSampleProvider - naudio

I'm hoping someone can help me. I am using NAudio and am recording from multiple wsapiloopbackcapture devices and mixing them together. None of this can be written to disk, so I am doing it all in memory and am ultimately loading the data into a concurrent dictionary for another process to use that I will develop later. All this works except that whenever I run my thread to load my chunk data into my dictionary, when I play the audio back I hear a single clip sound and it coincides with how often I run the thread. If I set it to run every 20 seconds then I hear a clip sound at the 20 second mark when I listen to the audio. I need to get rid of this clipping and I can't figure out what is causing it.
Here are the basic steps
private static WasapiLoopbackCapture Wavein = null;
private static WasapiLoopbackCapture Wavein2 = null;
private static WaveFormat pcm8k16bitSt = new WaveFormat(8000, 16, 2);
private static WaveFormat pcm8k16bitMo = new WaveFormat(8000, 16, 1);
private static WaveFormat Bit16;
private static byte[] DataHeader = System.Text.Encoding.UTF8.GetBytes("data");
private static List<byte> SBL = new List<byte>();
private static List<byte> SBL2 = new List<byte>();
private static byte[] chunkdata;
private static byte[] chunkdata2;
internal static ConcurrentDictionary<DateTime, DataFrame> AllSpeakerBytes = new ConcurrentDictionary<DateTime, DataFrame>();
int SdeviceNumber = 0;
int SdeviceNumber2 = 0;
private static MMDevice deviceToRecord = null;
private static MMDevice deviceToRecord2 = null;
deviceToRecord = (new MMDeviceEnumerator().EnumerateAudioEndPoints(DataFlow.All, DeviceState.Active))[SdeviceNumber];
deviceToRecord2 = (new MMDeviceEnumerator().EnumerateAudioEndPoints(DataFlow.All, DeviceState.Active))[SdeviceNumber2];
RecordAllSpeakers();
private void RecordAllSpeakers()
{
if (deviceToRecord != null)
{
Wavein = new WasapiLoopbackCapture(deviceToRecord);
var silence = new SilenceProvider(Wavein.WaveFormat).ToSampleProvider();
var wo = new WaveOutEvent();
wo.DeviceNumber = SdeviceNumber;
wo.Init(silence);
wo.Play();
Wavein.DataAvailable += new EventHandler<NAudio.Wave.WaveInEventArgs>(SsourceStream_DataAvailable);
Wavein.StartRecording();
SRecFlag = true;
}
if (deviceToRecord2 != null)
{
Wavein2 = new WasapiLoopbackCapture(deviceToRecord2);
var silence = new SilenceProvider(Wavein2.WaveFormat).ToSampleProvider();
var wo = new WaveOutEvent();
wo.DeviceNumber = SdeviceNumber2;
wo.Init(silence);
wo.Play();
Wavein2.DataAvailable += new EventHandler<NAudio.Wave.WaveInEventArgs>(SsourceStream2_DataAvailable);
Wavein2.StartRecording();
SRecFlag2 = true;
}
}
private void SsourceStream_DataAvailable(object sender, NAudio.Wave.WaveInEventArgs e)
{
if (!SRecFlag) return;
if (Wavein.WaveFormat.BitsPerSample == 32)
{
#region NewStraightConvert
using (RawSourceWaveStream RS = new RawSourceWaveStream(e.Buffer, 0, e.BytesRecorded, WaveFormat.CreateIeeeFloatWaveFormat(Wavein.WaveFormat.SampleRate, Wavein.WaveFormat.Channels)))
using (Wave32To16Stream wav16 = new Wave32To16Stream(RS))
using (MemoryStream ms2 = new MemoryStream())
{
WaveFileWriter.WriteWavFileToStream(ms2, wav16);
ms2.Position = 0;
using (var reader = new WaveFileReader(ms2))
using (var conversionStream0 = new WaveFormatConversionStream(pcm8k16bitSt, reader))
using (var conversionStream1 = new WaveFormatConversionStream(pcm8k16bitMo, conversionStream0))
//using (var conversionStream2 = new WaveFormatConversionStream(muLaw8k8bit, conversionStream1))
{
byte[] SendingBytes;
using (MemoryStream ms3 = new MemoryStream())
{
using (RawSourceWaveStream cc = new RawSourceWaveStream(conversionStream1, pcm8k16bitMo))
{
cc.Position = 0;
cc.CopyTo(ms3);
SendingBytes = ms3.ToArray();
}
}
if (SendingBytes.Length > 0)
{
//SslTcpClient.VociDataToSendST2.AddRange(SendingBytes);
SBL.AddRange(SendingBytes);
}
}
}
#endregion
return;
}
else
{
byte[] outtovoci;
Bit16 = new WaveFormat(Wavein.WaveFormat.SampleRate, 16, Wavein.WaveFormat.Channels);
outtovoci = new byte[e.BytesRecorded];
Array.Copy(e.Buffer, 0, outtovoci, 0, e.BytesRecorded);
using (MemoryStream TESTWaveMS = new MemoryStream())
{
using (MemoryStream TESTWaveMS2 = new MemoryStream())
{
using (WaveFileWriter TESTwaveWriter = new WaveFileWriter(TESTWaveMS, Bit16))
{
TESTwaveWriter.Write(outtovoci, 0, outtovoci.Length);
TESTwaveWriter.Flush();
byte[] tbytes = TESTWaveMS.ToArray();
using (MemoryStream tstream = new MemoryStream(tbytes))
{
using (var reader = new WaveFileReader(tstream))
using (var conversionStream0 = new WaveFormatConversionStream(pcm8k16bitSt, reader))
using (var conversionStream1 = new WaveFormatConversionStream(pcm8k16bitMo, conversionStream0))
//using (var conversionStream2 = new WaveFormatConversionStream(muLaw8k8bit, conversionStream1))
{
WaveFileWriter.WriteWavFileToStream(TESTWaveMS2, conversionStream1);
byte[] tbytes2 = TESTWaveMS2.ToArray();
int fPos = SearchBytes(tbytes2, DataHeader);
if (fPos > 0)
{
fPos = fPos + 8;
}
else
{
fPos = 0;
}
long SendingBytes = tbytes2.Length - fPos;
byte[] WBack = new byte[SendingBytes];
if (SendingBytes > 0)
{
Array.Copy(tbytes2, fPos, WBack, 0, SendingBytes);
//SslTcpClient.VociDataToSendST2.AddRange(WBack);
SBL.AddRange(WBack);
}
}
}
}
}
}
}
}
private void SsourceStream2_DataAvailable(object sender, NAudio.Wave.WaveInEventArgs e)
{
if (!SRecFlag2) return;
if (Wavein2.WaveFormat.BitsPerSample == 32)
{
#region NewStraightConvert
using (RawSourceWaveStream RS = new RawSourceWaveStream(e.Buffer, 0, e.BytesRecorded, WaveFormat.CreateIeeeFloatWaveFormat(Wavein2.WaveFormat.SampleRate, Wavein2.WaveFormat.Channels)))
using (Wave32To16Stream wav16 = new Wave32To16Stream(RS))
using (MemoryStream ms2 = new MemoryStream())
{
WaveFileWriter.WriteWavFileToStream(ms2, wav16);
ms2.Position = 0;
using (var reader = new WaveFileReader(ms2))
using (var conversionStream0 = new WaveFormatConversionStream(pcm8k16bitSt, reader))
using (var conversionStream1 = new WaveFormatConversionStream(pcm8k16bitMo, conversionStream0))
//using (var conversionStream2 = new WaveFormatConversionStream(muLaw8k8bit, conversionStream1))
{
byte[] SendingBytes;
using (MemoryStream ms3 = new MemoryStream())
{
using (RawSourceWaveStream cc = new RawSourceWaveStream(conversionStream1, pcm8k16bitMo))
{
cc.Position = 0;
cc.CopyTo(ms3);
SendingBytes = ms3.ToArray();
}
}
if (SendingBytes.Length > 0)
{
//SslTcpClient.VociDataToSendST2.AddRange(SendingBytes);
SBL2.AddRange(SendingBytes);
}
}
}
#endregion
return;
}
else
{
byte[] outtovoci;
Bit16 = new WaveFormat(Wavein2.WaveFormat.SampleRate, 16, Wavein2.WaveFormat.Channels);
outtovoci = new byte[e.BytesRecorded];
Array.Copy(e.Buffer, 0, outtovoci, 0, e.BytesRecorded);
using (MemoryStream TESTWaveMS = new MemoryStream())
{
using (MemoryStream TESTWaveMS2 = new MemoryStream())
{
using (WaveFileWriter TESTwaveWriter = new WaveFileWriter(TESTWaveMS, Bit16))
{
TESTwaveWriter.Write(outtovoci, 0, outtovoci.Length);
TESTwaveWriter.Flush();
byte[] tbytes = TESTWaveMS.ToArray();
using (MemoryStream tstream = new MemoryStream(tbytes))
{
using (var reader = new WaveFileReader(tstream))
using (var conversionStream0 = new WaveFormatConversionStream(pcm8k16bitSt, reader))
using (var conversionStream1 = new WaveFormatConversionStream(pcm8k16bitMo, conversionStream0))
//using (var conversionStream2 = new WaveFormatConversionStream(muLaw8k8bit, conversionStream1))
{
WaveFileWriter.WriteWavFileToStream(TESTWaveMS2, conversionStream1);
byte[] tbytes2 = TESTWaveMS2.ToArray();
int fPos = SearchBytes(tbytes2, DataHeader);
if (fPos > 0)
{
fPos = fPos + 8;
}
else
{
fPos = 0;
}
long SendingBytes = tbytes2.Length - fPos;
byte[] WBack = new byte[SendingBytes];
if (SendingBytes > 0)
{
Array.Copy(tbytes2, fPos, WBack, 0, SendingBytes);
//SslTcpClient.VociDataToSendST2.AddRange(WBack);
SBL2.AddRange(WBack);
}
}
}
}
}
}
}
}
private async void timer3_Tick(object sender, EventArgs e)
{
timer3.Enabled = false;
if (SRecFlag == true || SRecFlag2 == true)
{
await Task.Run(() => SyncSpeakers());
}
timer3.Interval = 20000;
timer3.Enabled = true;
}
private static void SyncSpeakers()
{
MemoryStream ms = new MemoryStream();
MemoryStream ms2 = new MemoryStream();
WaveFileReader reader = null;
WaveFileReader reader2 = null;
MixingSampleProvider mixer = null;
int lbc = SBL.Count();
int lbc2 = SBL2.Count();
int lowest = 0;
int[] array = new int[] { lbc, lbc2 };
lowest = array.Where(f => f > 0).Min();
if (deviceToRecord != null && SBL.Count > 0)
{
chunkdata = new byte[lowest];
Array.Copy(SBL.ToArray(), 0, chunkdata, 0, chunkdata.Length);
SwaveWriterS1 = new NAudio.Wave.WaveFileWriter(ms, pcm8k16bitMo);
SwaveWriterS1.Write(chunkdata, 0, chunkdata.Length);
SwaveWriterS1.Flush();
SBL.RemoveRange(0, lowest);
}
if (deviceToRecord2 != null && SBL2.Count > 0)
{
chunkdata2 = new byte[lowest];
Array.Copy(SBL2.ToArray(), 0, chunkdata2, 0, chunkdata2.Length);
SwaveWriterS2 = new NAudio.Wave.WaveFileWriter(ms2, pcm8k16bitMo);
SwaveWriterS2.Write(chunkdata2, 0, chunkdata2.Length);
SwaveWriterS2.Flush();
SBL2.RemoveRange(0, lowest);
}
int SWaves = 0;
if (Wavein != null && SRecFlag == true)
{
ms.Position = 0;
reader = new WaveFileReader(ms);
SWaves++;
}
if (Wavein2 != null && SRecFlag2 == true)
{
ms2.Position = 0;
reader2 = new WaveFileReader(ms2);
SWaves++;
}
if (SWaves == 1)
{
mixer = new MixingSampleProvider(new[] { reader.ToSampleProvider() });
}
else if (SWaves == 2)
{
mixer = new MixingSampleProvider(new[] { reader.ToSampleProvider(), reader2.ToSampleProvider() });
}
if (SWaves > 0)
{
using (MemoryStream lms = new MemoryStream())
{
WaveFileWriter.WriteWavFileToStream(lms, mixer.ToWaveProvider16());
byte[] SendingBytes;
using (MemoryStream ms35 = new MemoryStream())
{
using (RawSourceWaveStream cc = new RawSourceWaveStream(lms, pcm8k16bitMo))
{
cc.Position = 0;
cc.CopyTo(ms35);
SendingBytes = ms35.ToArray();
SwaveWriter.Write(SendingBytes, 0, SendingBytes.Length);
SwaveWriter.Flush();
byte[] lByte = Compress(SendingBytes);
DataFrame aFrame2 = new DataFrame();
aFrame2.bytes = new byte[lByte.Length];
aFrame2.bytesRecorded = SendingBytes.Length;
lByte.CopyTo(aFrame2.bytes, 0);
AllSpeakerBytes.TryAdd(DateTime.UtcNow, aFrame2);
lByte = null;
}
}
}
}
}
internal static byte[] Compress(byte[] data)
{
try
{
//return data;
using (MemoryStream output = new MemoryStream())
{
using (DeflateStream dstream = new DeflateStream(output, CompressionLevel.Optimal))
{
dstream.Write(data, 0, data.Length);
}
return output.ToArray();
}
}
catch (Exception ERR5)
{
//Logging.LogData($"Failure in Compress: {ERR5.ToString()}");
return null;
}
}
internal static byte[] Decompress(byte[] data)
{
//return data;
try
{
using (MemoryStream output = new MemoryStream())
{
using (MemoryStream input = new MemoryStream(data))
{
using (DeflateStream dstream = new DeflateStream(input, CompressionMode.Decompress))
{
dstream.CopyTo(output);
}
}
return output.ToArray();
}
}
catch (Exception ERR5)
{
//Logging.LogData($"Failure in Decompress: {ERR5.ToString()}");
return null;
}
}
class DataFrame
{
public byte[] bytes { get; set; }
public int bytesRecorded { get; set; }
public string extraData { get; set; } = "";
}
private void btnStop_Click(object sender, EventArgs e)
{
if (Wavein != null)
{
Wavein.StopRecording();
Wavein.Dispose();
Wavein = null;
}
if (Wavein2 != null)
{
Wavein2.StopRecording();
Wavein2.Dispose();
Wavein2 = null;
}
mp3WriterAllSpk = new NAudio.Lame.LameMP3FileWriter(FinalSRFilename, pcm8k16bitMo, 64);
List<DateTime> SpkWrites = AllSpeakerBytes.Select(k => k.Key).OrderBy(c => c).ToList();
foreach (DateTime DT in SpkWrites)
{
byte[] outgoing = Decompress(AllSpeakerBytes[DT].bytes);
mp3WriterAllSpk.Write(outgoing, 0, AllSpeakerBytes[DT].bytesRecorded);
}
mp3WriterAllSpk.Dispose();
SRecFlag = false;
SRecFlag2 = false;
}
This code needs a lot of cleaning up but basically the SyncSpeakers() is being ran every 20 seconds and I am hearing a clipping at 20 second increments of the audio. If I change the timer to run every 10 seconds I will hear a clip sound every 10 seconds of the resulting audio. Any ideas?

I was able to solve this by shaving the first 100 bytes off of the front and replacing them with byte 101. If there is a better way I'd love to hear it.
Thanks!

Related

iTextSharp Document Isn't Working After Deployment

i'm using iTextSharp to create a pdf document then add it as an attachment to send an email using SendGrid.
The code is working locally but after deploying the project in Azure this function stopped working for some reason. I tried to analyze the problem and i think that the document didn't fully created of attached due to the connection. I can't pin point the exact issue to solve it. Any opinions or discussion is appreciated.
Action:
public async Task<IActionResult> GeneratePDF(int? id, string recipientEmail)
{
//if id valid
if (id == null)
{
return NotFound();
}
var story = await _db.Stories.Include(s => s.Child).Include(s => s.Sentences).ThenInclude(s => s.Image).FirstOrDefaultAsync(s => s.Id == id);
if (story == null)
{
return NotFound();
}
var webRootPath = _hostingEnvironment.WebRootPath;
var path = Path.Combine(webRootPath, "dump"); //folder name
try
{
using (System.IO.MemoryStream memoryStream = new System.IO.MemoryStream())
{
iTextSharp.text.Document document = new iTextSharp.text.Document(iTextSharp.text.PageSize.A4, 10, 10, 10, 10);
PdfWriter writer = PdfWriter.GetInstance(document, memoryStream);
document.Open();
string usedFont = Path.Combine(webRootPath + "\\fonts\\", "arial.TTF");
BaseFont bf = BaseFont.CreateFont(usedFont, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
iTextSharp.text.Font titleFont = new iTextSharp.text.Font(bf, 40);
iTextSharp.text.Font sentencesFont = new iTextSharp.text.Font(bf, 15);
iTextSharp.text.Font childNamewFont = new iTextSharp.text.Font(bf, 35);
PdfPTable T = new PdfPTable(1);
//Hide the table border
T.DefaultCell.BorderWidth = 0;
T.DefaultCell.HorizontalAlignment = 1;
T.DefaultCell.PaddingTop = 15;
T.DefaultCell.PaddingBottom = 15;
//Set RTL mode
T.RunDirection = PdfWriter.RUN_DIRECTION_RTL;
//Add our text
if (story.Title != null)
{
T.AddCell(new iTextSharp.text.Paragraph(story.Title, titleFont));
}
if (story.Child != null)
{
if (story.Child.FirstName != null && story.Child.LastName != null)
{
T.AddCell(new iTextSharp.text.Phrase(story.Child.FirstName + story.Child.LastName, childNamewFont));
}
}
if (story.Sentences != null)
{
.................
}
document.Add(T);
writer.CloseStream = false;
document.Close();
byte[] bytes = memoryStream.ToArray();
var fileName = path + "\\PDF" + DateTime.Now.ToString("yyyyMMdd-HHMMss") + ".pdf";
using (FileStream fs = new FileStream(fileName, FileMode.Create))
{
fs.Write(bytes, 0, bytes.Length);
}
memoryStream.Position = 0;
memoryStream.Close();
//Send generated pdf as attchment
// Create the file attachment for this email message.
var attachment = Convert.ToBase64String(bytes);
var client = new SendGridClient(Options.SendGridKey);
var msg = new SendGridMessage();
msg.From = new EmailAddress(SD.DefaultEmail, SD.DefaultEmail);
msg.Subject = story.Title;
msg.PlainTextContent = "................";
msg.HtmlContent = "..................";
msg.AddTo(new EmailAddress(recipientEmail));
msg.AddAttachment("Story.pdf", attachment);
try
{
await client.SendEmailAsync(msg);
}
catch (Exception ex)
{
Console.WriteLine("{0} First exception caught.", ex);
}
//Remove form root
if (System.IO.File.Exists(fileName))
{
System.IO.File.Delete(fileName);
}
}
}
catch (FileNotFoundException e)
{
Console.WriteLine($"The file was not found: '{e}'");
}
catch (DirectoryNotFoundException e)
{
Console.WriteLine($"The directory was not found: '{e}'");
}
catch (IOException e)
{
Console.WriteLine($"The file could not be opened: '{e}'");
}
return RedirectToAction("Details", new { id = id });
}
try to edit usedfont variable as bellow :
var usedfont = Path.Combine(webRootPath ,#"\fonts\arial.TTF")
It turns out that the problem is far from iTextSharp. I did a remote debugging from this article.
Two parts of the code was causing the problem.
First, for some reason the folder "dump" was not created on Azure wwwroot folder while locally it is. so, i added these lines:
var webRootPath = _hostingEnvironment.WebRootPath;
var path = Path.Combine(webRootPath, "dump");
if (!Directory.Exists(path)) //Here
Directory.CreateDirectory(path);
Second, after debugging it shows that creating the file was failing every time. I replaced the following lines:
using (FileStream fs = new FileStream(fileName, FileMode.Create))
{
fs.Write(bytes, 0, bytes.Length);
}
memoryStream.Position = 0;
memoryStream.Close();
With:
using (FileStream fs = new FileStream(fileName, FileMode.Create))
using (var binaryWriter = new BinaryWriter(fs))
{
binaryWriter.Write(bytes, 0, bytes.Length);
binaryWriter.Close();
}
memoryStream.Close();
Hope this post helps someone.

Reading attachment from a secured PDF

I am working on a PDF file, which is a secured one and an excel is attached in the PDF file.
The following is the code i tried.
static void Main(string[] args)
{
Program pgm = new Program();
pgm.EmbedAttachments();
//pgm.ExtractAttachments(pgm.pdfFile);
}
private void ExtractAttachments(string _pdfFile)
{
try
{
if (!Directory.Exists(attExtPath))
Directory.CreateDirectory(attExtPath);
byte[] password = System.Text.ASCIIEncoding.ASCII.GetBytes("TFAER13052016");
//byte[] password = System.Text.ASCIIEncoding.ASCII.GetBytes("Password");
PdfDictionary documentNames = null;
PdfDictionary embeddedFiles = null;
PdfDictionary fileArray = null;
PdfDictionary file = null;
PRStream stream = null;
//PdfReader reader = new PdfReader(_pdfFile);
PdfReader reader = new PdfReader(_pdfFile, password);
PdfDictionary catalog = reader.Catalog;
documentNames = (PdfDictionary)PdfReader.GetPdfObject(catalog.Get(PdfName.NAMES));
if (documentNames != null)
{
embeddedFiles = (PdfDictionary)PdfReader.GetPdfObject(documentNames.Get(PdfName.EMBEDDEDFILES));
if (embeddedFiles != null)
{
PdfArray filespecs = embeddedFiles.GetAsArray(PdfName.NAMES);
for (int i = 0; i < filespecs.Size; i++)
{
i++;
fileArray = filespecs.GetAsDict(i);
file = fileArray.GetAsDict(PdfName.EF);
foreach (PdfName key in file.Keys)
{
stream = (PRStream)PdfReader.GetPdfObject(file.GetAsIndirectObject(key));
string attachedFileName = fileArray.GetAsString(key).ToString();
byte[] attachedFileBytes = PdfReader.GetStreamBytes(stream);
System.IO.File.WriteAllBytes(attExtPath + attachedFileName, attachedFileBytes);
}
}
}
else
throw new Exception("Unable to Read the attachment or There may be no Attachment");
}
else
{
throw new Exception("Unable to Read the document");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
Console.ReadKey();
}
}
private void EmbedAttachments()
{
try
{
if (File.Exists(pdfFile))
File.Delete(pdfFile);
Document PDFD = new Document(PageSize.LETTER);
PdfWriter writer;
writer = PdfWriter.GetInstance(PDFD, new FileStream(pdfFile, FileMode.Create));
PDFD.Open();
PDFD.NewPage();
PDFD.Add(new Paragraph("This is test"));
PdfFileSpecification pfs = PdfFileSpecification.FileEmbedded(writer, #"C:\PDFReader\1.xls", "11.xls", null);
//PdfFileSpecification pfs = PdfFileSpecification.FileEmbedded(writer, attFile, "11", File.ReadAllBytes(attFile), true);
writer.AddFileAttachment(pfs);
//writer.AddAnnotation(PdfAnnotation.CreateFileAttachment(writer, new iTextSharp.text.Rectangle(100, 100, 100, 100), "File Attachment", PdfFileSpecification.FileExtern(writer, "C:\\test.xml")));
//writer.Close();
PDFD.Close();
Program pgm=new Program();
using (Stream input = new FileStream(pgm.pdfFile, FileMode.Open, FileAccess.Read, FileShare.Read))
{
using (Stream output = new FileStream(pgm.epdfFile, FileMode.Create, FileAccess.Write, FileShare.None))
{
PdfReader reader = new PdfReader(input);
PdfEncryptor.Encrypt(reader, output, true, "Password", "secret", PdfWriter.ALLOW_SCREENREADERS);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.StackTrace.ToString());
Console.ReadKey();
}
}
}
The above code contains the creation of a encrypted PDF with an excel attachment and also to extract the same.
Now the real problem is with the file which I already have as a requirement document(I cannot share the file) which also has an excel attachment like my example.
But the above code works for the secured PDF which i have created but not for the actual Secured PDF.
While debugging, I found that the Issue is with the following code
documentNames = (PdfDictionary)PdfReader.GetPdfObject(catalog.Get(PdfName.NAMES));
In which,
catalog.Get(PdfName.NAMES)
is returned as NULL, Where as the File created by me, provides the expected output.
Please guide me on the above.
TIA.
As mkl suggested, It has been attached as an Annotated attachment. But the reference which is used in the example is provided ZipFile Method is no longer supported. Hence I found an alternate code attached below.
public void ExtractAttachments(byte[] src)
{
PRStream stream = null;
string attExtPath = #"C:\PDFReader\Extract\";
if (!Directory.Exists(attExtPath))
Directory.CreateDirectory(attExtPath);
byte[] password = System.Text.ASCIIEncoding.ASCII.GetBytes("TFAER13052016");
PdfReader reader = new PdfReader(src, password);
for (int i = 1; i <= reader.NumberOfPages; i++)
{
PdfArray array = reader.GetPageN(i).GetAsArray(PdfName.ANNOTS);
if (array == null) continue;
for (int j = 0; j < array.Size; j++)
{
PdfDictionary annot = array.GetAsDict(j);
if (PdfName.FILEATTACHMENT.Equals(
annot.GetAsName(PdfName.SUBTYPE)))
{
PdfDictionary fs = annot.GetAsDict(PdfName.FS);
PdfDictionary refs = fs.GetAsDict(PdfName.EF);
foreach (PdfName name in refs.Keys)
{
//zip.AddEntry(
// fs.GetAsString(name).ToString(),
// PdfReader.GetStreamBytes((PRStream)refs.GetAsStream(name))
//);
stream = (PRStream)PdfReader.GetPdfObject(refs.GetAsIndirectObject(name));
string attachedFileName = fs.GetAsString(name).ToString();
var splitname = attachedFileName.Split('\\');
if (splitname.Length != 1)
attachedFileName = splitname[splitname.Length - 1].ToString();
byte[] attachedFileBytes = PdfReader.GetStreamBytes(stream);
System.IO.File.WriteAllBytes(attExtPath + attachedFileName, attachedFileBytes);
}
}
}
}
}
Please Let me Know if it can be achieved in any other way.
Thanks!!!

Component One pdf generation using draw image crashing if printing pdf pages more than 40

I'm using below code to generate pdf of a page having listview. And it all works good till I have a very small list once I got list with more than 50 items it crashing with memory exception. I think variable pdf is taking all memory. I have checked using profiling it goes above 180 and pdf variable was on top when I took snapshot at profile.
async PDFTest_Loaded(int a)
{
try
{
pdf = new C1PdfDocument(PaperKind.Letter);
pdf.Compression = CompressionLevel.NoCompression;
WriteableBitmap writeableBmp = await initializeImage();
List<WriteableBitmap> ListBitmaps = new List<WriteableBitmap>();
pdfPage PageBitmaps = new pdfPage();
FrameworkElement header = RTABlock as FrameworkElement;
header.Arrange(pdf.PageRectangle);
var headerImage = await CreateBitmap(header);
FrameworkElement Pageheader = SalikPaymentReceipt as FrameworkElement;
Pageheader.Arrange(pdf.PageRectangle);
var PageHeaderImage = await CreateBitmap(Pageheader);
double pdfImageWidth = 0;
foreach (var item in EpayPreviewListView.Items)
{
List<WriteableBitmap> temp = new List<WriteableBitmap>();
var obj = EpayPreviewListView.ContainerFromItem(item);
List<FrameworkElement> controls = Children(obj);
StackPanel ListItemStackPanel = controls.Where(x => x is StackPanel && x.Name == "ListItemStackPanel").First() as StackPanel;
if (ListItemStackPanel is StackPanel)
{
StackPanel itemui = ListItemStackPanel as StackPanel;
if (!(pdfImageWidth > 0))
{
pdfImageWidth = itemui.ActualWidth;
}
itemui.Arrange(new Rect(0, 0, pdfImageWidth, pdf.PageRectangle.Height));
temp.Add(await CreateBitmap(itemui));
PageBitmaps = new pdfPage() { bitmap = temp };
CreateDocumentText(pdf, headerImage, writeableBmp, PageHeaderImage, PageBitmaps);
PageBitmaps = null;
temp = new List<WriteableBitmap>();
}
}
StorageFile Assets = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFileAsync("Salik Payment Receipts.pdf", CreationCollisionOption.GenerateUniqueName);
PdfUtils.Save(pdf, Assets);
EpayPreviewListView.InvalidateArrange();
EpayPreviewListView.UpdateLayout();
LoadingProgress.Visibility = Visibility.Collapsed;
PrintButton.IsEnabled = true;
}
catch (Exception ex)
{
Debugger.Break();
}
}
public List<FrameworkElement> Children(DependencyObject parent)
{
try
{
var list = new List<FrameworkElement>();
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
if (child is StackPanel || child is TextBlock || child is ListView)
list.Add(child as FrameworkElement);
list.AddRange(Children(child));
}
return list;
}
catch (Exception e)
{
Debug.WriteLine(e.ToString() + "\n\n" + e.StackTrace);
Debugger.Break();
return null;
}
}
async public Task<WriteableBitmap> CreateBitmap(FrameworkElement element)
{
// render element to image (WinRT)
try
{
var renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(element);
var wb = new WriteableBitmap(renderTargetBitmap.PixelWidth, renderTargetBitmap.PixelHeight);
(await renderTargetBitmap.GetPixelsAsync()).CopyTo(wb.PixelBuffer);
//var rect = new Rect(0, 0, renderTargetBitmap.PixelWidth, renderTargetBitmap.PixelHeight);
if (!App.IsEnglishSelected)
{
wb = wb.Flip(WriteableBitmapExtensions.FlipMode.Vertical);
}
return wb;
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString() + "\n\n" + ex.StackTrace);
Debugger.Break();
return new WriteableBitmap(0, 0);
}
}
bool isFirst = true;
void CreateDocumentText(C1PdfDocument pdf, WriteableBitmap headerImage, WriteableBitmap writeableBmp, WriteableBitmap pageHeading, pdfPage ListItem)
{
try
{
if (!isFirst)
{
pdf.NewPage();
}
isFirst = false;
pdf.Landscape = false;
double contentHeight = 0;
double leftMargin = 0;
string fontName = "Arial";
// measure and show some text
var text = App.GetResource("RoadandTransportAuthority");
var font = new Font(fontName, 36, PdfFontStyle.Bold);
// create StringFormat used to set text alignment and line spacing
var fmt = new StringFormat();
fmt.Alignment = HorizontalAlignment.Center;
var rc = new Rect(0, 0,
pdf.PageRectangle.Width, headerImage.PixelHeight);
pdf.DrawImage(headerImage, rc, ContentAlignment.MiddleCenter, Stretch.None);
contentHeight += headerImage.PixelHeight + 2;
rc = new Rect(0, contentHeight, pdf.PageRectangle.Width, writeableBmp.PixelHeight);
pdf.DrawImage(writeableBmp, rc);
contentHeight += writeableBmp.PixelHeight + 5;
rc = new Rect(leftMargin, contentHeight,
pdf.PageRectangle.Width,
pageHeading.PixelHeight);
pdf.DrawImage(pageHeading, rc, ContentAlignment.MiddleCenter, Stretch.None);
contentHeight += pageHeading.PixelHeight + 2;
Debug.WriteLine(ListItem.bitmap.Count.ToString());
for (int i = 0; i < ListItem.bitmap.Count; i++)
{
rc = PdfUtils.Offset(rc, 0, rc.Height + 10);
rc.Height = ListItem.bitmap.ElementAt(i).PixelHeight;
pdf.DrawImage(ListItem.bitmap.ElementAt(i), rc, ContentAlignment.TopCenter, Stretch.None);
ListItem.bitmap[i] = null;
}
ListItem = null;
}
catch (Exception e)
{
//...
}
}
It is due to memory clash I have to decrease the quality of images to handle it. Also it takes some time to release memory.

iTextSharp retain named destinations and bookmarks after writing a new document

I have a method that fixes my document so it opens on Page Level Zoom, the bookmarks are retained but I can't seem to keep my named destinations (anchors) in my new document. I commented in my method what I thought would fix the problem, I used the code before in another method.
private static void FixZoom(string source)
{
var reader = new PdfReader(new FileStream(source, FileMode.Open, FileAccess.Read));
var size = reader.GetPageSizeWithRotation(1);
using (var document = new iTextSharp.text.Document(size))
{
var path = String.Empty;
var dirName = Path.GetDirectoryName(source);
if (dirName != null)
{
path = Path.Combine(dirName, "Zoom" + Path.GetFileName(source));
}
using (var stream = new FileStream(path, FileMode.Create, FileAccess.ReadWrite))
{
using (var writer = PdfWriter.GetInstance(document, stream))
{
document.Open();
var bookmarks = SimpleBookmark.GetBookmark(reader);
var cb = writer.DirectContent;
var pdfDest = new PdfDestination(PdfDestination.FIT);
var action = PdfAction.GotoLocalPage(1, pdfDest, writer);
for (var pageNumber = 1; pageNumber <= reader.NumberOfPages; pageNumber++)
{
document.SetPageSize(reader.GetPageSizeWithRotation(pageNumber));
document.NewPage();
var page = writer.GetImportedPage(reader, pageNumber);
cb.AddTemplate(page, 0, 0);
}
//BEGIN: This is not working
var map = SimpleNamedDestination.GetNamedDestination(reader, false);
if (map.Count > 0)
{
writer.AddNamedDestinations(map, reader.NumberOfPages);
}
//END: This is not working
var pageMode = 0;
pageMode += PdfWriter.PageLayoutOneColumn;
writer.SetOpenAction(action);
writer.ViewerPreferences = pageMode;
writer.Outlines = bookmarks;
document.Close();
}
}
File.Delete(source);
File.Move(path, source);
}
}
After the comment I fixed it with this code.
private static void FixZoom(string source)
{
var reader = new PdfReader(new FileStream(source, FileMode.Open, FileAccess.Read));
var size = reader.GetPageSizeWithRotation(1);
using (var document = new iTextSharp.text.Document(size))
{
var path = String.Empty;
var dirName = Path.GetDirectoryName(source);
if (dirName != null)
{
path = Path.Combine(dirName, "Zoom" + Path.GetFileName(source));
}
using (var stream = new FileStream(path, FileMode.Create, FileAccess.ReadWrite))
{
using (var stamper = new PdfStamper(reader, stream))
{
document.Open();
var pdfDestination = new PdfDestination(PdfDestination.FIT);
var pdfAction = PdfAction.GotoLocalPage(1, pdfDestination, stamper.Writer);
stamper.Writer.SetOpenAction(pdfAction);
document.Close();
}
}
File.Delete(source);
File.Move(path, source);
}
}

Rewriting from MonoTouch Application to MonoDroid

I'm going to rewrite the application from Monotouh to Monodroid application for android. Correct me if I'm wrong. The logic remains the same as in MonoTouch or change anything? If something changes, please tell me, what?
As far as I understand, only GIU changes. Thanks in advance!
So, this is my code where i call data from my server:
namespace Mobile{
public static class SiteHelper
{
public static string DbPath = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.Personal), "Sql_1.4.sqlite");
public const string TempDbPath = "./Sql.sqlite";
public static UIView View { get; set; }
public static BaseController Controller { get; set; }
private static event NIHandler _noInternetHandler;
private static bool _noInternetShoved = false;
public static string SiteDomain = "http://mysite.com"; //files which connecting to the DB on server (.asx files)
private delegate void NIHandler ();
public static XDocument DoRequest (string Request)
{
if (_noInternetHandler != null) {
foreach (var del in _noInternetHandler.GetInvocationList()) {
_noInternetHandler -= del as NIHandler;
}
}
if (Controller != null)
_noInternetHandler += new NIHandler (Controller.PushThenNoInternet);
string CryptoString = "";
string Language = "ru";
using (MD5 md5Hash = MD5.Create()) {
string hashKey = Guid.NewGuid ().ToString ().Substring (0, 4);
CryptoString = Request + (Request.Contains ("?") ? "&" : "?") + "hash=" + GetMd5Hash (
md5Hash,
"myprogMobhash_" + hashKey
) + "&hashKey=" + hashKey + "&language=" + Language;
UIActivityIndicatorView _preloader = null;
if (Controller != null) {
Controller.InvokeOnMainThread (delegate() {
_preloader = new UIActivityIndicatorView (UIActivityIndicatorViewStyle.Gray);
if (View != null && Request.IndexOf ("login.ashx") == -1
&& Request.IndexOf ("yandex") == -1
&& Request.IndexOf ("GetDialogMessages") == -1) {
lock (_preloader) {
if (_preloader != null && !_preloader.IsAnimating)
_preloader.HidesWhenStopped = true;
_preloader.Frame = new RectangleF (150, 170, 30, 30);
_preloader.Transform = MonoTouch.CoreGraphics.CGAffineTransform.MakeScale ((float)1.3, (float)1.3);
_preloader.StartAnimating ();
View.Add (_preloader);
}
}
});
}
/*ctx.GetText(Resource.String.SiteAddress)*/
Stream Stream = null;
try {
HttpWebRequest request = new HttpWebRequest (new Uri (SiteDomain + "/FolderWithFiles/" + CryptoString));
request.Timeout = 8000;
Stream = request.GetResponse ().GetResponseStream ();
_noInternetShoved = false;
if (_noInternetHandler != null)
_noInternetHandler -= new NIHandler (Controller.PushThenNoInternet);
} catch (WebException) {
if (_noInternetHandler != null)
_noInternetHandler.Invoke ();
var resp = new XDocument (new XElement ("Response",
new XElement ("status", "error"),
new XElement ("error", "Отсутствует интернет"))
);
return resp;
}
StreamReader Sr = new StreamReader (Stream);
string Resp = Sr.ReadToEnd ();
XDocument Response = XDocument.Parse (Resp.Substring (0, Resp.IndexOf ("<html>") == -1 ? Resp.Length : Resp.IndexOf ("<!DOCTYPE html>")));
string Hash = Response.Descendants ().Where (x => x.Name == "hash")
.FirstOrDefault ().Value;
string HashKey = Response.Descendants ().Where (x => x.Name == "hashKey")
.FirstOrDefault ().Value;
Sr.Close ();
Stream.Close ();
if (Controller != null && _preloader != null) {
Controller.InvokeOnMainThread (delegate() {
lock (_preloader) {
_preloader.StopAnimating ();
_preloader.RemoveFromSuperview ();
}
});
}
if (VerifyMd5Hash (
md5Hash,
"mobileSitehash_" + HashKey,
Hash
))
return Response;
else
throw new Exception ();
}
}
public static XDocument DoWriteFileRequest (string Request, byte[] file)
{
string CryptoString = "";
string Language = "ru";
using (MD5 md5Hash = MD5.Create()) {
string hashKey = Guid.NewGuid ().ToString ().Substring (0, 4);
CryptoString = Request + (Request.Contains ("?") ? "&" : "?") + "hash=" + GetMd5Hash (
md5Hash,
"mobileMobhash_" + hashKey
) + "&hashKey=" + hashKey + "&language=" + Language;
HttpWebRequest Req = (HttpWebRequest)WebRequest.Create (SiteDomain + "/misc/mobile/" + CryptoString);
Req.Method = "POST";
Stream requestStream = Req.GetRequestStream ();
requestStream.Write (file, 0, file.Length);
requestStream.Close ();
Stream Stream = Req.GetResponse ().GetResponseStream ();
StreamReader Sr = new StreamReader (Stream);
string Resp = Sr.ReadToEnd ();
XDocument Response = XDocument.Parse (Resp);
string Hash = Response.Descendants ().Where (x => x.Name == "hash")
.FirstOrDefault ().Value;
string HashKey = Response.Descendants ().Where (x => x.Name == "hashKey")
.FirstOrDefault ().Value;
Sr.Close ();
Stream.Close ();
if (VerifyMd5Hash (
md5Hash,
"mobileSitehash_" + HashKey,
Hash
))
return Response;
else
throw new Exception ();
}
}
public static string GetMd5Hash (MD5 md5Hash, string input)
{
// Convert the input string to a byte array and compute the hash.
byte[] data = md5Hash.ComputeHash (Encoding.UTF8.GetBytes (input));
// Create a new Stringbuilder to collect the bytes
// and create a string.
StringBuilder sBuilder = new StringBuilder ();
// Loop through each byte of the hashed data
// and format each one as a hexadecimal string.
for (int i = 0; i < data.Length; i++) {
sBuilder.Append (data [i].ToString ("x2"));
}
// Return the hexadecimal string.2
return sBuilder.ToString ();
}
//Geting the info for my app
public static List<PackageListModel> GetUserPackages (int UserID)
{
List<PackageListModel> Events = new List<PackageListModel> ();
string Req = "SomeFile.ashx?UserID=" + UserID;
XDocument XmlAnswer = DoRequest (Req);
if (XmlAnswer.Descendants ("status").First ().Value == "ok") {
foreach (var el in XmlAnswer.Descendants ("Response").First ().Descendants().Where(x=>x.Name == "Event")) {
PackageListModel Event = null;
Event = new PackageListModel ()
{
ID = int.Parse(el.Attribute("ID").Value),
Title = el.Element("Title").Value,
Date = el.Element("Date").Value,
Price = el.Element("Price").Value,
ImageUrl = el.Element("ImageUrl").Value,
Location = el.Element("Location").Value
};
Events.Add (Event);
}
}
return Events;
}
//Получить пользовательские поездки
public static List<TransporterListModel> GetUserTransporters (int UserID)
{
List<TransporterListModel> Events = new List<TransporterListModel> ();
string Req = "SomeFile.ashx?UserID=" + UserID;
XDocument XmlAnswer = DoRequest (Req);
if (XmlAnswer.Descendants ("status").First ().Value == "ok") {
foreach (var el in XmlAnswer.Descendants ("Response").First ().Descendants().Where(x=>x.Name == "Event")) {
TransporterListModel Event = null;
Event = new TransporterListModel ()
{
ID = int.Parse(el.Attribute("ID").Value),
Date = el.Element("Date").Value,
Price = el.Element("Price").Value,
TransportsStr = el.Element("Transports").Value,
Location = el.Element("Location").Value
};
Events.Add (Event);
}
}
return Events;
}
}
}
}
I think you should read this.
In brief - you can reuse application logic that not depends on platform-specific parts, so working with database/server can be shared between MonoTouch and Mono for Android.