How to Convert multiple 32bpp multi-frame TIFF MemoryStreams to one Group 4 1bpp B&W Grayscale MemoryStream

Hello,

This fix does not fix the problem.

Am I correct in that your fix resizes each new loaded TIF frame (page) to a defined size (newWidth and newHeight)? This will not work.
ri.Resize(newWidth, newHeight, ResizeType.NearestNeighbourResample);

Wouldn't this distort the loaded image - especially if the next frame to be added is in landscape instead of portrait... - it would be resized - squished - to fit in the same frame. Our existing 3rd party vendor's tools do add each TIF as their original orientation and everything works - problem is we purchased Aspose.Total and did not renew the other companies license... and would like to use your tools.

We need to be able to:

  1. create a new TIFF
  2. add frames to this base TIF where each frame may have:
  • Different size - where size and orientation are retained
  • Different compression - each frame added is converted to G3*
  • Different resolution - each frame added is converted to 200dpi*

All frames added to the base new TIF image must retain their original size and orientation and have been converted to G3 or G4, and had their resolution converted to 200dpi.

*This conversion I can do externally until you update Aspose.Imaging to support Dithering.
Can you provide a way to Load a TIF, iterate through the frames, export them as MS Bitmap Image object so I can Dither it, and then I can add them as a converted TIF MemoryStream object to the new TIF container?

I know how to iterate through Aspose frames - but no clue how to read/convert the Aspose frame image to a MS Image in order to 'Dither' and convert it to G3 or G4 at 200dpi. So right now I have to load it as a MS Bitmap and iterate through the Frames of it - risking out of memory issues if this TIF being processed is too large. So if you can provide how to load the TIF as an Aspose image, iterate through each frame, export an Aspose frame to a MS image where I can Dither it - then add that frame to the base new TIF (remember, must be able to be a different size than original base TIF) - we will have a working solution until Aspose can add Dithering to the Imaging product.

We missed the June 1st release date of our product, now pushed to beginning of July - I hope you can help us make our next deadline.

Thank you for your help,
Todd

Hi Todd,


Thanks for your feedback. We are looking into your requirement and will update you soon.

Best Regards,

I have attached the code I am currently using with Aspose.Imaging. Maybe this will help you see the workaround we have - that resizing of the image is NOT what we want to do - yet is required to make your code work still.

This code still uses Microsoft to load the TIF, call a CopyToB(..) method which converts it to a Dithered image, and then adds it as a frame to the base TIFF.

It would be great if you could get it working so I can add a TIF Frame to the base original TIF and retain it's original size and orientation. I.e. a portrait first page, followed by a Landscape second page - both readable as their original form without rotating is a requirement for our application.

Right now I have it shrinking the Landscape image and putting it in a Portrait page the same size as the first page created - the only way I can get it to work with Aspose.

Thank you,

Todd Nelson
Univita Health

Hi Todd,

Thanks for your inquiry.

"- Am I correct in that your fix resizes each new loaded TIF frame (page) to a defined size (newWidth and newHeight)?"

you may add tiff frame of any size when loading the source frame size remains the same
using (RasterImage ri = (RasterImage)Image.Load(file))
{

TiffFrame frame = new TiffFrame(outputSettings, ri.Width, ri.Height);
frame.SavePixels(frame.Bounds, ri.LoadPixels(ri.Bounds));
tiffImage.AddFrame(frame);

}

"-add frames to this base TIF where each frame may have:
-Different size - where size and orientation are retained no problem with that at all
-Different compression - each frame added is converted to G3*"

you may use some standard tiffOptions for new frames or must edit the options for the newly added frame.
-FrameOptions.Compression = .... and that's all that is required
-Different resolution - each frame added is converted to 200dpi* .
-FrameOptions.Resoluition = new TiffRational(200);

-Can you provide a way to Load a TIF, iterate throught the frames, export them as MS Bitmap Image object, and then I can add them back as a converted TIF MemoryStream object to the new TIF container

