Click here to Skip to main content
15,867,453 members
Articles / Web Development / ASP.NET
Article

An ASP.NET thumbnail solution

Rate me:
Please Sign up or sign in to vote.
4.61/5 (52 votes)
10 Dec 2002Ms-RL12 min read 585.3K   8.5K   266   97
An article describing a set of ASP.NET tools for generation of thumbnails and thumbnail views.

A screenshot

Test page of ThumbList control

Introduction

Welcome to my first article in CodeProject! The picture above should give an idea of what the code i developed does. I started this project after reading the (very good) ASP.NET tutorials of the Framework SDK. The DataList control gave me the idea to make a user control to display thumbnails in grid format. In order to generate thumbnails 'on the fly' i made a C# class and a C# HTTP handler. Part of the solution (although optional) is an ATL COM thumbnail-generator object. I have added useful features like paging and beveled thumbnails. After the first version of this article some people asked for comments below the images. In this second version i haved added comments and online editing of them. Since i don't have the VS.NET, developing was made using the free Web Matrix tool. It is a very nice tool with many design features, unfortunately the code editor is not so good yet. 

Following, I will describe how to use the thumbnail tools and then (briefly) important parts of the code. 

How to use the tools

The ASP.NET part of my thumbnail solution consists of the files PhilipSoft.Thumbnails.ThumbGenerator.cs, ThumbJpeg.ashx and ThumbList.ascx. The web.config file contains some application settings (appSettings), however all of them are optional. After downloading the zip and extracting the files, make the containing ThumbAspnet folder a virtual directory and point the browser to the ThumbDisplay.aspx page. This is a test page, an instance of which is shown at the figure above. Enter in the Path textbox a path of an IIS virtual-directory containing images and press the 'Regenerate thumbnails' button. You should see thumbnails of images residing in that directory. Try the other choices also and see the changes on the thumbnails. If you want the 'Use COM object' choise to work, you must register the ThumbExtract.dll found in the bin subfolder.  More on this COM object later. 

ThumbJpeg.ashx is an .NET-based HTTP handler that you can use in an <img> tag to produce a thumbnail dynamically. The thumbnail is not saved in disk but it is put in cache memory to be available for subsequent calls. If you change a parameter it will be generated again and not be taken from the cache. A typical use of the handler is shown below. 

The <a> link points to an image and the

<img>
tag specifies a dynamically generated thumbnail via its src attribute. 

<a href='/images/OLIMP012.jpg'>
<img src='ThumbJpeg.ashx?VFilePath=/images/OLIMP012.jpg&width=200&
height=200&Bevel=true' 
     alt='Click here'/></a> 

 Parameters to the HTTP handler are given in the form of a query string. They are the following:

  • VFilePath: Virtual path of original image. The only mandatory parameter. If the file specified does not exist or it is not an image, a "no thumbnail" default image is generated from the NoThumb.gif file. 
  • Width, Height: desired thumbnail size. If not given it is read from appSettings, if not specified in appSettings defaults to 150x150.
  • AllowStretch: Set to 'true' to allow stretching of thumbnail to fit the above size. If not given defaults to false.
  • Bevel: Set to 'true' to generate a beveled thumbnail, as shown in the image above. If not given defaults to false.
  • Refresh: Set to 'true' to refresh thumbnail (erase the cache version first). I've not used it and it is rather useless.
  • UseCOMobj: Set to 'true' to generate the thumbnail using the COM object implemented in ThumbExtract.dll (you must register it first). The ProgID for the COM object is 'ThumbExtract.FileThumbExtract'
  • ShowComments: Set to 'true' to show a comment (if exists) under the thumbnail. Comments are saved in an XML file named 'ThumbComments.xml' located in the same directory as the images.
  • AllowEdit: If it is set to 'true' an edit link allows you to edit the comment for each thumbnail. Then you press 'update' and the comment is saved in the XML file. 

