上面连个压缩文件图标和exe图标都是这样生成的
我改写了一下用来获取文件图标,用C#,winform实现。不过写的有点烂,希望大家积极改进。(后面有译文)
我不断的设置断点,由于我想保存超大图标所以首先改变size
文件大小int size = 128;
这样就会使程序运行至public static Bitmap loadJumbo(string lookup)
方法获取我要的特大图标。
我设置了public static Bitmap bmp;
静态变量,保存我要的图标。
随后回到Fom1中,当点击执行时,
FileToIconConverter.Convert(textBox1.Text);
FileToIconConverter.bmp.Save(textBox2.Text, ImageFormat.Png);
方法一:生成bmp
方法二:保存到指定文件夹
生成的图标为256*256
你也可以将原文件名替换成文件夹名,就可以生成文件夹图标了
源文件来自:WPF Filename To Icon Converter
开发:C#,.net 3.5,WPF
Introduction
介绍
This article describes FileToIconConverter, which is a MultiBinding Converter that can retrieve an Icon from system based on a filename (exist or not) and size.
该文描述的是文件转图片程序使用方法,根据文件名和大小,通过多重绑定转换器,提取图标的功能。
Background
背景
I am working on a file explorer, which shows a file list, inside the filelist, which requires to place a file icon next to each file in a folder.
我正在做一个可以显示文件列表的文件管理器,在这个文件列表中,要求文档中的文件图标两两相邻。
In my first implementation, I added an Icon property in the data model of the file, it works fine. When I implements the Icon View, I added a Large Icon property, then I added Thumbnail property for the Thumbnail view support.
初次尝试,我为文件数据模型增加一个图标属性,效果不错。但当我需要是实现显示图标,我又添加大图标属性,然后又添加了缩略图属性,用来支持缩略图显示。
This implementation has a number of problems:
-
Three Bitmaps (Icon, LargeIcon, Thumbnail), five if we include ExtraLarge and Jumbo in the Datamodel. They are usually duplicated (e.g. folder with JPGs), and unused (who will change views regularly anyway).
-
The code that is not related to the DataModel shouldn't be placed there.
-
Icon resize (like the slidebar in Vista Explorer) becomes very difficult, as there are 3-5 properties to bind with.
这次出现了几个问题
-
三个Bitmap位图,(图标(Icon),大图标(LargeIcon),缩略图(Thumbnail)),如果再加上超大图标(ExtraLarge)和特大图标(Jumbo)的话,就有五种位图了。他们之间会存在重复,或未使用的情况。
-
与数据模型有关的代码不该放在实现部分。
-
图标可以缩放,由于有3-5种不同的位图显示,这会使实现变得困难。
So I changed my design. I believe a converter with cache is best suited for this purpose.
-
Icons are cached in a dictionary, file with same extension occupied only one copy of memory.
-
Load on demand (e.g. if the view needs an Icon, then load Icon only).
-
Reusable, coder just needs to bind filename and size
于是我改变了我的程序设计方法,我想把它做成一个图标缓存的转换器应该能达到我的目的
-
图标缓存在dictionary类中,相同扩展名的文件值占用一次内存。
-
根据需要载入图标(例如:如果需要这种图标,只要转换成这种就好了)。
-
可重用性,程序员,只需要绑定文件名和文件大小就可以获得文件的五种图标。
Thumbnails are loaded in separate thread (no longer jam the UI). Jumbo icon is shown before the thumbnail is loaded.
缩略图有单独的线程载入(这样就不会与UI载入拥堵了),特大图标在缩略图载入前显示出来。
How to Use?
怎样使用呢?
The converter is a MultiBinding Converter, which takes 2 parameters, filename and size:
-
Filename need not necessarily exist (e.g. abc.txt works)
-
Size determines which icon to obtain (Optional)
-
<= 16 - Small
-
<= 32 - Large
-
<= 48 - Extra Large
-
<= 100 - Jumbo
-
Otherwise, Thumbnail if it is an image, Jumbo if it is not an image.
-
多重绑定转换器,定义了两个参数,filename,文件名和size文件大小。
-
文件不要求一定存在,例如只要给定文件名和扩展名,就可以显示图标了。
-
文件大小选择性的决定获取那种图标。
-
<= 16 – 小图标
-
<= 32 – 大图标
-
<= 48 – 超大图标
-
<= 100 – 特大图标
-
否则,如果是图片文件则取缩略图,不是图片则取特大图标
-
<t:FileToIconConverter x:Name="converter" /> <Slider x:Name="slider" ... /> <TextBlock x:Name="fileName" ... /> <Image Height="{Binding ElementName=slider, Path=Value}" Width="{Binding ActualHeight}" Stretch="Uniform"> <Image.Source> <MultiBinding Converter="{StaticResource converter}"> <Binding ElementName="fileName" Path="Text"/> <!-- FileName --> <Binding ElementName="slider" Path="Value" /> <!-- Size, use DefaultSize if not specified --> </MultiBinding > </Image.Source> </Image>
How It Works?
如何工作的?
MultiBinding Converter is similar to the normal Binding IValueConverter except it takes multiple value to convert, the Convert is as shown below:
多重绑定转换器与常用的实现IValueConverter 接口类似,除非有多个值需要转换,转换方法如下:
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { int size = defaultSize; if (values.Length > 1 && values[1] is double) size = (int)(float)(double)values[1]; if (values[0] is string) return imageDic[getIconKey(values[0] as string, size)]; else return imageDic[getIconKey("", size)]; }
-
parameter 2 is converted to a local variable named size.
-
parameter 1 is converted to a Icon in imageDic with a key (getIconKey() method, see below).
-
参数1转换成imageDic(字典类)中的带键图标项
-
参数2转换成常量Size图片大小
Icons are retrieved based on Size and Extensions
-
Thumbnail
-
Image - Return WritableBitmap (new in .NET 3.5), which acts like BitmapImage but allows change after initialization.
-
Otherwise - treat as Icon
-
-
Jumbo / ExtraLarge
-
All (include EXE) - load from SystemImageList
-
-
Small / Large
-
Load using SHGetFileInfo (Win32 API) directly. I try to avoid SystemImageList because it has its own cache system which will cause some overhead.
-
-
根据图标大小和扩展名提取图标
-
缩略图
-
图片 – 返回WritableBitmap (.Net 3.5中的新类),与位图图片BitmapImage 类相似,不过此类初始化后可变,类似于Stringbuilder
-
-
特大图标和超大图标
-
所有文件(包括Exe文件)都是加载至SystemImageList
-
-
小图标/大图标
-
使用Win32API中的SHGetFileInfo加载图片 。这是为了尽量避免都使用 SystemImageList ,导致缓存占用过多
-
There are two caches, iconCache and thumbnailCache, all Icons and thumbnail are stored in cache.
-
iconCache is static, for small - Jumbo Icons, common for all FileToIconConverter.
-
thumbnailCache is instanced, for thumbnail, you can call ClearInstanceCache() method to clear this cache.
-
addToDic() method will add the Icon or Thumbnail (from getImage()) to its cache
-
returnKey() method will return a key for dictionary based on fileName and size,
-
e.g. (".txt+L" for Large Text Icon, ".jpg+S" for Small JPEG icon)
-
-
loadBitmap() method takes a Bitmap and return a BitmapSource. It's actually callingImaging.CreateBitmapSourceFromHBitmap() method, and is required because Image UIelement does not take a bitmap directly.
包括两种两种图标缓存,iconCache和thumbnailCache,所有图标和缩略图都保存在内存里。
-
iconCache 是静态的,对于从小到特大之间的图标, FileToIconConverter来说都是公用的。
-
thumbnailCache 是实例化生成的,对于缩略图,可以调用ClearInstanceCache() 清除实例内存。
-
addToDic() 方法将图标或是缩略图添加到缓存中
-
returnKey() 方法返回基于filename和size生成的键key(例如".txt+L"表示大文本图标,".jpg + S"表示小位图图标)
-
loadBitmap() 方法如入Bitmap,返回BitmapSource,实际上是调用了Imaging.CreateBitmapSourceFromHBitmap()方法,这是由于图片UIelement 不直接读入 Bitmap 才采用的方法。
getImage() method retrieves Icon and Thumbnail, its thumbnail loading code looks like below:
getImage() 方法更新图标和缩略图,载入缩略图的代码如下所示:
//Load as jumbo icon first. WriteableBitmap bitmap = new WriteableBitmap (addToDic(fileName, IconSize.jumbo) as BitmapSource); ThreadPool.QueueUserWorkItem(new WaitCallback(PollThumbnailCallback), new thumbnailInfo(bitmap, fileName)); return bitmap;
The code will try to load the jumbo icon first, which is usually cached already, and much faster to load not cache, then when the processor is free, it will call PollThumbnailCallback() in background thread. This implementation will prevent UI thread hogging problem.
该段代码尝试首先载入早以缓存的特大图标,这样可以加快速度,然后当处理器空闲时,调用PollThumbnailCallback() 后台线程运行,这可以解决UI线程受阻的问题。
PollThumbnailCallback() method is not too complicated. It actually gets and resizes the thumbnail bitmap (line 4-8), turns it to BitmapSource (Line 9-C), and writes it to the WriteableBitmap obtained (Line 6, D-Q). Line M to Line Q is executed in UI thread, so the only work that is required to process the writeBitmap is placed there.
PollThumbnailCallback() 方法不是很复杂,实际上只是得到和缩放位图bitmap缩略图,生成BitmapSource ,并把它写入WriteableBitmap ,第M-N行执行UI线程,所以唯一要做的就是运行writeBitmap方法。
private void PollThumbnailCallback(object state) 2) { 3) //Non UIThread 4) thumbnailInfo input = state as thumbnailInfo; 5) string fileName = input.fullPath; 6) WriteableBitmap writeBitmap = input.bitmap; 7) Bitmap origBitmap = new Bitmap(fileName); 8) Bitmap inputBitmap = resizeImage(origBitmap, new System.Drawing.Size(256, 256)); 9) BitmapSource inputBitmapSource = Imaging.CreateBitmapSourceFromHBitmap(inputBitmap.GetHbitmap(), A) IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); B) origBitmap.Dispose(); C) inputBitmap.Dispose(); D) int width = inputBitmapSource.PixelWidth; E) int height = inputBitmapSource.PixelHeight; F) int stride = width * ((inputBitmapSource.Format.BitsPerPixel + 7) / 8); G) byte[] bits = new byte[height * stride]; H) inputBitmapSource.CopyPixels(bits, stride, 0); I) inputBitmapSource = null; J) writeBitmap.Dispatcher.Invoke(DispatcherPriority.Background, K) new ThreadStart(delegate L) { M) //UI Thread N) Int32Rect outRect = new Int32Rect(0, (int)(writeBitmap.Height - height) / 2, width, height); O) writeBitmap.WritePixels(outRect, bits, stride, 0); P) })); Q) }