Please refer to documentation link hopefully it will help you to achieve your desired results.

Please let us know to provide any further assistance.

Best Regards,

Hello,

I did manage to recode this and have attached my latest version. Using your sample code, I began getting "{Aspose.Imaging.Exceptions.FrameworkException: Cannot allocate so many bytes. Use LoadPartialPixels instead." So I redesigned again, this time not using Aspose graphics, and creating a new TiffImage and copying the Frames[0] frame using it's own settings to a new TiffFrame and adding that to the base TIF. This is done in a 'using' block so in theory should deallocate on completion. I still added Dispose to all the MemoryStream's to ensure they are not left over.

Functionally - it does everything I want it to - and does work adding a 12-page TIF to the base TIF.

BUT - it fails drastically when adding a larger TIF.
The same code - attempting to add a 2737KB TIF* to the base TIF results in 2/3 of the pages added corrupted..
I have retried it a second and third time - but always about 2/3 with 1/2 the page missing. The last run had corrupted 69 of the 103 pages, with the top 1/2 of the page showing - and the lower half black. Maybe it needs some sort of wait state to pause adding pages until the prior added page has been added? Is the corruption due to the fact it might not be finished adding before the next page starts to add? Is there some way to use threading - I do not know how your code works or how it could be fixed to ensure each page is finished before next add is started.

Statistics:
Source files:

  • 1-page 33KB G4 TIF 2200x1700
  • 102 page 2737KB CCITT6 TIF of various sizes resulted in 429MB worth of .TMP files.

With
Cache.MaxDiskSpaceForCache = 1073741824;
Cache.MaxMemoryForCache = 1073741824;
AllocatedDiskBytesCount at the end of the last page added was 991,008,000

Summary:
There is a page/frame corruption problem adding frames sourced from a large TIF to a base TIF.

I have attached my latest code and one of the pages half black. (I cropped the top portion as these were actual files and had confidential info - it did have content on the top 1/2).

Thank you for your help,

Todd

Hi Todd,


Thanks for your inquiry. Can you please share some sample problematic input TIFF image here? It would help us to test the scenario at our end. If you are facing some issue with attachment size then can share either using some file sharing services e.g. dropbox,skydrive or email using contact tab of forum thread.

Sorry for the inconvenience faced.

Best Regards,

Big problems… Attempting to use your code - calling my DitherBitmap which uses Microsoft Bitmap to Dither an image, gets to page 39 and throws a Microsoft Out-of-Memory even though I Dispose of all streams and bitmap objects in the called method.


So - Back to Aspose - I rewrote my code, using the foreach TiffFrame frame in TiffImage pageImage - and use your sample from https://forum.aspose.com/t/2208
where you simply go through a pixel array and convert to Black or White.
This works for a few pages - but throws an Aspose out of memory error trying to save page 13 - even though added/saved pages are around 13k each:

Aspose.Imaging.Exceptions.FrameworkException was caught
HResult=-2146233088
Message=Cannot allocate so many bytes. Use LoadPartialPixels instead.
Source=Aspose.Imaging
StackTrace:
at Aspose.Imaging.RasterImage. .Process(Rectangle , Color[] , Point , Point )
at . . . (Rectangle )
at . . (Rectangle , , , Int32 , Int32 )
at . . (Rectangle , )
at . . (TiffStream , Rectangle , IPartialPixelLoader )
at . . (Rectangle , IPartialPixelLoader )
at Aspose.Imaging.FileFormats.Tiff.TiffFrame.LoadPixelsToCache(Rectangle rectangle, IPartialPixelLoader partialPixelLoader)
at Aspose.Imaging.RasterCachedImage.LoadPixelsInternal(Rectangle rectangle, IPartialPixelLoader pixelLoader)
at Aspose.Imaging.RasterImage. (Rectangle , Color[] , Boolean , IPartialPixelLoader )
at Aspose.Imaging.RasterImage. (Rectangle , Boolean , IPartialPixelLoader )
at Aspose.Imaging.RasterImage.LoadPixels(Rectangle rectangle)
at LINK.Common.Enterprise.DocumentManagement.Document.GetStreamOfReportAndImages(String informationRequestId, Int32 reportingBatchId, String reportPath, String reportFormat, String[] imagePaths, Int32& pageCount)
InnerException:



How / why would I use LoadPartialPixels when I am not specifying a sub-rectangle of any larger image? AND I am only getting the pixels from the frame. It would appear despite being in a using statement - your system has two problems - it is not disposing when dispose is called directly, and looking at the the values of cache used - they remain the same, unchanging between frames - which implies the memory was released - but it is not.
saving each frame as shown in my code below resulted in files saved of this:

06/19/2013 01:56 PM 40,960 Page1_reportheader.tif
06/19/2013 01:56 PM 21,597 Page2_DCUsed0_MCUsed32000244.tif
06/19/2013 01:57 PM 12,675 Page3_DCUsed0_MCUsed32000244.tif
06/19/2013 01:57 PM 13,043 Page4_DCUsed0_MCUsed32000244.tif
06/19/2013 01:57 PM 12,722 Page5_DCUsed0_MCUsed32000244.tif
06/19/2013 01:57 PM 12,759 Page6_DCUsed0_MCUsed32000244.tif
06/19/2013 01:57 PM 12,686 Page7_DCUsed0_MCUsed32000244.tif
06/19/2013 01:57 PM 6,046 Page8_DCUsed0_MCUsed32000244.tif
06/19/2013 01:57 PM 12,198 Page9_DCUsed0_MCUsed32000244.tif
06/19/2013 01:57 PM 13,303 Page10_DCUsed0_MCUsed32000244.tif
06/19/2013 01:57 PM 13,211 Page11_DCUsed0_MCUsed32000244.tif
06/19/2013 01:57 PM 13,522 Page12_DCUsed0_MCUsed32000244.tif
06/19/2013 01:57 PM 13,506 Page13_DCUsed0_MCUsed32000244.tif

which shows no changes in Memory cache used - and you can see by the saved file size - timage couldn’t be bigger than the sum of these added frames I would think…
This code dies on the 13th frame.

I have attached my sample TIF file (note, contains trademarked color company logo which is what needs to be grayscaled - your conversion to G3 or G4 1bpp erases it completely). note: Actual added TIF files may have varying resolution/bpp/size, etc.
This is the one loaded in my document.cs file as the first and only imagePaths entry loaded as imagePath[0] below on line:
using (Stream imageFile = new FileStream(imagePaths[i], FileMode.Open, FileAccess.Read))


My code is (anything missing can be found in my prior submitted document.cs):

