|
TreeView's way is better.
|
|
|
|
|
Ye I guess it might be, when you first explore the way they work, and figure tag functions
|
|
|
|
|
So, I gave this a try today for my ImageViewer UserControl (See my articles for more detail on it). And people have requested me to implement Multi-Page TIFF support.
Now I have been trying lots of different techniques for it but none of them seem to really work. My UserControl accepts images in 2 different ways. By passing in a FilePath or an Image through properties. Both these properties end up with having storing the image into a Bitmap.
Now this Bitmap is used in my Draw methods and if I try to do a SelectActiveFrame() it crashes on me with GDI+ An generic error has occured ExternalException (0x80004005).
What I tried to do is creating a new Bitmap of the original and then doing the SelectActiveFrame() and that did not crash. However it did not display either.
Here is a sample of my code from my DrawObject class:
pages = this.bmp.GetFrameCount(System.Drawing.Imaging.FrameDimension.Page);
currentPage = 0;
if (pages > 1) { multiPage = true; } else { multiPage = false; }
public void NextPage()
{
try
{
if (this.bmp != null)
{
int nextPage = this.currentPage + 1;
if (nextPage <= this.pages)
{
Bitmap myImg = new Bitmap(this.bmp);
myImg.SelectActiveFrame(System.Drawing.Imaging.FrameDimension.Page, nextPage);
this.bmp.Dispose();
this.bmp = null;
this.bmp = myImg;
currentPage = nextPage;
}
}
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show("ImageViewer error: " + ex.ToString());
}
}
And here is the code that calls the NextPage() function:
drawing.NextPage();
pbFull.Refresh();
UpdatePanels(true);
And PreviousPage() is exactly the same but with a minus ofcourse.
Any help would be much appreciated, I've been staring at it for hours now
|
|
|
|
|
Hi,
I don't expect "new Bitmap(image)" to return a multi-page image, so what you should try is select the page you want in the original image, then create a new bitmap from it.
there are some CodeProjects about multi-page TIFF images, here[^] is one.
|
|
|
|
|
Well that is exactly what I tried to do Originally, and I already looked at the exact multi-page tiff viewer. The problem is, within the viewer when switching to the next page it loads the entire TIFF file again and then makes a Bitmap of it.
The problem with this is, my UserControl doesn't neccesarily has to have a file path (Because it can be passed in programmetically aswell). And to store the original TIFF file next to the Bitmap it would mean that I need double the resource for the same image. And once the TIFF file is loaded, there is no way to tell when opening a new image (going to next page for example) if it's
A.) The same TIFF file.
B.) Actually a Multi-Page TIFF file.
What this means is that I have no idea when to Dispose() the original TIFF file which would result in using unneccesary resources. With Multi-page TIFF files this could be ALOT!
I also tried Cloning the object but when I do that it gets locked and I get the same GDI+ generic error. Believe me I tried so many things.
I was just hoping someone would be like.. You forgot this little line.
Thanks for your help tho
modified on Thursday, April 29, 2010 8:03 AM
|
|
|
|
|
Jordy "Kaiwa" Ruiter wrote: to store the original TIFF file next to the Bitmap it would mean that I need double the resource for the same image
I don't think so. You load the (multi-page) image once, and keep one (or more) references to it; and you need a bitmap that represents one page, that will cost you a fraction of the multi-page image.
You could encapsulate things in a little class (more error handling may be needed):
class MultiPageImage {
private Image image;
public Image Image {
get {
return image;
}
set {
if (image!=null) image.Dispose;
image=value;
}
}
public Bitmap GetBitmap() {
if (image==null) return null;
return new Bitmap(image);
}
public Bitmap GetBitmap(int pageNumber) {
if (image==null) return null;
image.SelectActiveFrame(System.Drawing.Imaging.FrameDimension.Page, nextPage);
return new Bitmap(image);
}
}
Warning: if you don't actually copy the multi-page image, the current page setting is affecting both this class and the external image users. For perfect encapsulation, one would have to copy the image in the setter property.
|
|
|
|
|
Damn.. Unbelievable, I just implemented this entire thing. Took like half an hour to find out that it gives me the exact same error. {"A generic error occurred in GDI+."} System.Exception {System.Runtime.InteropServices.ExternalException}
Any other ideas?
|
|
|
|
|
What happened to your other message, the one with:
Jordy "Kaiwa" Ruiter wrote: Woah.. You're right! Why didn't I think of something like that? Well I'm gonna give it a try then
I think I've stared at the same code for too long to come up with this! I'll let you know the outcome!
you are not supposed to remove messages, just keep the thread flow intact, as laid out in the forum guidelines.
Jordy "Kaiwa" Ruiter wrote: the exact same error.
you should provide more information; where does this occur? under what circumstances?
is it always the same frame of the same image that fails? try some others. What is the source of your multiTIFF?
Everything that fails inside GDI+ is reported as a "Generic error", making it hard to pinpoint. Is there some other utility that reads and shows all pages correctly?
If you suspect an early Dispose() call, just remove them all to see if that helps; this is only a test, NOT a recommendation.
|
|
|
|
|
Ah sorry, I figured a double post wasn't really nice either. But anyway. I found a "fix". It seems that if I use Bitmap.FromFile() to open the TIFF file that browsing through pages is possible.
And the first post explained exactly the issue, with it being the same error i ment the same function that crashes SelectActiveFrame()
I'm going to try and work it out with Bitmap.FromFile() instead of Bitmap.FromStream() .
|
|
|
|
|
IIRC there is a little note in the FromStream() documentation that states one should keep the stream open as long as the image is alive; you now have discovered a very good reason for this unexplained statement.
|
|
|
|
|
That actually makes alot of sense yes. I solved it with a different approach just working out the last issues with dragging and dropping
Thanks for your help! (A copy of the code will soon be updated in my article if you are interested )
|
|
|
|
|
|
Hi,
I am working on a website and on the home page we have a pdf file link. The moment user clicks on that link the control takes the user to new URL, also displays the URL in the Address line of Browser, where the PDF file exists. However I don't want to show this URL to user, so that he can't copy and paste that URL in another browser.
Is there any way possible to hide such details or is it possible to just download the pdf without showing the URL (one where PDF file actually exists) in the address line of the browser. If user is able to download also it is fine. The only thing we need is to hide the URL.
Thanks in Advance!!
|
|
|
|
|
you can zip that pdf then user download it wirhout opening in another browser
|
|
|
|
|
You can use the Content-Disposition HTTP header to force the file to download and not open in the browser. No zipping required.
|
|
|
|
|
If you are using ASP.NET you can create an aspx site where you check if the user
has the right to download/see the pdf (maybe through a temp guid). If he has the right, then you can
send this pdf through the response stream to the client pc.
Example:
.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="GetPDF.aspx.cs" Inherits="[namespace].GetPDF" %>
.cs
public partial class GetPDF : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
try
{
Response.Clear();
Response.ContentType = "application/pdf";
Response.BufferOutput = true;
Response.Cache.SetNoServerCaching();
Response.Cache.SetNoStore();
Response.OutputStream.Write(buffer, 0, buffer.Length);
}
catch (Exception)
{
}
}
}
Maybe the user sees the url "http://.../GetPDF.aspx?querystring" but through your check, copy and paste the url
will not work. (You could create a temp guid to access the pdf for the user, provide it in the querystring and delete
this temp guid after downloading. On the next call of this url the user will not be able to download it again.)
Hope this helps.
Edit:
In addition to the example above, you can also use the session object to check if the user has the rights to access the pdf file. Just set a session value (like Session["UserCanAccessPDF"] = true; ) on link click event and check this session value on GetPDF::Page_Load. If the session value is invalid or not set, just redirect to an error page (or something else). If the value is valid, send the pdf trough the stream and delete the session value.
Greetings
Covean
modified on Thursday, April 29, 2010 7:01 AM
|
|
|
|
|
Assuming ASP.Net...
Create a button. In the click handler, write the file to the HTTP response, as the previous poster suggested. That way, you aren't using a different URL. The only way they can get the file would be to click the button. You can have whatever logic you like to decide when to display that button, or if they manage to click the button when they are not allowed, you can add additional validation to prevent the download. You could, for example, validate that the user has never downloaded the PDF before so that they can't download it a second time. If they have already downloaded it, you could show a message that says "sorry, but you are only allowed to download this PDF once". The PDF data you return can come from the server file system or from a database on the server (or even from another server). Where you want to get the PDF from is up to you.
|
|
|
|
|
|
Not sure that's what the OP is after, but perhaps you should redirect your answer to the OP anyway. It's certainly going to do me no good.
|
|
|
|
|
ups... sorry aspdotnetdev! ok! my answer was:...............
Perhaps you can use Server.Transfer("url");[^] instead of Response.Redirect("url");.....
good luck
|
|
|
|
|
Hi.
I have an array of images like:
Image[] images = new Image[3];
After populating it with three images, i want to remove all of them and prepare it for the next set of three images by clearing the array. i have tried:
images.Clear();
as in an array but this does not work. How do i remove the images?
Thank you in advance.
Wamuti: Any man can be an island, but islands to need water around them!
Edmund Burke: No one could make a greater mistake than he who did nothing because he could do only a little.
|
|
|
|
|
Have you tried repeating step 1
images = new Image[3];
Never underestimate the power of human stupidity
RAH
|
|
|
|
|
Wamuti wrote: How do i remove the images?
What do you mean by "remove"? you can't remove anything from an array, each element will be there, all you can do is replace it, possibly by null.
If you want a variable number of elements, use a real collection such as a List<Image>
If you are worried about memory clean-up (and you should), then call Dispose() on each non-null element before replacing it by something else (unless the same image is still needed elsewhere).
|
|
|
|
|
If you want the elements to vary and you want to keep using an array and you don't want to reference a new array, you could always try:
Image[] images = new Image[3];
Array.Resize<Image>(ref images, 0);
Array.Resize<Image>(ref images, 4);
|
|
|
|
|
Two days in row, two different questions (yesterday's problem is solved by the way )
This is another one where I need some creative ideas...
I need to find all groups of items in an array. In this case same items in a different order means same group. The array/set/... is prepared by some methods that are executed earlier. This means I could start with 1 item, but with 250 items as well.
Let's suppose the generated array/set/... contains 5 items A, B, C, D and E. The groups I should get as result are the following:
A - B - C - D - E
AB - AC - AD - AE - BC - BD - BE - CD - CE - DE
ABC - ABD - ABE - ACD - ACE - ADE - BCD - BCE - BDE - CDE
ABCD - ABCE - ABDE - ACDE - BCDE
ABCDE
I don't need to reuse the combinations afterward. I just need the algorithm to perform a check routine on each group (and it occurs on only one place in my program). A little like "loop { check(group) }"
Thanks in advance for your ideas!
modified on Friday, April 30, 2010 4:21 AM
|
|
|
|