A reason to use the COM object (by setting UseCOMobj property to 'true'), is its capability to generate thumbnails for more file types than the C# code. It exploits the shell interface (IExtractImage) responsible for generating thumbnails when you click a file or select the Thumbnail view in Explorer. For example see the image below. The object generated thumbnails for a DICOM (medical) image, an HTML file, a Powerpoint file and a Scribble (Visual C++ tutorial) file (drawing). I haved submited another article (Create Thumbnail Extractor objects for your MFC document types) about how to develop a COM object that can extract thumbnails for Scribbles and generally any file type by implementing the IExtractImage interface. In the zip download for that article you can find the source code for the COM component ThumbExtract.dll. In this article's zip you can find only the binary file.

Thumbnail using the COM object

ThumbList.ascx implements a user control (ThumbList) based on the DataList control that simplifies the creation of Web thumbnail views. Here are the properties of the ThumbList user control:

  • VPath: Virtual directory that you want to display its contents as thumbnails 
  • Filter: Filter to select the files for which you want to display thumbnails (e.g. *.jpg;*.gif)
  • Width, Height,AllowStretch,Bevel,Refresh,UseCOMobj: see explanations above
  • Columns: number of columns of the view
  • HeaderTitle: title appearing at the header of the control 
  • Sort: Set to true to sort by file name
  • AllowPaging,PageSize: Set AllowPaging=true to show pages containing PageSize thumbnails each
  • CurPage: Set to a value above 0 to define a current page. Normally you don't set this value in order to let user to define the current page by clicking on the page links at the footer of the control.
  • HideNavBar: Hide navigation bar located at the footer of the control
  • SaveThumbnails: Save every thumbnail (if not previously saved) to the hard disk and point to the saved thumbnail (and not to the HTTP handler). The thumbnail files will be saved in a 'thumbnail' subfolder below the folder corresponding to the virtual directory. This is a good option if you want to use the control in a busy Web site because it will save CPU time and increase resposiveness of the server (however if you let the user to choose between various thumbnail sizes then many small files will be created in your hard disk). Additionally, if your Web hosting provider does not support ASP.NET pages you can run a web spider program in your test server to create static HTML pages.

If you change the location of ThumbList.ascx (e.g. put it in a subfolder), you must put ThumbJpeg.ashx file in the same location. The ThumbDisplay.aspx page contains an instance of the control and manipulates its properties based on user selections.

Thumbnail generator class

The core of this thumbnail solution is the PhilipSoft.Thumbnails.ThumbGenerator.cs class. I encapsulated generation of thumbnails into a class since i can call it from many ASP.net pages and also from Windows Forms pages (i haven't tried this yet). After creating an instance, you set the thumbnail parameters by calling its SetParams(...) function. Then, you can get the thumbnail by calling the 

ExtractThumbnail()
function which returns a Bitmap corresponding to the thumbnail.  The GetUniqueThumbName() function returns a unique filename with respect to the parameters of the thumbnail. The code below is a part of the
ExtractThumbnail()
function that creates the thumbnail using the GetThumbnailImage of the Bitmap class. In order to retain the aspect ratio of the original image, i use the same subsampling factor f to derive the actual dimensions of the generated Bitmap.

C#
// create thumbnail using .net function GetThumbnailImage
bitmapNew = new Bitmap(_path); // load original image
if(!_bStretch) { // retain aspect ratio
  widthOrig = bitmapNew.Width;
  heightOrig = bitmapNew.Height;
  fx = widthOrig/_width;
  fy = heightOrig/_height; // subsampling factors
  // must fit in thumbnail size
  f=Math.Max(fx,fy); if(f<1) f=1;
  widthTh = (int)(widthOrig/f); heightTh = (int)(heightOrig/f);
}
else {
  widthTh = _width; heightTh = _height;
}
bitmapNew = (Bitmap)bitmapNew.GetThumbnailImage(widthTh, heightTh,
  new Image.GetThumbnailImageAbort(ThumbnailCallback),IntPtr.Zero);
if(!_bBevel) return bitmapNew;
}
public bool ThumbnailCallback() { return false; }

If you choose to create the thumbnail using the COM object, the following code is executed:

C#
if(_oCOMThumb==null) _oCOMThumb = new FileThumbExtract();
_oCOMThumb.SetPath(_path);
_oCOMThumb.SetThumbnailSize(_width,_height);
IntPtr hBitmap = (IntPtr)_oCOMThumb.ExtractThumbnail();
bitmapNew = Bitmap.FromHbitmap(hBitmap);
_oCOMThumb.FreeThumbnail();

FileThumbExtract class is a wrapper class for the COM object, generated using the tlbimp.exe NET framework tool. I will not discuss its code, it is based on a sample from the GotDotNet site. The

ExtractThumbnail()
returns an HBITMAP handle (as a long value) which is used in the Bitmap.FromHbitmap static function to create the thumbnail (FromHbitmap function comes from the base Image class, unfortunately by mistake it is not listed in the documentation of the Bitmap class). An nice feature of the COM object is that it can generate thumbnails for URLs also !

Applying the bevel effect on the generated thumbnail was an interesting issue. After observing how Photoshop applies the effect i realized that i should draw at the borders of the thumbnail linear gradients with decreasing transparency (increasing A color value). C# GDI+ offers many capabilities and its use is much simpler than normal C GDI, so it was not difficult to implement the effect. See the code below (some lines omitted) for the implementation, may be you can use it to create a Web or Forms beveled button that draws itself based on parameters.  The bevel effect it creates is not perfect but it is satisfactory. Parameters of the effect (like bevel width) are fixed but you could make them adjustable. 

C#
// ---- apply bevel
int widTh,heTh;
widTh = bitmapNew.Width; heTh = bitmapNew.Height;
int BevW = 10, LowA=0, HighA=180, Dark=80, Light=255;
// hilight color, low and high
Color clrHi1 = Color.FromArgb(LowA,Light,Light,Light);
Color clrHi2 = Color.FromArgb(HighA,Light,Light,Light);
Color clrDark1 = Color.FromArgb(LowA,Dark,Dark,Dark);
Color clrDark2 = Color.FromArgb(HighA,Dark,Dark,Dark);
LinearGradientBrush br; Rectangle rectSide;

Graphics newG = Graphics.FromImage(bitmapNew);
Size szHorz = new Size(widTh,BevW);
Size szVert = new Size(BevW,heTh);
// ---- draw dark (shadow) sides first
// draw bottom-side of bevel
szHorz+=new Size(0,2); szVert+=new Size(2,0);
rectSide = new Rectangle(new Point(0,heTh-BevW),szHorz);
br = new LinearGradientBrush(
  rectSide,clrDark1,clrDark2,LinearGradientMode.Vertical);
rectSide.Inflate(0,-1);
newG.FillRectangle(br,rectSide);
// draw right-side of bevel
...
// ---- draw bright (hilight) sides next
...
// draw top-side of bevel
...
// draw left-side of bevel
...
// dispose graphics objects and return bitmap
br.Dispose(); newG.Dispose();
return bitmapNew;

Thumbnail HTTP handler

The ThumbJpeg.ashx file HTTP handler is responsible for sending the thumbnail to the output. Before creating it, it checks if a thumbnail created with the same parameters already exists in the cache. To enable this, cached thumbnails are associated with a key returned by the

GetUniqueThumbName()
function. If it exists, it retrieves it using the key, otherwise it uses the services of the ThumbGenerator class to get the thumbnail. Finally the thumbnail is sent to the response as a JPEG file:

C#
_oGenerator.SetParams(_path,_width,_height,_bStretch,_bBevel,_
                       bUseCOMobject);
Cache MyCache = context.Cache;
sCacheKey = _oGenerator.GetUniqueThumbName();
// --- remove from cache when we want to refresh
bool bRefresh = (context.Request["Refresh"]=="true");
if(bRefresh) MyCache.Remove(sCacheKey);
if(MyCache[sCacheKey] == null)
{ // the thumbnail does not exist in cache, create it...
  try {
    bitmap = _oGenerator.ExtractThumbnail();
    bFoundInCache=false;
  }
  catch(Exception e)  {
    // requested image cannot be loaded, try to load the
    // 'NoThumb' image
    ...
  }
}
else bitmap = (Bitmap)MyCache[sCacheKey];
context.Response.ContentType = "image/Jpeg";
bitmap.Save (context.Response.OutputStream, ImageFormat.Jpeg);