Aspose.Imaging.ImageOptions.TiffOptions createOptions =
new Aspose.Imaging.ImageOptions.TiffOptions();
TiffRational rX = new TiffRational(200);
TiffRational rY = new TiffRational(200);
createOptions.BitsPerSample = new ushort[] { 1 };
createOptions.Xresolution = rX;
createOptions.Yresolution = rY;
createOptions.Orientation = Aspose.Imaging.FileFormats.Tiff.Enums.TiffOrientations.TopLeft;
createOptions.PlanarConfiguration = Aspose.Imaging.FileFormats.Tiff.Enums.TiffPlanarConfigs.Contiguous;
createOptions.Photometric = Aspose.Imaging.FileFormats.Tiff.Enums.TiffPhotometrics.MinIsWhite;
createOptions.Compression = Aspose.Imaging.FileFormats.Tiff.Enums.TiffCompressions.CcittFax3;
createOptions.Source = new Aspose.Imaging.Sources.StreamSource(new System.IO.MemoryStream());
using (TiffImage timage = (TiffImage)Aspose.Imaging.Image.Create(createOptions, 1770, 2200))
{
//… code excluded - see document.cs - that adds report header TIF to timage
//…

for (int i = 0; i < imagePaths.Length; i++)
{
using (Stream imageFile = new FileStream(imagePaths[i], FileMode.Open, FileAccess.Read))
{
byte[] tmpBytes = new byte[imageFile.Length];
imageFile.Read(tmpBytes, 0, Convert.ToInt32(imageFile.Length));
MemoryStream copiedStream = new MemoryStream(tmpBytes);
copiedStream.Seek(0, SeekOrigin.Begin);

using (TiffImage pageImage = (TiffImage)Aspose.Imaging.Image.Load(copiedStream))
{
foreach (TiffFrame frame in ((TiffImage)pageImage).Frames)
{
Aspose.Imaging.Color[] pixels = frame.LoadPixels(frame.Bounds);

for (int x = 0; x < pixels.Length; x++)
{
// 0.3F,0.59F, 0.11F
double powerR = .3 * Convert.ToDouble(pixels[x].R);
double powerG = .59 * Convert.ToDouble(pixels[x].G);
double powerB = .11 * Convert.ToDouble(pixels[x].B);

int power = Convert.ToInt32(powerR + powerG + powerB);
if (power > 218)
{
pixels[x] = Aspose.Imaging.Color.White;
}
else
{
pixels[x] = Aspose.Imaging.Color.Black;
}
}

frame.SavePixels(frame.Bounds, pixels);

long Diskremaining = Cache.AllocatedDiskBytesCount;
long Memremaining = Cache.AllocatedMemoryBytesCount;

// create a new frame from
using (TiffFrame addframe = TiffFrame.CreateFrameFrom(frame, new Aspose.Imaging.ImageOptions.TiffOptions(createOptions)))
{
// copy addframe from modified frame and save it as createOptions 1bpp G4 TIF
addframe.SavePixels(frame.Bounds, frame.LoadPixels(frame.Bounds));

// add frame to base timage TIFF file
timage.AddFrame(addframe);
pageCount++;

addframe.Save(@“C:\Temp\Page” + pageCount.ToString() + “_DCUsed” +
Diskremaining.ToString() + “_MCUsed” + Memremaining.ToString() + “.tif”,
addframe.FrameOptions);

addframe.Dispose();
}
frame.Dispose();
} // end foreach frame
} // end pageImage
} // end using imageFile
} // end foreach TIF file to add - there is only one in current testing


Of NOTE: Your latest 1.8 build is MISSING a DrawImage (…) definition mentioned in your documentation that has a parameter named ImageAttributes. The lack of this method according to the API basically destroys much of your documented features.
If this existed - I could use it with ColorMatrix to grayscale the image properly, and then use TiffFrame.GetPixel and TiffFrame.SetPixel to clean it up as I did in my DitherImage method.
This missing method is referenced on: http://www.aspose.com/docs/display/imagingnet/ImageAttributes+Class
The first paragraph states:
To apply such manipulations, initialize an ImageAttributes object and pass the path of that ImageAttributes object (along with the path of an Image ) to the DrawImage method.

There is no DrawImage method that currently takes an ImageAttributes object.
The Microsoft equivalent is (which can be seen in my DitherImage method):
float[][] colorMatrixElements = {
new float[] {0.3F, 0.3F, 0.3F, 0, 0},
new float[] {0.59F, 0.59F, 0.59F, 0, 0},
new float[] {0.11F, 0.11F, 0.11F, 0, 0},
new float[] { 0, 0, 0, 1, 0},
new float[] { 0, 0, 0, 0, 1}};
System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bm);
System.Drawing.Imaging.ColorMatrix c = new System.Drawing.Imaging.ColorMatrix(colorMatrixElements);
System.Drawing.Imaging.ImageAttributes attributes = new System.Drawing.Imaging.ImageAttributes();
attributes.SetColorMatrix(c);
g.DrawImage(gsBitmap, new System.Drawing.Rectangle(left, top, destwidth, destheight), 0, 0, srcwidth, srcheight, System.Drawing.GraphicsUnit.Pixel, attributes);