If the thumbnail bitmap is not found in the application cache, it is added to it using the Insert function. A dependency on the original image file is created so that if the original image changes the cached bitmap becomes obsolete and is removed from the cache. I have also set a sliding expiration of mins minutes. Independently of these settings, the ASP.NET cache system periodically removes objects from the cache so you don't have to worry about memory usage.

C#
 if(!bFoundInCache)  {
  CacheDependency dependency = new CacheDependency(_path);
  int mins; try {
    mins = int.Parse(ConfigurationSettings.AppSettings["SlidingExpireMinutes"]);
  } catch(ArgumentNullException ex) { mins=20; }
  MyCache.Insert(sCacheKey, bitmap ,dependency,
    Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(mins),
    CacheItemPriority.Default, new CacheItemRemovedCallback(RemovedCallback));
  dependency.Dispose();
 }
}

static public void RemovedCallback(String k, Object item, 
                                   CacheItemRemovedReason r) {
  ((Bitmap)item).Dispose();
}

ThumbList User Control

The user control implemented in ThumbList.ascx displays thumbnail views. It is based on an instance of a DataList which is an ASP.NET templated data-bound control. Creation of the data source and databinding is implemented in the function BindThumbList() listed below. As data source i use the DefaultView of a  DataTable named dtThumbs created in memory. The table has two columns, the Filename and the Comment. For each filename in the virtual directory (VPath) to be shown, a new row is added to the table. The XML comments file is loaded as a DataSet (using the ReadXml function). If it does not exist, it is created in memory. Then, for each row in the XML, a matching row is searched in the dtThumbs DataTable to set the comment. In order to support paging, i had to write additional code to select the files belonging to the each page. Unfortunately, DataList does not inherently support paging. Since the properties of the ThumbList control may have changed by the calling page, BindThumbList() is executed at every page load, except when the update command is executed.

C#
public void BindThumbList()
      {
      String[] files; int i;
      ArrayList arFilesAll = new ArrayList();
      try {
      if(_filter.Length==0 || _filter=="*.*") {
        files = Directory.GetFiles(_path);
        arFilesAll.AddRange(files);
      }
      else { // separate different filters with ';'
        String[] filters = _filter.Split(';');
        for(i=0; i<filters.Length; i++) {
          files = Directory.GetFiles(_path,filters[i]);
          arFilesAll.AddRange(files);
        }
      }
      // create the datasource (list of files)
      for(i=0; i<arFilesAll.Count; i++)
        arFilesAll[i] = Path.GetFileName((String)arFilesAll[i]);
      MyThumbList.Attributes["TotalFiles"] = arFilesAll.Count.ToString();
      if(_bSaveThumbnails) {
        _oGenerator = new ThumbGenerator();
        String pathThumbs = _path+"\\thumbnails";
        Directory.CreateDirectory(pathThumbs);
        } // end if save thumbs
      } catch(Exception exDir) { arFilesAll = new ArrayList(); }
      // sort file-list if requested
      if(Sort)
        arFilesAll.Sort();
        
      // page thumblist if requested
      ArrayList arFilesToShow;
      if(!AllowPaging)
         arFilesToShow = arFilesAll;
      else { // create a data source with only the page files
       int totalPages = (int)Math.Ceiling((float)arFilesAll.Count/PageSize);
       if(totalPages==0) totalPages=1;
       MyThumbList.Attributes["TotalPages"] = totalPages.ToString();
       if(CurPage<1) {
         // we have not given a page from caller, get it from hidden field
         try {
          CurPage = int.Parse(hdnCurPage.Value); //Request.Form["__EVENTARGUMENT"]);
         } catch(Exception exParse) { CurPage=1; }
        }
       if(hdnPrevPath.Value!=VPath) // restart page numbering
         CurPage = 1;
       Trace.Warn("BindThumbList: Current page=" + CurPage.ToString());
       // make sure current page is in the [1,totalPages] range
       if(CurPage>totalPages) CurPage=totalPages;
       else if(CurPage<1) CurPage=1;
       // store curPage in attributes and in hidden field
       MyThumbList.Attributes["CurPage"] = CurPage.ToString();
       hdnCurPage.Value = CurPage.ToString();
       // put files of the page in the dsPageFiles array
       int startIndex = (CurPage-1)*PageSize;
       int endIndex = Math.Min(CurPage*PageSize,arFilesAll.Count);
       arFilesToShow = arFilesAll.GetRange(startIndex, endIndex-startIndex );
      } // end define page

 
       // create in-memory DataTable to be the data source
      DataTable dtThumbs = CreateCommentsTable(); //see below for this function
      DataView dvCommentsFromXML = null;
      if(ShowComments || AllowEdit) {
        DataSet dsComments = ReadCommentsFromXML();
        dvCommentsFromXML = dsComments.Tables[0].DefaultView;
      }
      // add rows with filenames
      for(i=0; i<arFilesToShow.Count; i++) {
        // Response.Write(arFilesToShow[i]);
        DataRow dr = dtThumbs.NewRow();
        dr[0] = arFilesToShow[i];
	dtThumbs.Rows.Add(dr);
      } // next file
      // add existing comments
      if((ShowComments || AllowEdit) && dvCommentsFromXML!=null) {
	for(i = 0; i < dvCommentsFromXML.Count; i++) {
	  String sFilename=((String)dvCommentsFromXML[i][0]).Trim();
           DataRow[] foundRows = dtThumbs.Select("Filename = '"+sFilename+"'");
           if(foundRows.Length>0) 
            foundRows[0][1] = dvCommentsFromXML[i][1]; // copy comment
 	}
      }
 
      MyThumbList.DataSource = dtThumbs.DefaultView;
      MyThumbList.DataBind();
} // end method