I started writing the equivilent in Aspose code - but without the DrawImage Aspose method - it is useless:
Aspose.Imaging.Image gimage;
Aspose.Imaging.Graphics ga = new Aspose.Imaging.Graphics(gimage);
Aspose.Imaging.ImageAttributes gattributes = new Aspose.Imaging.ImageAttributes();
Aspose.Imaging.ColorMatrix gcolormatrix = new Aspose.Imaging.ColorMatrix(colorMatrixElements);
gattributes.SetColorMatrix(gcolormatrix);
ga.DrawImage(tFrame, new System.Drawing.Rectangle(left, top, destwidth, destheight), 0, 0, srcwidth, srcheight, System.Drawing.GraphicsUnit.Pixel, gattributes);

And another FYI: Your reply above dated: 6-5
contains: -FrameOptions.Resoluition = new TiffRational(200);

There no longer is a .Resolution value - someone apparently removed that API…
I figured out how to set Resolution the hard way:
TiffRational rX = new TiffRational(200);
TiffRational rY = new TiffRational(200);
createOptions.Xresolution = rX;
createOptions.Yresolution = rY;

Thanks for your help,
Todd

Hi Todd,


Thanks for your feedback. After initial investigation, we’ve logged following issues in our issue tracking system for further investigation and resolution. We will keep you updated about these issues progress via this forum thread. Sorry for the inconvenience faced.

IMAGING-35528: Exception issue in setting pixel color
IMAGING-35529: DrawImage() with ImageAttributes object.

Moreover, we will solve the caching system that is being reworked in 1.9 it will work better and require less memory.


Currently you need to use the LoadPartialPixels method to pass the whole required rectangle and delegate to handle the loaded pixels. The pixels will come, whole pixels or by parts. Like if you require rectangle (0,0,1000,1000) there may come a smaller rectangle (0,0,1000,10) then again a smaller rectangle (0,10,1000,10) and so on until the whole area is covered. You need to store the pixels elsewhere and then use the save pixels to save them back, when all pixels were properly loaded. You should not save pixels during partial loading as this may
affect performance and lead to unpredictable results! only when the whole rectangle (0,0,1000,1000) has been
completed processing and method LoadPartialPixels has returned control then you may save the processed pixels back.


Hopefully your issues will be resolved in upcoming release i.e. 1.9. Sorry for the inconvenience faced.


Best Regards.
Hello,

I do not understand your LoadPartialPixels references.
There are no samples on how to use this command? The frame I am copying pixels from is a normal 2200 x 1700 pixel frame - NOT some even remotely close to the size referenced supported using that method (2,147,483,647 x 2,147,483,647 pixels). If I were to take a (0,0,1000,1000) rectangle of a 2200x1700 - how could it make any difference - since it works on pages 1 to 12, why would a sub-rectangle of one page make a difference on page 13?

I believe this problem is not related to to frame size - but to overall entire file size.
Besides, If I get this working and use my Dither code - it looks at up to a 9 pixel high by 9 pixel wide area to remove stray pixels - so I cannot 'sub-rectangle' size process a 2200x1700 sized frame without serious redesign - it should not be required to partially process a normal 11 x 8-1/2 inch 2200 x 1700 pixel frame.
My code used is no different than your samples provided for iterating through frames.

Is my conceptual layout above correct - to me I would think it is, pretty simply it:
  • iterates through the frames of the very large source TIF
    • create a copy of the pixels from each frame from the large TIF
    • save those pixels to a new frame of the same size
    • save the new frame to the base TIF
  • dispose of the pixels and temp frame before iterating to the next source Frame
Maybe my ideas are incorrect...


The problem as I see it appears to be your code to access a very large TIF and iterate through the frames (as shown in your sample code):
using (TiffImage pageImage = (TiffImage)Aspose.Imaging.Image.Load(copiedStream))
foreach (TiffFrame frame in ((TiffImage)pageImage).Frames)

...this fails on the the 9th to 13th frame attempting to only read the pixels from the frame:
Aspose.Imaging.Color[] pixels = frame.LoadPixels(frame.Bounds);

I do not understand - maybe the LoadPixels(..) attempts to load all pixels and then filter by the frame.Bounds or something. It should just index into the file by the frame index and read the defined size for that frame.

Could it be attempting to reload the image on each frame indexing re-reference?
I noticed it takes a very long time, like 3 to 5 seconds on the ...Image.Load(..) call to initially load the source TIF - and the exception is thrown attempting to load the 12th or 13th frame, and perhaps LoadPixels loads the entire tiff and gets its frame from the full amount?

FYI - The way I got this to work with Microsoft Imaging was to not load the image.
I opened a file reference to it, and requesting one at a time, a specific page number - setting that as the Active page and accessing its frame, processing, and writing. So the entire image was never opened at load. I did this as early attempts to load every frame into an Image[] array caused out of memory errors.
Is it possible in your code to only load a specific frame without loading the entire TIF?
>In MS Image - this is done with:

BitmapName.SelectActiveFrame(objDimension, pageIndex);

If it was - and I copied the pixels from that frame, converted them to grayscale, then saved to a new base TIF - I would think that would work...
I can find no reference to ActiveFrame other than an equate method - which to me would mean just copying the sourceframe to the ActiveFrame object in your code which looks like just a frame container. There should be some method in Aspose.Imaging to literally select a frame by index. Using image.Frames[index] - implies the entire image is loaded and you are just getting the frame[index]. My uneducated suggestion (since I know nothing of the internal workings of your code) would be to implement the SelectActiveFrame method in your code like MS, and rewrite the frames[index] to just call your new SelectActiveFrame method to get the requested frame - thus never loading the image content... I hope this helps - anything to get this resolved...

I attached my latest code - which includes use of an IDisposable external class and method to ensure DitherFrame is not retained between calls.
I also had luck seriously shrinking the size of the problem code.

I hope this info helps... and that 1.9 is available soon - we are already a month behind implementing Aspose into our product. I look forward to the next build...
Thank you,
Todd

Hi Todd,


Thank you for providing additional information. I’ve shared the details with development team and hopefully it will help to fix the issue. We will keep you updated about issue progress via this forum thread.

Thanks for your patience and cooperation.

Best Regards,

Hi Todd,

Thanks for your patience. We have a good news for you that IMAGING-35528 (Exception issue in setting pixel color) has been resolved and fix will be available in upcoming release of Aspose.Imaging for .NET 1.9. Please check following code snippet for the purpose. The code snippet tuned for performance and corrected too since the frame disposal may be used but it is better to let it be disposed when the parent TiffImage is disposed. Syntax may be used for the new Aspose.Imaging v1.9 only since v1.8 will allocate pixels in memory regardless Cache.CacheType = CacheType.CacheOnDiskOnly setting):