When the Update button is pressed, the ThumbList_UpdateCommand function is executed to update the XML file having the comments. By exploiting the XML reading/writing capabilities of the DataSet, i treat the XML comments file as a relational table and thus i can easily change my datasource to a traditional database (e.g. an Access file). I chose the XML solution because it is convenient for a small database and you can edit it by hand if necessary. You can safely add HTML tags in the comments because when the file is saved the '<' and '>' characters are escaped and thus the XML structure is not broken. Note also that in the previous version of this thumbnail control i had the DataList EnableViewState property set to 'false' and this prevented the update command to be executed. When i put the proporty to 'true' the command was executed normally.

C#
void ThumbList_UpdateCommand(Object sender, DataListCommandEventArgs e)
{
  DataRowView drvTarget;
  String sComment = (String)((TextBox)e.Item.FindControl("txtComment")).Text;
  String sFilename = ((TextBox)e.Item.FindControl("txtFilename")).Text;

  DataSet dsComments = ReadCommentsFromXML();
  DataView dvCommentsFromXML = dsComments.Tables[0].DefaultView;
  dvCommentsFromXML.RowFilter =  "Filename='"+sFilename+"'";
  // find row for filename or create a new one if does not exist
  if (dvCommentsFromXML.Count > 0) {
     drvTarget = dvCommentsFromXML[0];
     dvCommentsFromXML.RowFilter = "";
  }
  else {
    drvTarget = dvCommentsFromXML.AddNew();
    drvTarget[0] = sFilename;
  }
  drvTarget[1] = sComment;
  drvTarget.EndEdit();
  dsComments.WriteXml(_path +"\\ThumbComments.xml");

  MyThumbList.EditItemIndex = -1;
  BindThumbList();
 }

 DataSet ReadCommentsFromXML() {
   DataSet dsComments = new DataSet("ThumbnailDataset");
   // read comments from XML file
   try {
      dsComments.ReadXml(_path +"\\ThumbComments.xml");
   } catch(Exception exRead) { }
   if(dsComments.Tables.Count==0)
     dsComments.Tables.Add(CreateCommentsTable());
   return dsComments;
  }

 DataTable CreateCommentsTable() {
  DataTable dtThumbs = new DataTable("ThumbComment");
  DataColumn dcPrimary = new DataColumn("Filename", typeof(string));
  dtThumbs.Columns.Add(dcPrimary);
  dtThumbs.Columns.Add(new DataColumn("Comment", typeof(string)));
  dtThumbs.PrimaryKey = new DataColumn[] { dcPrimary };
  dtThumbs.CaseSensitive = false;
  return dtThumbs;
  }