TiffImage timage = null;
try
{
    //... code excluded - see document.cs - that adds report header TIF to timage

    //...

    for (int i = 0; i < imagePaths.Length; i++)
    {
        using (Stream imageFile = new FileStream(imagePaths[i], FileMode.Open, FileAccess.Read))
        {
            byte[] tmpBytes = new byte[imageFile.Length];
            imageFile.Read(tmpBytes, 0, Convert.ToInt32(imageFile.Length));

            MemoryStream copiedStream = new MemoryStream(tmpBytes);
            copiedStream.Seek(0, SeekOrigin.Begin);

            using (TiffImage pageImage = (TiffImage)Aspose.Imaging.Image.Load(copiedStream))
            {
                foreach (TiffFrame frame in ((TiffImage)pageImage).Frames)
                {
                    Aspose.Imaging.Color[] pixels = frame.LoadPixels(frame.Bounds);

                    // note processing is much faster if you do not reference RGB properties and instead use the ToArgb() method and
                    // additionally please cache the white and black color instead calling each time Color.White or Color.Black
                    for (int x = 0; x < pixels.Length; x++)
                    {
                        // 0.3F,0.59F, 0.11F
                        int argb = pixels[x].ToArgb();
                        double r = (argb >> 16) & 0xff;
                        double g = (argb >> 8) & 0xff;
                        double b = (argb & 0xff);
                        double powerR = .3 * r;
                        double powerG = .59 * g;
                        double powerB = .11 * b;
                        double power = powerR + powerG + powerB;

                        if (power > 218)
                        {
                            pixels[x] = white;
                        }
                        else
                        {
                            pixels[x] = black;
                        }
                    }

                    // save pixels is not required for source frame unless you intend to use it somewhere else.
                    //frame.SavePixels(frame.Bounds, pixels);

                    long Diskremaining = Cache.AllocatedDiskBytesCount;
                    long Memremaining = Cache.AllocatedMemoryBytesCount;

                    // creation of a new frame is better to perform from scratch and then fill pixels.
                    // TiffFrame addframe = TiffFrame.CreateFrameFrom(frame, new Aspose.Imaging.ImageOptions.TiffOptions(createOptions));

                    TiffFrame addFrame = new TiffFrame(new Aspose.Imaging.ImageOptions.TiffOptions(createOptions), frame.Width, frame.Height);
                    try
                    {
                        // save modified pixels and save it as createOptions 1bpp G4 TIF
                        addFrame.SavePixels(frame.Bounds, pixels);

                        // add frame to base timage TIFF file
                        if (timage == null)
                        {
                            timage = new TiffImage(addFrame);
                        }
                        else
                        {
                            timage.AddFrame(addFrame);
                        }

                        pageCount++;
                    }
                    catch (Exception)
                    {
                        addFrame.Dispose();
                        throw;
                    }

                    addFrame.Save(@"C:\Temp\Page" + pageCount.ToString() + "_DCUsed" +
                    Diskremaining.ToString() + "_MCUsed" + Memremaining.ToString() + ".tif",
                    addFrame.FrameOptions);

                    // disposal is not required since it will be disposed when the parent container is disposed.
                    //frame.Dispose();
                } // end foreach frame
            } // end pageImage
        } // end using imageFile
    } // end foreach TIF file to add - there is only one in current testing
}
finally
{
    if (timage != null)
    {
        timage.Dispose();
    }
}

Additionally it is observed that memory consumption is still growing which is caused by the fact we save pixels back to the frame and by default (when Cache.CacheType = CacheType.Auto) the pixels are stored in the memory to enhance performance (we need to store the pixels somewhere in any case). When each new frame is added the memory significantly grows up to the point where CLR cannot allocate enough bytes and the observed FrameworkException may be thrown. For the mentioned scenario it is better to use Cache.CacheType = CacheType.CacheOnDiskOnly setting to allocate pixels on disk or may be rework the application to handle LoadPartialPixels instead LoadPixels method (however the performance will probably suffer for tiff having so much pages). If pixels are allocated on disk then processing will be pretty fast (for the mentioned scenario) but will perform slowly when saving the constructed output tiff file since we need to reconstruct each frame data from temporary files cached on disk. If the disk is SSD type then performance penalty is much lower than using traditional hard drive.

In either way so many information cannot fit into the memory until the user have installed enough memory and probably it is better to cache on disk. Per calculations performed we need about 80 megabytes to store one frame having 1700x2200 dimensions and probably about 9 gigabytes is required to fit all 111 pages into memory. Although the amount of memory arises from the fact we store managed objects and each object requires additional information to be stored along with the pixel data. If target PC has enough memory and CLR is configured properly to have at least 9 gigabytes of memory available then it is possible to fit the mentioned 111 page tiff into memory and caching on disk may be disabled. In the future we will probably reduce the memory required to store the pixel data but it requires massive refactoring and cannot be performed at the moment due to other priority tasks and the lack of resources available.

Please feel free to contact us for any further assistance.

Best Regards,

The issues you have found earlier (filed as IMAGING-33437) have been fixed in this update.


This message was posted using Notification2Forum from Downloads module by Aspose Notifier.

The issues you have found earlier (filed as ) have been fixed in this Aspose.Words for JasperReports 18.3 update.