The item template specifies a thumbnail which links to the original image. You can see that we have flexibility for databinding expressions. ThumbUrl is a function that creates the link to the thumbnail (the parametrised HTTP handler or the saved thumbnail if SaveThumbnails is true). AltString is a function that creates a string with the filename and the size of the original image file.

C#
<ItemTemplate>
  <a href="<%# String.Format("{0}/{1}",_vpath,
    ((DataRowView)Container.DataItem)["Filename"]) %>" > 
   <img border="0" 
     src="<%# ThumbUrl((String)((DataRowView)Container.DataItem)["Filename"]) %>"
     alt="<%# AltString((String)((DataRowView)Container.DataItem)["Filename"]) %>" />
  </a>
  <%# _bShowFilenames?"<br/>"+((DataRowView)Container.DataItem)["Filename"]:"" %>
  <%# ShowComments?"<br/>"+((DataRowView)Container.DataItem)["Comment"]:"" %>
  </br><asp:LinkButton id="button1" Visible='<%# AllowEdit ? true:false %>' 
      Text="Edit" CommandName="Edit" runat="server"/>
</ItemTemplate>
The trickiest part was how to implement the page links and respond to them. The page links are created inside the DataList control footer with code executed in the handler of  the DataBound event. I chose that event because at that time databinding has occured and we know how many pages we need. At first i created  page links as LinkButton controls and defined a common command handler. Inside the handler, the page number was determined from the CommandEventArgs. However i had to databind again to show the page that the user selected. I found a better solution to avoid the double databinding by exploiting the RegisterClientScriptBlock function of the Page class. At page load a GoToPage client javascript function is added (see the code below). This function is executed by the page links. It sets the hdnCurPage hidden field's value equal to the argument n (page number). The  ClientID property permits to access a server control from the client side! After postback we can retrieve the page number from the hidden field at page load (see also the BindThumbList() function above). The GetPostBackEventReference function of the
Page
class returns a reference to the postback function that resubmits the form. This is important because if you create a simple link to the same page and the form is not resubmitted, the server controls lose their state. 
C#
void Page_Load(Object Src, EventArgs e)
{
// register client script to go to a next page
StringBuilder scriptb = new StringBuilder();
scriptb.Append("<script
language="\""javascript\">\n");
scriptb.Append("//<!--\n function GoToPage(vpath,n) { \n");
scriptb.AppendFormat("document._ctl0.{0}.value=n; \n",hdnCurPage.ClientID);
scriptb.Append(Page.GetPostBackEventReference(this));
scriptb.Append("\n } \n//-->\n </");
scriptb.Append("script>");
 
if(!Page.IsClientScriptBlockRegistered("clientGotoPageScript"))
  Page.RegisterClientScriptBlock("clientGotoPageScript",scriptb.ToString());
 
// if not in update, bind every time since parameters may have change
if(MyThumbList.EditItemIndex < 0)
   BindThumbList();
}

The following code snippet shows how the "Next >>" navigation button is created. plLinks is a PlaceHolder server control inside the DataList footer. The reason to include the VPath in the link is that i want the color of links (visited color or not) to be dependent on page number and also on the virtual directory. Other page navigation links are created similarly.

C#
plLinks.Controls.Add(new LiteralControl(String.Format(
  "  <A href=\"javascript:GoToPage('{0}',{1});\">Next >></A>",VPath,CurPage+1)));

Conclusion

I hope that you'll find my thumbnail solution useful and use it. I am not a professional Web developer and i cannot test it in a Web site, however i use it to see thumbnails from CDs with images! (my system has Win2000 Pro with PWS installed).  I enjoyed writing the code and actually was my first C# code. The ASP.NET model simplifies Web programming and makes it similar to desktop programming. Finally, i would propose to anyone interested to rewrite the ThumbList control as a custom (rendered) control because according to documentation rendering is faster that composition. Hidden fields can be emitted programmatically using the RegisterHiddenField method of the Page class. You could also derive the user control from the DataList control and override some functions .. i guess :)

License

This article, along with any associated source code and files, is licensed under Microsoft Reciprocal License


Written By
Web Developer Forthnet
Greece Greece
Software developer and Microsoft Trainer, Athens, Greece (MCT, MCSD.net, MCSE 2003, MCDBA 2000,MCTS, MCITP, MCIPD).

Comments and Discussions

 
GeneralRe: I've got a problem with paging. [modified] Pin
k3nn3thcp9-Jan-07 19:22
k3nn3thcp9-Jan-07 19:22 
GeneralRe: I've got a problem with paging. Pin
Teddy Salad29-Mar-07 4:14
Teddy Salad29-Mar-07 4:14 
GeneralRe: I've got a problem with paging. Pin
Teddy Salad30-Mar-07 2:36
Teddy Salad30-Mar-07 2:36 
GeneralRe: I've got a problem with paging. Pin
Mangore4-Feb-09 10:21
Mangore4-Feb-09 10:21 
Generalphilipos question in making thumbnails for HTML files Pin
r.waymen12-Jun-06 20:34
r.waymen12-Jun-06 20:34 
GeneralMissing file Pin
StrickS25-Jan-06 10:46
StrickS25-Jan-06 10:46 
GeneralAutomatic thumbnail generation Pin
zioturo1-Nov-05 23:37
zioturo1-Nov-05 23:37 
GeneralRe: Automatic thumbnail generation Pin
Dmitry Kirsanov26-Feb-07 7:52
Dmitry Kirsanov26-Feb-07 7:52 
GeneralThumbnail preview only works for images Pin
bigbollogs24-May-05 9:36
bigbollogs24-May-05 9:36 
Generalproblem deleting images (permissions) Pin
edonistart31-Mar-05 19:34
edonistart31-Mar-05 19:34 
GeneralRe: problem deleting images (permissions) Pin
Anonymous23-May-05 21:17
Anonymous23-May-05 21:17 
GeneralRe: problem deleting images (permissions) Pin
edonistart23-May-05 21:28
edonistart23-May-05 21:28 
GeneralRe: problem deleting images (permissions) Pin
andré_k26-May-05 18:43
andré_k26-May-05 18:43 
GeneralRe: problem deleting images (permissions) Pin
edonistart26-May-05 20:03
edonistart26-May-05 20:03 
GeneralRe: problem deleting images (permissions) Pin
smitty_cool27-Nov-06 17:59
smitty_cool27-Nov-06 17:59 
Questionto smitty_cool have u any luck on file lock? Pin
k3nn3thcp18-Dec-06 20:22
k3nn3thcp18-Dec-06 20:22 
Generalopening the images in a new html page !! Pin
Member 130039520-Sep-04 11:58
Member 130039520-Sep-04 11:58 
GeneralRe: opening the images in a new html page !! Pin
andré_k26-May-05 19:26
andré_k26-May-05 19:26 
QuestionHow about keeping the apect ratio Pin
asdasdsdaas6-Jun-04 22:36
asdasdsdaas6-Jun-04 22:36 
GeneralProblem with thumbnails. Pin
locco15-Jul-03 9:15
locco15-Jul-03 9:15 
GeneralRe: Problem with thumbnails. Pin
Anonymous7-Aug-03 6:21
Anonymous7-Aug-03 6:21 
GeneralRe: Problem with thumbnails. Pin
Valtur7-Aug-03 6:21
Valtur7-Aug-03 6:21 
GeneralRe: Problem with thumbnails. Pin
Philipos Sakellaropoulos12-Mar-04 5:12
professionalPhilipos Sakellaropoulos12-Mar-04 5:12 
GeneralRe: Problem with thumbnails. Pin
SpinXXX29-Apr-04 5:53
SpinXXX29-Apr-04 5:53 
GeneralRe: Problem with thumbnails. Pin
Dinomite12-Jul-05 3:40
Dinomite12-Jul-05 3:40 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.