c#做动态(gif)中文验证码
无意中在国外论坛发现一个gif动画类,我使用它来制作了一个动态验证码 ;
一:首先新建一个类库
1:新建AnimatedGifEncoder类
View Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
|
using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using System.Text; namespace Common.Gif { #region Java /** * Class AnimatedGifEncoder - Encodes a GIF file consisting of one or * more frames. * <pre> * Example: * AnimatedGifEncoder e = new AnimatedGifEncoder(); * e.start(outputFileName); * e.setDelay(1000); // 1 frame per sec * e.addFrame(image1); * e.addFrame(image2); * e.finish(); * </pre> * No copyright asserted on the source code of this class. May be used * for any purpose, however, refer to the Unisys LZW patent for restrictions * on use of the associated LZWEncoder class. Please forward any corrections * to kweiner@fmsware.com. * * @author Kevin Weiner, FM Software * @version 1.03 November 2003 * */ #endregion public class AnimatedGifEncoder { protected int width; // image size protected int height; protected Color transparent = Color.Empty; // transparent color if given protected int transIndex; // transparent index in color table protected int repeat = -1; // no repeat protected int delay = 0; // frame delay (hundredths) protected bool started = false ; // ready to output frames // protected BinaryWriter bw; //protected FileStream fs; protected Stream fs; protected Image image; // current frame protected byte [] pixels; // BGR byte array from frame protected byte [] indexedPixels; // converted frame indexed to palette protected int colorDepth; // number of bit planes protected byte [] colorTab; // RGB palette protected bool [] usedEntry = new bool [256]; // active palette entries protected int palSize = 7; // color table size (bits-1) protected int dispose = -1; // disposal code (-1 = use default) protected bool closeStream = false ; // close stream when finished protected bool firstFrame = true ; protected bool sizeSet = false ; // if false, get size from first frame protected int sample = 10; // default sample interval for quantizer /** * Sets the delay time between each frame, or changes it * for subsequent frames (applies to last frame added). * * @param ms int delay time in milliseconds */ public void SetDelay( int ms) { delay = ( int )Math.Round(ms / 10.0f); } /** * Sets the GIF frame disposal code for the last added frame * and any subsequent frames. Default is 0 if no transparent * color has been set, otherwise 2. * @param code int disposal code. */ public void SetDispose( int code) { if (code >= 0) { dispose = code; } } /** * Sets the number of times the set of GIF frames * should be played. Default is 1; 0 means play * indefinitely. Must be invoked before the first * image is added. * * @param iter int number of iterations. * @return */ public void SetRepeat( int iter) { if (iter >= 0) { repeat = iter; } } /** * Sets the transparent color for the last added frame * and any subsequent frames. * Since all colors are subject to modification * in the quantization process, the color in the final * palette for each frame closest to the given color * becomes the transparent color for that frame. * May be set to null to indicate no transparent color. * * @param c Color to be treated as transparent on display. */ public void SetTransparent(Color c) { transparent = c; } /** * Adds next GIF frame. The frame is not written immediately, but is * actually deferred until the next frame is received so that timing * data can be inserted. Invoking <code>finish()</code> flushes all * frames. If <code>setSize</code> was not invoked, the size of the * first image is used for all subsequent frames. * * @param im BufferedImage containing frame to write. * @return true if successful. */ public bool AddFrame(Image im) { if ((im == null ) || !started) { return false ; } bool ok = true ; try { if (!sizeSet) { // use first frame's size SetSize(im.Width, im.Height); } image = im; GetImagePixels(); // convert to correct format if necessary AnalyzePixels(); // build color table & map pixels if (firstFrame) { WriteLSD(); // logical screen descriptior WritePalette(); // global color table if (repeat >= 0) { // use NS app extension to indicate reps WriteNetscapeExt(); } } WriteGraphicCtrlExt(); // write graphic control extension WriteImageDesc(); // image descriptor if (!firstFrame) { WritePalette(); // local color table } WritePixels(); // encode and write pixel data firstFrame = false ; } catch (IOException e) { ok = false ; } return ok; } /** * Flushes any pending data and closes output file. * If writing to an OutputStream, the stream is not * closed. */ public bool Finish() { if (!started) return false ; bool ok = true ; started = false ; try { fs.WriteByte(0x3b); // gif trailer fs.Flush(); if (closeStream) { fs.Close(); } } catch (IOException e) { ok = false ; } // reset for subsequent use transIndex = 0; fs = null ; image = null ; pixels = null ; indexedPixels = null ; colorTab = null ; closeStream = false ; firstFrame = true ; return ok; } /** * Sets frame rate in frames per second. Equivalent to * <code>setDelay(1000/fps)</code>. * * @param fps float frame rate (frames per second) */ public void SetFrameRate( float fps) { if (fps != 0f) { delay = ( int )Math.Round(100f / fps); } } /** * Sets quality of color quantization (conversion of images * to the maximum 256 colors allowed by the GIF specification). * Lower values (minimum = 1) produce better colors, but slow * processing significantly. 10 is the default, and produces * good color mapping at reasonable speeds. Values greater * than 20 do not yield significant improvements in speed. * * @param quality int greater than 0. * @return */ public void SetQuality( int quality) { if (quality < 1) quality = 1; sample = quality; } /** * Sets the GIF frame size. The default size is the * size of the first frame added if this method is * not invoked. * * @param w int frame width. * @param h int frame width. */ public void SetSize( int w, int h) { if (started && !firstFrame) return ; width = w; height = h; if (width < 1) width = 320; if (height < 1) height = 240; sizeSet = true ; } /** * Initiates GIF file creation on the given stream. The stream * is not closed automatically. * * @param os OutputStream on which GIF images are written. * @return false if initial write failed. */ public bool Start(Stream os) { if (os == null ) return false ; bool ok = true ; closeStream = false ; fs = os; try { WriteString( "GIF89a" ); // header } catch (IOException e) { ok = false ; } return started = ok; } /** * Initiates writing of a GIF file with the specified name. * * @param file String containing output file name. * @return false if open or initial write failed. */ public bool Start(String file) { bool ok = true ; try { // bw = new BinaryWriter( new FileStream( file, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None ) ); fs = new FileStream(file, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None); ok = Start(fs); closeStream = true ; } catch (IOException e) { ok = false ; } return started = ok; } /** * Analyzes image colors and creates color map. */ protected void AnalyzePixels() { int len = pixels.Length; int nPix = len / 3; indexedPixels = new byte [nPix]; NeuQuant nq = new NeuQuant(pixels, len, sample); // initialize quantizer colorTab = nq.Process(); // create reduced palette // convert map from BGR to RGB // for (int i = 0; i < colorTab.Length; i += 3) // { // byte temp = colorTab[i]; // colorTab[i] = colorTab[i + 2]; // colorTab[i + 2] = temp; // usedEntry[i / 3] = false; // } // map image pixels to new palette int k = 0; for ( int i = 0; i < nPix; i++) { int index = nq.Map(pixels[k++] & 0xff, pixels[k++] & 0xff, pixels[k++] & 0xff); usedEntry[index] = true ; indexedPixels[i] = ( byte )index; } pixels = null ; colorDepth = 8; palSize = 7; // get closest match to transparent color if specified if (transparent != Color.Empty) { transIndex = FindClosest(transparent); } } /** * Returns index of palette color closest to c * */ protected int FindClosest(Color c) { if (colorTab == null ) return -1; int r = c.R; int g = c.G; int b = c.B; int minpos = 0; int dmin = 256 * 256 * 256; int len = colorTab.Length; for ( int i = 0; i < len; ) { int dr = r - (colorTab[i++] & 0xff); int dg = g - (colorTab[i++] & 0xff); int db = b - (colorTab[i] & 0xff); int d = dr * dr + dg * dg + db * db; int index = i / 3; if (usedEntry[index] && (d < dmin)) { dmin = d; minpos = index; } i++; } return minpos; } /** * Extracts image pixels into byte array "pixels" */ protected void GetImagePixels() { int w = image.Width; int h = image.Height; // int type = image.GetType().; if ((w != width) || (h != height) ) { // create new image with right size/format Image temp = new Bitmap(width, height); Graphics g = Graphics.FromImage(temp); g.DrawImage(image, 0, 0); image = temp; g.Dispose(); } /* ToDo: improve performance: use unsafe code */ pixels = new Byte[3 * image.Width * image.Height]; int count = 0; Bitmap tempBitmap = new Bitmap(image); for ( int th = 0; th < image.Height; th++) { for ( int tw = 0; tw < image.Width; tw++) { Color color = tempBitmap.GetPixel(tw, th); pixels[count] = color.R; count++; pixels[count] = color.G; count++; pixels[count] = color.B; count++; } } // pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData(); } /** * Writes Graphic Control Extension */ protected void WriteGraphicCtrlExt() { fs.WriteByte(0x21); // extension introducer fs.WriteByte(0xf9); // GCE label fs.WriteByte(4); // data block size int transp, disp; if (transparent == Color.Empty) { transp = 0; disp = 0; // dispose = no action } else { transp = 1; disp = 2; // force clear if using transparent color } if (dispose >= 0) { disp = dispose & 7; // user override } disp <<= 2; // packed fields fs.WriteByte(Convert.ToByte(0 | // 1:3 reserved disp | // 4:6 disposal 0 | // 7 user input - 0 = none transp)); // 8 transparency flag WriteShort(delay); // delay x 1/100 sec fs.WriteByte(Convert.ToByte(transIndex)); // transparent color index fs.WriteByte(0); // block terminator } /** * Writes Image Descriptor */ protected void WriteImageDesc() { fs.WriteByte(0x2c); // image separator WriteShort(0); // image position x,y = 0,0 WriteShort(0); WriteShort(width); // image size WriteShort(height); // packed fields if (firstFrame) { // no LCT - GCT is used for first (or only) frame fs.WriteByte(0); } else { // specify normal LCT fs.WriteByte(Convert.ToByte(0x80 | // 1 local color table 1=yes 0 | // 2 interlace - 0=no 0 | // 3 sorted - 0=no 0 | // 4-5 reserved palSize)); // 6-8 size of color table } } /** * Writes Logical Screen Descriptor */ protected void WriteLSD() { // logical screen size WriteShort(width); WriteShort(height); // packed fields fs.WriteByte(Convert.ToByte(0x80 | // 1 : global color table flag = 1 (gct used) 0x70 | // 2-4 : color resolution = 7 0x00 | // 5 : gct sort flag = 0 palSize)); // 6-8 : gct size fs.WriteByte(0); // background color index fs.WriteByte(0); // pixel aspect ratio - assume 1:1 } /** * Writes Netscape application extension to define * repeat count. */ protected void WriteNetscapeExt() { fs.WriteByte(0x21); // extension introducer fs.WriteByte(0xff); // app extension label fs.WriteByte(11); // block size WriteString( "NETSCAPE" + "2.0" ); // app id + auth code fs.WriteByte(3); // sub-block size fs.WriteByte(1); // loop sub-block id WriteShort(repeat); // loop count (extra iterations, 0=repeat forever) fs.WriteByte(0); // block terminator } /** * Writes color table */ protected void WritePalette() { fs.Write(colorTab, 0, colorTab.Length); int n = (3 * 256) - colorTab.Length; for ( int i = 0; i < n; i++) { fs.WriteByte(0); } } /** * Encodes and writes pixel data */ protected void WritePixels() { LZWEncoder encoder = new LZWEncoder(width, height, indexedPixels, colorDepth); encoder.Encode(fs); } /** * Write 16-bit value to output stream, LSB first */ protected void WriteShort( int value) { fs.WriteByte(Convert.ToByte(value & 0xff)); fs.WriteByte(Convert.ToByte((value >> 8) & 0xff)); } /** * Writes string to output stream */ protected void WriteString(String s) { char [] chars = s.ToCharArray(); for ( int i = 0; i < chars.Length; i++) { fs.WriteByte(( byte )chars[i]); } } } } |
2:新建GifDecoder类
View Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
|
#region .NET Disclaimer/Info //=============================================================================== // // gOODiDEA, uland.com //=============================================================================== // // $Header : $ // $Author : $ // $Date : $ // $Revision: $ // $History: $ // //=============================================================================== #endregion #region Java /** * Class GifDecoder - Decodes a GIF file into one or more frames. * <br><pre> * Example: * GifDecoder d = new GifDecoder(); * d.read("sample.gif"); * int n = d.getFrameCount(); * for (int i = 0; i < n; i++) { * BufferedImage frame = d.getFrame(i); // frame i * int t = d.getDelay(i); // display duration of frame in milliseconds * // do something with frame * } * </pre> * No copyright asserted on the source code of this class. May be used for * any purpose, however, refer to the Unisys LZW patent for any additional * restrictions. Please forward any corrections to kweiner@fmsware.com. * * @author Kevin Weiner, FM Software; LZW decoder adapted from John Cristy's ImageMagick. * @version 1.03 November 2003 * */ #endregion using System; using System.Collections; using System.Drawing; using System.Drawing.Imaging; using System.IO; namespace Common.Gif { public class GifDecoder { /** * File read status: No errors. */ public static readonly int STATUS_OK = 0; /** * File read status: Error decoding file (may be partially decoded) */ public static readonly int STATUS_FORMAT_ERROR = 1; /** * File read status: Unable to open source. */ public static readonly int STATUS_OPEN_ERROR = 2; protected Stream inStream; protected int status; protected int width; // full image width protected int height; // full image height protected bool gctFlag; // global color table used protected int gctSize; // size of global color table protected int loopCount = 1; // iterations; 0 = repeat forever protected int [] gct; // global color table protected int [] lct; // local color table protected int [] act; // active color table protected int bgIndex; // background color index protected int bgColor; // background color protected int lastBgColor; // previous bg color protected int pixelAspect; // pixel aspect ratio protected bool lctFlag; // local color table flag protected bool interlace; // interlace flag protected int lctSize; // local color table size protected int ix, iy, iw, ih; // current image rectangle protected Rectangle lastRect; // last image rect protected Image image; // current frame protected Bitmap bitmap; protected Image lastImage; // previous frame protected byte [] block = new byte [256]; // current data block protected int blockSize = 0; // block size // last graphic control extension info protected int dispose = 0; // 0=no action; 1=leave in place; 2=restore to bg; 3=restore to prev protected int lastDispose = 0; protected bool transparency = false ; // use transparent color protected int delay = 0; // delay in milliseconds protected int transIndex; // transparent color index protected static readonly int MaxStackSize = 4096; // max decoder pixel stack size // LZW decoder working arrays protected short [] prefix; protected byte [] suffix; protected byte [] pixelStack; protected byte [] pixels; protected ArrayList frames; // frames read from current file protected int frameCount; public class GifFrame { public GifFrame( Image im, int del) { image = im; delay = del; } public Image image; public int delay; } /** * Gets display duration for specified frame. * * @param n int index of frame * @return delay in milliseconds */ public int GetDelay( int n) { // delay = -1; if ((n >= 0) && (n < frameCount)) { delay = ((GifFrame) frames[n]).delay; } return delay; } /** * Gets the number of frames read from file. * @return frame count */ public int GetFrameCount() { return frameCount; } /** * Gets the first (or only) image read. * * @return BufferedImage containing first frame, or null if none. */ public Image GetImage() { return GetFrame(0); } /** * Gets the "Netscape" iteration count, if any. * A count of 0 means repeat indefinitiely. * * @return iteration count if one was specified, else 1. */ public int GetLoopCount() { return loopCount; } /** * Creates new frame image from current data (and previous * frames as specified by their disposition codes). */ int [] GetPixels( Bitmap bitmap ) { int [] pixels = new int [ 3 * image.Width * image.Height ]; int count = 0; for ( int th = 0; th < image.Height; th++) { for ( int tw = 0; tw < image.Width; tw++) { Color color = bitmap.GetPixel(tw, th); pixels[count] = color.R; count++; pixels[count] = color.G; count++; pixels[count] = color.B; count++; } } return pixels; } void SetPixels( int [] pixels ) { int count = 0; for ( int th = 0; th < image.Height; th++) { for ( int tw = 0; tw < image.Width; tw++) { Color color = Color.FromArgb( pixels[count++] ); bitmap.SetPixel( tw, th, color ); } } } protected void SetPixels() { // expose destination image's pixels as int array // int[] dest = // (( int ) image.getRaster().getDataBuffer()).getData(); int [] dest = GetPixels( bitmap ); // fill in starting image contents based on last image's dispose code if (lastDispose > 0) { if (lastDispose == 3) { // use image before last int n = frameCount - 2; if (n > 0) { lastImage = GetFrame(n - 1); } else { lastImage = null ; } } if (lastImage != null ) { // int[] prev = // ((DataBufferInt) lastImage.getRaster().getDataBuffer()).getData(); int [] prev = GetPixels( new Bitmap( lastImage ) ); Array.Copy(prev, 0, dest, 0, width * height); // copy pixels if (lastDispose == 2) { // fill last image rect area with background color Graphics g = Graphics.FromImage( image ); Color c = Color.Empty; if (transparency) { c = Color.FromArgb( 0, 0, 0, 0 ); // assume background is transparent } else { c = Color.FromArgb( lastBgColor ) ; // c = new Color(lastBgColor); // use given background color } Brush brush = new SolidBrush( c ); g.FillRectangle( brush, lastRect ); brush.Dispose(); g.Dispose(); } } } // copy each source line to the appropriate place in the destination int pass = 1; int inc = 8; int iline = 0; for ( int i = 0; i < ih; i++) { int line = i; if (interlace) { if (iline >= ih) { pass++; switch (pass) { case 2 : iline = 4; break ; case 3 : iline = 2; inc = 4; break ; case 4 : iline = 1; inc = 2; break ; } } line = iline; iline += inc; } line += iy; if (line < height) { int k = line * width; int dx = k + ix; // start of line in dest int dlim = dx + iw; // end of dest line if ((k + width) < dlim) { dlim = k + width; // past dest edge } int sx = i * iw; // start of line in source while (dx < dlim) { // map color and insert in destination int index = (( int ) pixels[sx++]) & 0xff; int c = act[index]; if (c != 0) { dest[dx] = c; } dx++; } } } SetPixels( dest ); } /** * Gets the image contents of frame n. * * @return BufferedImage representation of frame, or null if n is invalid. */ public Image GetFrame( int n) { Image im = null ; if ((n >= 0) && (n < frameCount)) { im = ((GifFrame) frames[n] ).image; } return im; } /** * Gets image size. * * @return GIF image dimensions */ public Size GetFrameSize() { return new Size(width, height); } /** * Reads GIF image from stream * * @param BufferedInputStream containing GIF file. * @return read status code (0 = no errors) */ public int Read( Stream inStream ) { Init(); if ( inStream != null ) { this .inStream = inStream; ReadHeader(); if (!Error()) { ReadContents(); if (frameCount < 0) { status = STATUS_FORMAT_ERROR; } } inStream.Close(); } else { status = STATUS_OPEN_ERROR; } return status; } /** * Reads GIF file from specified file/URL source * (URL assumed if name contains ":/" or "file:") * * @param name String containing source * @return read status code (0 = no errors) */ public int Read(String name) { status = STATUS_OK; try { name = name.Trim().ToLower(); status = Read( new FileInfo( name ).OpenRead() ); } catch (IOException e) { status = STATUS_OPEN_ERROR; } return status; } /** * Decodes LZW image data into pixel array. * Adapted from John Cristy's ImageMagick. */ protected void DecodeImageData() { int NullCode = -1; int npix = iw * ih; int available, clear, code_mask, code_size, end_of_information, in_code, old_code, bits, code, count, i, datum, data_size, first, top, bi, pi; if ((pixels == null ) || (pixels.Length < npix)) { pixels = new byte [npix]; // allocate new pixel array } if (prefix == null ) prefix = new short [MaxStackSize]; if (suffix == null ) suffix = new byte [MaxStackSize]; if (pixelStack == null ) pixelStack = new byte [MaxStackSize + 1]; // Initialize GIF data stream decoder. data_size = Read(); clear = 1 << data_size; end_of_information = clear + 1; available = clear + 2; old_code = NullCode; code_size = data_size + 1; code_mask = (1 << code_size) - 1; for (code = 0; code < clear; code++) { prefix[code] = 0; suffix[code] = ( byte ) code; } // Decode GIF pixel stream. datum = bits = count = first = top = pi = bi = 0; for (i = 0; i < npix;) { if (top == 0) { if (bits < code_size) { // Load bytes until there are enough bits for a code. if (count == 0) { // Read a new data block. count = ReadBlock(); if (count <= 0) break ; bi = 0; } datum += ((( int ) block[bi]) & 0xff) << bits; bits += 8; bi++; count--; continue ; } // Get the next code. code = datum & code_mask; datum >>= code_size; bits -= code_size; // Interpret the code if ((code > available) || (code == end_of_information)) break ; if (code == clear) { // Reset decoder. code_size = data_size + 1; code_mask = (1 << code_size) - 1; available = clear + 2; old_code = NullCode; continue ; } if (old_code == NullCode) { pixelStack[top++] = suffix[code]; old_code = code; first = code; continue ; } in_code = code; if (code == available) { pixelStack[top++] = ( byte ) first; code = old_code; } while (code > clear) { pixelStack[top++] = suffix[code]; code = prefix[code]; } first = (( int ) suffix[code]) & 0xff; // Add a new string to the string table, if (available >= MaxStackSize) break ; pixelStack[top++] = ( byte ) first; prefix[available] = ( short ) old_code; suffix[available] = ( byte ) first; available++; if (((available & code_mask) == 0) && (available < MaxStackSize)) { code_size++; code_mask += available; } old_code = in_code; } // Pop a pixel off the pixel stack. top--; pixels[pi++] = pixelStack[top]; i++; } for (i = pi; i < npix; i++) { pixels[i] = 0; // clear missing pixels } } /** * Returns true if an error was encountered during reading/decoding */ protected bool Error() { return status != STATUS_OK; } /** * Initializes or re-initializes reader */ protected void Init() { status = STATUS_OK; frameCount = 0; frames = new ArrayList(); gct = null ; lct = null ; } /** * Reads a single byte from the input stream. */ protected int Read() { int curByte = 0; try { curByte = inStream.ReadByte(); } catch (IOException e) { status = STATUS_FORMAT_ERROR; } return curByte; } /** * Reads next variable length block from input. * * @return number of bytes stored in "buffer" */ protected int ReadBlock() { blockSize = Read(); int n = 0; if (blockSize > 0) { try { int count = 0; while (n < blockSize) { count = inStream.Read(block, n, blockSize - n); if (count == -1) break ; n += count; } } catch (IOException e) { } if (n < blockSize) { status = STATUS_FORMAT_ERROR; } } return n; } /** * Reads color table as 256 RGB integer values * * @param ncolors int number of colors to read * @return int array containing 256 colors (packed ARGB with full alpha) */ protected int [] ReadColorTable( int ncolors) { int nbytes = 3 * ncolors; int [] tab = null ; byte [] c = new byte [nbytes]; int n = 0; try { n = inStream.Read(c, 0, c.Length ); } catch (IOException e) { } if (n < nbytes) { status = STATUS_FORMAT_ERROR; } else { tab = new int [256]; // max size to avoid bounds checks int i = 0; int j = 0; while (i < ncolors) { int r = (( int ) c[j++]) & 0xff; int g = (( int ) c[j++]) & 0xff; int b = (( int ) c[j++]) & 0xff; tab[i++] = ( int ) ( 0xff000000 | (r << 16) | (g << 8) | b ); } } return tab; } /** * Main file parser. Reads GIF content blocks. */ protected void ReadContents() { // read GIF file content blocks bool done = false ; while (!(done || Error())) { int code = Read(); switch (code) { case 0x2C : // image separator ReadImage(); break ; case 0x21 : // extension code = Read(); switch (code) { case 0xf9 : // graphics control extension ReadGraphicControlExt(); break ; case 0xff : // application extension ReadBlock(); String app = "" ; for ( int i = 0; i < 11; i++) { app += ( char ) block[i]; } if (app.Equals( "NETSCAPE2.0" )) { ReadNetscapeExt(); } else Skip(); // don't care break ; default : // uninteresting extension Skip(); break ; } break ; case 0x3b : // terminator done = true ; break ; case 0x00 : // bad byte, but keep going and see what happens break ; default : status = STATUS_FORMAT_ERROR; break ; } } } /** * Reads Graphics Control Extension values */ protected void ReadGraphicControlExt() { Read(); // block size int packed = Read(); // packed fields dispose = (packed & 0x1c) >> 2; // disposal method if (dispose == 0) { dispose = 1; // elect to keep old image if discretionary } transparency = (packed & 1) != 0; delay = ReadShort() * 10; // delay in milliseconds transIndex = Read(); // transparent color index Read(); // block terminator } /** * Reads GIF file header information. */ protected void ReadHeader() { String id = "" ; for ( int i = 0; i < 6; i++) { id += ( char ) Read(); } if (!id.StartsWith( "GIF" )) { status = STATUS_FORMAT_ERROR; return ; } ReadLSD(); if (gctFlag && !Error()) { gct = ReadColorTable(gctSize); bgColor = gct[bgIndex]; } } /** * Reads next frame image */ protected void ReadImage() { ix = ReadShort(); // (sub)image position & size iy = ReadShort(); iw = ReadShort(); ih = ReadShort(); int packed = Read(); lctFlag = (packed & 0x80) != 0; // 1 - local color table flag interlace = (packed & 0x40) != 0; // 2 - interlace flag // 3 - sort flag // 4-5 - reserved lctSize = 2 << (packed & 7); // 6-8 - local color table size if (lctFlag) { lct = ReadColorTable(lctSize); // read table act = lct; // make local table active } else { act = gct; // make global table active if (bgIndex == transIndex) bgColor = 0; } int save = 0; if (transparency) { save = act[transIndex]; act[transIndex] = 0; // set transparent color if specified } if (act == null ) { status = STATUS_FORMAT_ERROR; // no color table defined } if (Error()) return ; DecodeImageData(); // decode pixel data Skip(); if (Error()) return ; frameCount++; // create new image to receive frame data // image = // new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE); bitmap = new Bitmap( width, height ); image = bitmap; SetPixels(); // transfer pixel data to image frames.Add( new GifFrame(bitmap, delay)); // add image to frame list if (transparency) { act[transIndex] = save; } ResetFrame(); } /** * Reads Logical Screen Descriptor */ protected void ReadLSD() { // logical screen size width = ReadShort(); height = ReadShort(); // packed fields int packed = Read(); gctFlag = (packed & 0x80) != 0; // 1 : global color table flag // 2-4 : color resolution // 5 : gct sort flag gctSize = 2 << (packed & 7); // 6-8 : gct size bgIndex = Read(); // background color index pixelAspect = Read(); // pixel aspect ratio } /** * Reads Netscape extenstion to obtain iteration count */ protected void ReadNetscapeExt() { do { ReadBlock(); if (block[0] == 1) { // loop count sub-block int b1 = (( int ) block[1]) & 0xff; int b2 = (( int ) block[2]) & 0xff; loopCount = (b2 << 8) | b1; } } while ((blockSize > 0) && !Error()); } /** * Reads next 16-bit value, LSB first */ protected int ReadShort() { // read 16-bit value, LSB first return Read() | (Read() << 8); } /** * Resets frame state for reading next image. */ protected void ResetFrame() { lastDispose = dispose; lastRect = new Rectangle(ix, iy, iw, ih); lastImage = image; lastBgColor = bgColor; // int dispose = 0; bool transparency = false ; int delay = 0; lct = null ; } /** * Skips variable length blocks up to and including * next zero length block. */ protected void Skip() { do { ReadBlock(); } while ((blockSize > 0) && !Error()); } } } |
3:新建LZWEncoder类
View Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
|
#region .NET Disclaimer/Info //=============================================================================== // // gOODiDEA, uland.com //=============================================================================== // // $Header : $ // $Author : $ // $Date : $ // $Revision: $ // $History: $ // //=============================================================================== #endregion #region Java /** * Class GifDecoder - Decodes a GIF file into one or more frames. * <br><pre> * Example: * GifDecoder d = new GifDecoder(); * d.read("sample.gif"); * int n = d.getFrameCount(); * for (int i = 0; i < n; i++) { * BufferedImage frame = d.getFrame(i); // frame i * int t = d.getDelay(i); // display duration of frame in milliseconds * // do something with frame * } * </pre> * No copyright asserted on the source code of this class. May be used for * any purpose, however, refer to the Unisys LZW patent for any additional * restrictions. Please forward any corrections to kweiner@fmsware.com. * * @author Kevin Weiner, FM Software; LZW decoder adapted from John Cristy's ImageMagick. * @version 1.03 November 2003 * */ #endregion using System; using System.Collections; using System.Drawing; using System.Drawing.Imaging; using System.IO; namespace Common.Gif { public class GifDecoder { /** * File read status: No errors. */ public static readonly int STATUS_OK = 0; /** * File read status: Error decoding file (may be partially decoded) */ public static readonly int STATUS_FORMAT_ERROR = 1; /** * File read status: Unable to open source. */ public static readonly int STATUS_OPEN_ERROR = 2; protected Stream inStream; protected int status; protected int width; // full image width protected int height; // full image height protected bool gctFlag; // global color table used protected int gctSize; // size of global color table protected int loopCount = 1; // iterations; 0 = repeat forever protected int [] gct; // global color table protected int [] lct; // local color table protected int [] act; // active color table protected int bgIndex; // background color index protected int bgColor; // background color protected int lastBgColor; // previous bg color protected int pixelAspect; // pixel aspect ratio protected bool lctFlag; // local color table flag protected bool interlace; // interlace flag protected int lctSize; // local color table size protected int ix, iy, iw, ih; // current image rectangle protected Rectangle lastRect; // last image rect protected Image image; // current frame protected Bitmap bitmap; protected Image lastImage; // previous frame protected byte [] block = new byte [256]; // current data block protected int blockSize = 0; // block size // last graphic control extension info protected int dispose = 0; // 0=no action; 1=leave in place; 2=restore to bg; 3=restore to prev protected int lastDispose = 0; protected bool transparency = false ; // use transparent color protected int delay = 0; // delay in milliseconds protected int transIndex; // transparent color index protected static readonly int MaxStackSize = 4096; // max decoder pixel stack size // LZW decoder working arrays protected short [] prefix; protected byte [] suffix; protected byte [] pixelStack; protected byte [] pixels; protected ArrayList frames; // frames read from current file protected int frameCount; public class GifFrame { public GifFrame( Image im, int del) { image = im; delay = del; } public Image image; public int delay; } /** * Gets display duration for specified frame. * * @param n int index of frame * @return delay in milliseconds */ public int GetDelay( int n) { // delay = -1; if ((n >= 0) && (n < frameCount)) { delay = ((GifFrame) frames[n]).delay; } return delay; } /** * Gets the number of frames read from file. * @return frame count */ public int GetFrameCount() { return frameCount; } /** * Gets the first (or only) image read. * * @return BufferedImage containing first frame, or null if none. */ public Image GetImage() { return GetFrame(0); } /** * Gets the "Netscape" iteration count, if any. * A count of 0 means repeat indefinitiely. * * @return iteration count if one was specified, else 1. */ public int GetLoopCount() { return loopCount; } /** * Creates new frame image from current data (and previous * frames as specified by their disposition codes). */ int [] GetPixels( Bitmap bitmap ) { int [] pixels = new int [ 3 * image.Width * image.Height ]; int count = 0; for ( int th = 0; th < image.Height; th++) { for ( int tw = 0; tw < image.Width; tw++) { Color color = bitmap.GetPixel(tw, th); pixels[count] = color.R; count++; pixels[count] = color.G; count++; pixels[count] = color.B; count++; } } return pixels; } void SetPixels( int [] pixels ) { int count = 0; for ( int th = 0; th < image.Height; th++) { for ( int tw = 0; tw < image.Width; tw++) { Color color = Color.FromArgb( pixels[count++] ); bitmap.SetPixel( tw, th, color ); } } } protected void SetPixels() { // expose destination image's pixels as int array // int[] dest = // (( int ) image.getRaster().getDataBuffer()).getData(); int [] dest = GetPixels( bitmap ); // fill in starting image contents based on last image's dispose code if (lastDispose > 0) { if (lastDispose == 3) { // use image before last int n = frameCount - 2; if (n > 0) { lastImage = GetFrame(n - 1); } else { lastImage = null ; } } if (lastImage != null ) { // int[] prev = // ((DataBufferInt) lastImage.getRaster().getDataBuffer()).getData(); int [] prev = GetPixels( new Bitmap( lastImage ) ); Array.Copy(prev, 0, dest, 0, width * height); // copy pixels if (lastDispose == 2) { // fill last image rect area with background color Graphics g = Graphics.FromImage( image ); Color c = Color.Empty; if (transparency) { c = Color.FromArgb( 0, 0, 0, 0 ); // assume background is transparent } else { c = Color.FromArgb( lastBgColor ) ; // c = new Color(lastBgColor); // use given background color } Brush brush = new SolidBrush( c ); g.FillRectangle( brush, lastRect ); brush.Dispose(); g.Dispose(); } } } // copy each source line to the appropriate place in the destination int pass = 1; int inc = 8; int iline = 0; for ( int i = 0; i < ih; i++) { int line = i; if (interlace) { if (iline >= ih) { pass++; switch (pass) { case 2 : iline = 4; break ; case 3 : iline = 2; inc = 4; break ; case 4 : iline = 1; inc = 2; break ; } } line = iline; iline += inc; } line += iy; if (line < height) { int k = line * width; int dx = k + ix; // start of line in dest int dlim = dx + iw; // end of dest line if ((k + width) < dlim) { dlim = k + width; // past dest edge } int sx = i * iw; // start of line in source while (dx < dlim) { // map color and insert in destination int index = (( int ) pixels[sx++]) & 0xff; int c = act[index]; if (c != 0) { dest[dx] = c; } dx++; } } } SetPixels( dest ); } /** * Gets the image contents of frame n. * * @return BufferedImage representation of frame, or null if n is invalid. */ public Image GetFrame( int n) { Image im = null ; if ((n >= 0) && (n < frameCount)) { im = ((GifFrame) frames[n] ).image; } return im; } /** * Gets image size. * * @return GIF image dimensions */ public Size GetFrameSize() { return new Size(width, height); } /** * Reads GIF image from stream * * @param BufferedInputStream containing GIF file. * @return read status code (0 = no errors) */ public int Read( Stream inStream ) { Init(); if ( inStream != null ) { this .inStream = inStream; ReadHeader(); if (!Error()) { ReadContents(); if (frameCount < 0) { status = STATUS_FORMAT_ERROR; } } inStream.Close(); } else { status = STATUS_OPEN_ERROR; } return status; } /** * Reads GIF file from specified file/URL source * (URL assumed if name contains ":/" or "file:") * * @param name String containing source * @return read status code (0 = no errors) */ public int Read(String name) { status = STATUS_OK; try { name = name.Trim().ToLower(); status = Read( new FileInfo( name ).OpenRead() ); } catch (IOException e) { status = STATUS_OPEN_ERROR; } return status; } /** * Decodes LZW image data into pixel array. * Adapted from John Cristy's ImageMagick. */ protected void DecodeImageData() { int NullCode = -1; int npix = iw * ih; int available, clear, code_mask, code_size, end_of_information, in_code, old_code, bits, code, count, i, datum, data_size, first, top, bi, pi; if ((pixels == null ) || (pixels.Length < npix)) { pixels = new byte [npix]; // allocate new pixel array } if (prefix == null ) prefix = new short [MaxStackSize]; if (suffix == null ) suffix = new byte [MaxStackSize]; if (pixelStack == null ) pixelStack = new byte [MaxStackSize + 1]; // Initialize GIF data stream decoder. data_size = Read(); clear = 1 << data_size; end_of_information = clear + 1; available = clear + 2; old_code = NullCode; code_size = data_size + 1; code_mask = (1 << code_size) - 1; for (code = 0; code < clear; code++) { prefix[code] = 0; suffix[code] = ( byte ) code; } // Decode GIF pixel stream. datum = bits = count = first = top = pi = bi = 0; for (i = 0; i < npix;) { if (top == 0) { if (bits < code_size) { // Load bytes until there are enough bits for a code. if (count == 0) { // Read a new data block. count = ReadBlock(); if (count <= 0) break ; bi = 0; } datum += ((( int ) block[bi]) & 0xff) << bits; bits += 8; bi++; count--; continue ; } // Get the next code. code = datum & code_mask; datum >>= code_size; bits -= code_size; // Interpret the code if ((code > available) || (code == end_of_information)) break ; if (code == clear) { // Reset decoder. code_size = data_size + 1; code_mask = (1 << code_size) - 1; available = clear + 2; old_code = NullCode; continue ; } if (old_code == NullCode) { pixelStack[top++] = suffix[code]; old_code = code; first = code; continue ; } in_code = code; if (code == available) { pixelStack[top++] = ( byte ) first; code = old_code; } while (code > clear) { pixelStack[top++] = suffix[code]; code = prefix[code]; } first = (( int ) suffix[code]) & 0xff; // Add a new string to the string table, if (available >= MaxStackSize) break ; pixelStack[top++] = ( byte ) first; prefix[available] = ( short ) old_code; suffix[available] = ( byte ) first; available++; if (((available & code_mask) == 0) && (available < MaxStackSize)) { code_size++; code_mask += available; } old_code = in_code; } // Pop a pixel off the pixel stack. top--; pixels[pi++] = pixelStack[top]; i++; } for (i = pi; i < npix; i++) { pixels[i] = 0; // clear missing pixels } } /** * Returns true if an error was encountered during reading/decoding */ protected bool Error() { return status != STATUS_OK; } /** * Initializes or re-initializes reader */ protected void Init() { status = STATUS_OK; frameCount = 0; frames = new ArrayList(); gct = null ; lct = null ; } /** * Reads a single byte from the input stream. */ protected int Read() { int curByte = 0; try { curByte = inStream.ReadByte(); } catch (IOException e) { status = STATUS_FORMAT_ERROR; } return curByte; } /** * Reads next variable length block from input. * * @return number of bytes stored in "buffer" */ protected int ReadBlock() { blockSize = Read(); int n = 0; if (blockSize > 0) { try { int count = 0; while (n < blockSize) { count = inStream.Read(block, n, blockSize - n); if (count == -1) break ; n += count; } } catch (IOException e) { } if (n < blockSize) { status = STATUS_FORMAT_ERROR; } } return n; } /** * Reads color table as 256 RGB integer values * * @param ncolors int number of colors to read * @return int array containing 256 colors (packed ARGB with full alpha) */ protected int [] ReadColorTable( int ncolors) { int nbytes = 3 * ncolors; int [] tab = null ; byte [] c = new byte [nbytes]; int n = 0; try { n = inStream.Read(c, 0, c.Length ); } catch (IOException e) { } if (n < nbytes) { status = STATUS_FORMAT_ERROR; } else { tab = new int [256]; // max size to avoid bounds checks int i = 0; int j = 0; while (i < ncolors) { int r = (( int ) c[j++]) & 0xff; int g = (( int ) c[j++]) & 0xff; int b = (( int ) c[j++]) & 0xff; tab[i++] = ( int ) ( 0xff000000 | (r << 16) | (g << 8) | b ); } } return tab; } /** * Main file parser. Reads GIF content blocks. */ protected void ReadContents() { // read GIF file content blocks bool done = false ; while (!(done || Error())) { int code = Read(); switch (code) { case 0x2C : // image separator ReadImage(); break ; case 0x21 : // extension code = Read(); switch (code) { case 0xf9 : // graphics control extension ReadGraphicControlExt(); break ; case 0xff : // application extension ReadBlock(); String app = "" ; for ( int i = 0; i < 11; i++) { app += ( char ) block[i]; } if (app.Equals( "NETSCAPE2.0" )) { ReadNetscapeExt(); } else Skip(); // don't care break ; default : // uninteresting extension Skip(); break ; } break ; case 0x3b : // terminator done = true ; break ; case 0x00 : // bad byte, but keep going and see what happens break ; default : status = STATUS_FORMAT_ERROR; break ; } } } /** * Reads Graphics Control Extension values */ protected void ReadGraphicControlExt() { Read(); // block size int packed = Read(); // packed fields dispose = (packed & 0x1c) >> 2; // disposal method if (dispose == 0) { dispose = 1; // elect to keep old image if discretionary } transparency = (packed & 1) != 0; delay = ReadShort() * 10; // delay in milliseconds transIndex = Read(); // transparent color index Read(); // block terminator } /** * Reads GIF file header information. */ protected void ReadHeader() { String id = "" ; for ( int i = 0; i < 6; i++) { id += ( char ) Read(); } if (!id.StartsWith( "GIF" )) { status = STATUS_FORMAT_ERROR; return ; } ReadLSD(); if (gctFlag && !Error()) { gct = ReadColorTable(gctSize); bgColor = gct[bgIndex]; } } /** * Reads next frame image */ protected void ReadImage() { ix = ReadShort(); // (sub)image position & size iy = ReadShort(); iw = ReadShort(); ih = ReadShort(); int packed = Read(); lctFlag = (packed & 0x80) != 0; // 1 - local color table flag interlace = (packed & 0x40) != 0; // 2 - interlace flag // 3 - sort flag // 4-5 - reserved lctSize = 2 << (packed & 7); // 6-8 - local color table size if (lctFlag) { lct = ReadColorTable(lctSize); // read table act = lct; // make local table active } else { act = gct; // make global table active if (bgIndex == transIndex) bgColor = 0; } int save = 0; if (transparency) { save = act[transIndex]; act[transIndex] = 0; // set transparent color if specified } if (act == null ) { status = STATUS_FORMAT_ERROR; // no color table defined } if (Error()) return ; DecodeImageData(); // decode pixel data Skip(); if (Error()) return ; frameCount++; // create new image to receive frame data // image = // new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE); bitmap = new Bitmap( width, height ); image = bitmap; SetPixels(); // transfer pixel data to image frames.Add( new GifFrame(bitmap, delay)); // add image to frame list if (transparency) { act[transIndex] = save; } ResetFrame(); } /** * Reads Logical Screen Descriptor */ protected void ReadLSD() { // logical screen size width = ReadShort(); height = ReadShort(); // packed fields int packed = Read(); gctFlag = (packed & 0x80) != 0; // 1 : global color table flag // 2-4 : color resolution // 5 : gct sort flag gctSize = 2 << (packed & 7); // 6-8 : gct size bgIndex = Read(); // background color index pixelAspect = Read(); // pixel aspect ratio } /** * Reads Netscape extenstion to obtain iteration count */ protected void ReadNetscapeExt() { do { ReadBlock(); if (block[0] == 1) { // loop count sub-block int b1 = (( int ) block[1]) & 0xff; int b2 = (( int ) block[2]) & 0xff; loopCount = (b2 << 8) | b1; } } while ((blockSize > 0) && !Error()); } /** * Reads next 16-bit value, LSB first */ protected int ReadShort() { // read 16-bit value, LSB first return Read() | (Read() << 8); } /** * Resets frame state for reading next image. */ protected void ResetFrame() { lastDispose = dispose; lastRect = new Rectangle(ix, iy, iw, ih); lastImage = image; lastBgColor = bgColor; // int dispose = 0; bool transparency = false ; int delay = 0; lct = null ; } /** * Skips variable length blocks up to and including * next zero length block. */ protected void Skip() { do { ReadBlock(); } while ((blockSize > 0) && !Error()); } } } |
4:最后新建一个NeuQuant类 (这样gif类库完成)
View Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
|
#region .NET Disclaimer/Info //=============================================================================== // // gOODiDEA, uland.com //=============================================================================== // // $Header : $ // $Author : $ // $Date : $ // $Revision: $ // $History: $ // //=============================================================================== #endregion #region Java /* NeuQuant Neural-Net Quantization Algorithm * ------------------------------------------ * * Copyright (c) 1994 Anthony Dekker * * NEUQUANT Neural-Net quantization algorithm by Anthony Dekker, 1994. * See "Kohonen neural networks for optimal colour quantization" * in "Network: Computation in Neural Systems" Vol. 5 (1994) pp 351-367. * for a discussion of the algorithm. * * Any party obtaining a copy of these files from the author, directly or * indirectly, is granted, free of charge, a full and unrestricted irrevocable, * world-wide, paid up, royalty-free, nonexclusive right and license to deal * in this software and documentation files (the "Software"), including without * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons who receive * copies from any such party to do so, with the only requirement being * that this copyright notice remain intact. */ // Ported to Java 12/00 K Weiner #endregion using System; namespace Common.Gif { public class NeuQuant { protected static readonly int netsize = 256; /* number of colours used */ /* four primes near 500 - assume no image has a length so large */ /* that it is divisible by all four primes */ protected static readonly int prime1 = 499; protected static readonly int prime2 = 491; protected static readonly int prime3 = 487; protected static readonly int prime4 = 503; protected static readonly int minpicturebytes = ( 3 * prime4 ); /* minimum size for input image */ /* Program Skeleton ---------------- [select samplefac in range 1..30] [read image from input file] pic = (unsigned char*) malloc(3*width*height); initnet(pic,3*width*height,samplefac); learn(); unbiasnet(); [write output image header, using writecolourmap(f)] inxbuild(); write output image using inxsearch(b,g,r) */ /* Network Definitions ------------------- */ protected static readonly int maxnetpos = (netsize - 1); protected static readonly int netbiasshift = 4; /* bias for colour values */ protected static readonly int ncycles = 100; /* no. of learning cycles */ /* defs for freq and bias */ protected static readonly int intbiasshift = 16; /* bias for fractions */ protected static readonly int intbias = ((( int ) 1) << intbiasshift); protected static readonly int gammashift = 10; /* gamma = 1024 */ protected static readonly int gamma = ((( int ) 1) << gammashift); protected static readonly int betashift = 10; protected static readonly int beta = (intbias >> betashift); /* beta = 1/1024 */ protected static readonly int betagamma = (intbias << (gammashift - betashift)); /* defs for decreasing radius factor */ protected static readonly int initrad = (netsize >> 3); /* for 256 cols, radius starts */ protected static readonly int radiusbiasshift = 6; /* at 32.0 biased by 6 bits */ protected static readonly int radiusbias = ((( int ) 1) << radiusbiasshift); protected static readonly int initradius = (initrad * radiusbias); /* and decreases by a */ protected static readonly int radiusdec = 30; /* factor of 1/30 each cycle */ /* defs for decreasing alpha factor */ protected static readonly int alphabiasshift = 10; /* alpha starts at 1.0 */ protected static readonly int initalpha = ((( int ) 1) << alphabiasshift); protected int alphadec; /* biased by 10 bits */ /* radbias and alpharadbias used for radpower calculation */ protected static readonly int radbiasshift = 8; protected static readonly int radbias = ((( int ) 1) << radbiasshift); protected static readonly int alpharadbshift = (alphabiasshift + radbiasshift); protected static readonly int alpharadbias = ((( int ) 1) << alpharadbshift); /* Types and Global Variables -------------------------- */ protected byte [] thepicture; /* the input image itself */ protected int lengthcount; /* lengthcount = H*W*3 */ protected int samplefac; /* sampling factor 1..30 */ // typedef int pixel[4]; /* BGRc */ protected int [][] network; /* the network itself - [netsize][4] */ protected int [] netindex = new int [256]; /* for network lookup - really 256 */ protected int [] bias = new int [netsize]; /* bias and freq arrays for learning */ protected int [] freq = new int [netsize]; protected int [] radpower = new int [initrad]; /* radpower for precomputation */ /* Initialise network in range (0,0,0) to (255,255,255) and set parameters ----------------------------------------------------------------------- */ public NeuQuant( byte [] thepic, int len, int sample) { int i; int [] p; thepicture = thepic; lengthcount = len; samplefac = sample; network = new int [netsize][]; for (i = 0; i < netsize; i++) { network[i] = new int [4]; p = network[i]; p[0] = p[1] = p[2] = (i << (netbiasshift + 8)) / netsize; freq[i] = intbias / netsize; /* 1/netsize */ bias[i] = 0; } } public byte [] ColorMap() { byte [] map = new byte [3 * netsize]; int [] index = new int [netsize]; for ( int i = 0; i < netsize; i++) index[network[i][3]] = i; int k = 0; for ( int i = 0; i < netsize; i++) { int j = index[i]; map[k++] = ( byte ) (network[j][0]); map[k++] = ( byte ) (network[j][1]); map[k++] = ( byte ) (network[j][2]); } return map; } /* Insertion sort of network and building of netindex[0..255] (to do after unbias) ------------------------------------------------------------------------------- */ public void Inxbuild() { int i, j, smallpos, smallval; int [] p; int [] q; int previouscol, startpos; previouscol = 0; startpos = 0; for (i = 0; i < netsize; i++) { p = network[i]; smallpos = i; smallval = p[1]; /* index on g */ /* find smallest in i..netsize-1 */ for (j = i + 1; j < netsize; j++) { q = network[j]; if (q[1] < smallval) { /* index on g */ smallpos = j; smallval = q[1]; /* index on g */ } } q = network[smallpos]; /* swap p (i) and q (smallpos) entries */ if (i != smallpos) { j = q[0]; q[0] = p[0]; p[0] = j; j = q[1]; q[1] = p[1]; p[1] = j; j = q[2]; q[2] = p[2]; p[2] = j; j = q[3]; q[3] = p[3]; p[3] = j; } /* smallval entry is now in position i */ if (smallval != previouscol) { netindex[previouscol] = (startpos + i) >> 1; for (j = previouscol + 1; j < smallval; j++) netindex[j] = i; previouscol = smallval; startpos = i; } } netindex[previouscol] = (startpos + maxnetpos) >> 1; for (j = previouscol + 1; j < 256; j++) netindex[j] = maxnetpos; /* really 256 */ } /* Main Learning Loop ------------------ */ public void Learn() { int i, j, b, g, r; int radius, rad, alpha, step, delta, samplepixels; byte [] p; int pix, lim; if (lengthcount < minpicturebytes) samplefac = 1; alphadec = 30 + ((samplefac - 1) / 3); p = thepicture; pix = 0; lim = lengthcount; samplepixels = lengthcount / (3 * samplefac); delta = samplepixels / ncycles; alpha = initalpha; radius = initradius; rad = radius >> radiusbiasshift; if (rad <= 1) rad = 0; for (i = 0; i < rad; i++) radpower[i] = alpha * (((rad * rad - i * i) * radbias) / (rad * rad)); //fprintf(stderr,"beginning 1D learning: initial radius=%d
", rad); if (lengthcount < minpicturebytes) step = 3; else if ((lengthcount % prime1) != 0) step = 3 * prime1; else { if ((lengthcount % prime2) != 0) step = 3 * prime2; else { if ((lengthcount % prime3) != 0) step = 3 * prime3; else step = 3 * prime4; } } i = 0; while (i < samplepixels) { b = (p[pix + 0] & 0xff) << netbiasshift; g = (p[pix + 1] & 0xff) << netbiasshift; r = (p[pix + 2] & 0xff) << netbiasshift; j = Contest(b, g, r); Altersingle(alpha, j, b, g, r); if (rad != 0) Alterneigh(rad, j, b, g, r); /* alter neighbours */ pix += step; if (pix >= lim) pix -= lengthcount; i++; if (delta == 0) delta = 1; if (i % delta == 0) { alpha -= alpha / alphadec; radius -= radius / radiusdec; rad = radius >> radiusbiasshift; if (rad <= 1) rad = 0; for (j = 0; j < rad; j++) radpower[j] = alpha * (((rad * rad - j * j) * radbias) / (rad * rad)); } } //fprintf(stderr,"finished 1D learning: readonly alpha=%f !
",((float)alpha)/initalpha); } /* Search for BGR values 0..255 (after net is unbiased) and return colour index ---------------------------------------------------------------------------- */ public int Map( int b, int g, int r) { int i, j, dist, a, bestd; int [] p; int best; bestd = 1000; /* biggest possible dist is 256*3 */ best = -1; i = netindex[g]; /* index on g */ j = i - 1; /* start at netindex[g] and work outwards */ while ((i < netsize) || (j >= 0)) { if (i < netsize) { p = network[i]; dist = p[1] - g; /* inx key */ if (dist >= bestd) i = netsize; /* stop iter */ else { i++; if (dist < 0) dist = -dist; a = p[0] - b; if (a < 0) a = -a; dist += a; if (dist < bestd) { a = p[2] - r; if (a < 0) a = -a; dist += a; if (dist < bestd) { bestd = dist; best = p[3]; } } } } if (j >= 0) { p = network[j]; dist = g - p[1]; /* inx key - reverse dif */ if (dist >= bestd) j = -1; /* stop iter */ else { j--; if (dist < 0) dist = -dist; a = p[0] - b; if (a < 0) a = -a; dist += a; if (dist < bestd) { a = p[2] - r; if (a < 0) a = -a; dist += a; if (dist < bestd) { bestd = dist; best = p[3]; } } } } } return (best); } public byte [] Process() { Learn(); Unbiasnet(); Inxbuild(); return ColorMap(); } /* Unbias network to give byte values 0..255 and record position i to prepare for sort ----------------------------------------------------------------------------------- */ public void Unbiasnet() { int i, j; for (i = 0; i < netsize; i++) { network[i][0] >>= netbiasshift; network[i][1] >>= netbiasshift; network[i][2] >>= netbiasshift; network[i][3] = i; /* record colour no */ } } /* Move adjacent neurons by precomputed alpha*(1-((i-j)^2/[r]^2)) in radpower[|i-j|] --------------------------------------------------------------------------------- */ protected void Alterneigh( int rad, int i, int b, int g, int r) { int j, k, lo, hi, a, m; int [] p; lo = i - rad; if (lo < -1) lo = -1; hi = i + rad; if (hi > netsize) hi = netsize; j = i + 1; k = i - 1; m = 1; while ((j < hi) || (k > lo)) { a = radpower[m++]; if (j < hi) { p = network[j++]; try { p[0] -= (a * (p[0] - b)) / alpharadbias; p[1] -= (a * (p[1] - g)) / alpharadbias; p[2] -= (a * (p[2] - r)) / alpharadbias; } catch (Exception e) { } // prevents 1.3 miscompilation } if (k > lo) { p = network[k--]; try { p[0] -= (a * (p[0] - b)) / alpharadbias; p[1] -= (a * (p[1] - g)) / alpharadbias; p[2] -= (a * (p[2] - r)) / alpharadbias; } catch (Exception e) { } } } } /* Move neuron i towards biased (b,g,r) by factor alpha ---------------------------------------------------- */ protected void Altersingle( int alpha, int i, int b, int g, int r) { /* alter hit neuron */ int [] n = network[i]; n[0] -= (alpha * (n[0] - b)) / initalpha; n[1] -= (alpha * (n[1] - g)) / initalpha; n[2] -= (alpha * (n[2] - r)) / initalpha; } /* Search for biased BGR values ---------------------------- */ protected int Contest( int b, int g, int r) { /* finds closest neuron (min dist) and updates freq */ /* finds best neuron (min dist-bias) and returns position */ /* for frequently chosen neurons, freq[i] is high and bias[i] is negative */ /* bias[i] = gamma*((1/netsize)-freq[i]) */ int i, dist, a, biasdist, betafreq; int bestpos, bestbiaspos, bestd, bestbiasd; int [] n; bestd = ~((( int ) 1) << 31); bestbiasd = bestd; bestpos = -1; bestbiaspos = bestpos; for (i = 0; i < netsize; i++) { n = network[i]; dist = n[0] - b; if (dist < 0) dist = -dist; a = n[1] - g; if (a < 0) a = -a; dist += a; a = n[2] - r; if (a < 0) a = -a; dist += a; if (dist < bestd) { bestd = dist; bestpos = i; } biasdist = dist - ((bias[i]) >> (intbiasshift - netbiasshift)); if (biasdist < bestbiasd) { bestbiasd = biasdist; bestbiaspos = i; } betafreq = (freq[i] >> betashift); freq[i] -= betafreq; bias[i] += (betafreq << gammashift); } freq[bestpos] += beta; bias[bestpos] -= betagamma; return (bestbiaspos); } } } |
二:新建一个网站:
1:建立一个验证码类,代码如下
using Common.Gif; using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Web; namespace Common.Tools { public class VerificationCode { private AnimatedGifEncoder coder = new AnimatedGifEncoder(); // private Stream stream = new MemoryStream(); private char [] _identifyingCode; private int _defaultIdentifyingCodeLen = 4; private string _availableLetters = @"的一是在了不和有大这主中人上为们地个用工时要动国产以我到他会作来分生对于学下级就年阶义发成部民可出能方进同行面说种过命度革而多子后自社加小机也经力线本电高量长党得实家定深法表着水理化争现所二起政三好十战无农使性前等反体合斗路图把结第里正新开论之物从当两些还天资事队批如应形想制心样干都向变关点育重其思与间内去因件日利相由压员气业代全组数果期导平各基或月毛然问比展那它最及外没看治提五解系林者米群头意只明四道马认次文通但条较克又公孔领军流入接席位情运器并飞原油放立题质指建区验活众很教决特此常石强极土少已根共直团统式转别造切九你取西持总料连任志观调七么山程百报更见必真保热委手改管处己将修支识病象几先老光专什六型具示复安带每东增则完风回南广劳轮科北打积车计给节做务被整联步类集号列温装即毫知轴研单色坚据速防史拉世设达尔场织历花受求传口断况采精金界品判参层止边清至万确究书术状厂须离再目海交权且儿青才证低越际八试规斯近注办布门铁需走议县兵固除般引齿千胜细影济白格效置推空配刀叶率述今选养德话查差半敌始片施响收华觉备名红续均药标记难存测士身紧液派准斤角降维板许破述技消底床田势端感往神便贺村构照容非搞亚磨族火段算适讲按值美态黄易彪服早班麦削信排台声该击素张密害侯草何树肥继右属市严径螺检左页抗苏显苦英快称坏移约巴材省黑武培著河帝仅针怎植京助升王眼她抓含苗副杂普谈围食射源例致酸旧却充足短划剂宣环落首尺波承粉践府鱼随考刻靠够满夫失包住促枝局菌杆周护岩师举曲春元超负砂封换太模贫减阳扬江析亩木言球朝医校古呢稻宋听唯输滑站另卫字鼓刚写刘微略范供阿块某功套友限项余倒卷创律雨让骨远帮初皮播优占死毒圈伟季训控激找叫云互跟裂粮粒母练塞钢顶策双留误础吸阻故寸盾晚丝女散焊功株亲院冷彻弹错散商视艺灭版烈零室轻血倍缺厘泵察绝富城冲喷壤简否柱李望盘磁雄似困巩益洲脱投送奴侧润盖挥距触星松送获兴独官混纪依未突架宽冬章湿偏纹吃执阀矿寨责熟稳夺硬价努翻奇甲预职评读背协损棉侵灰虽矛厚罗泥辟告卵箱掌氧恩爱停曾溶营终纲孟钱待尽俄缩沙退陈讨奋械载胞幼哪剥迫旋征槽倒握担仍呀鲜吧卡粗介钻逐弱脚怕盐末阴丰编印蜂急拿扩伤飞露核缘游振操央伍域甚迅辉异序免纸夜乡久隶缸夹念兰映沟乙吗儒杀汽磷艰晶插埃燃欢铁补咱芽永瓦倾阵碳演威附牙芽永瓦斜灌欧献顺猪洋腐请透司危括脉宜笑若尾束壮暴企菜穗楚汉愈绿拖牛份染既秋遍锻玉夏疗尖殖井费州访吹荣铜沿替滚客召旱悟刺脑措贯藏敢令隙炉壳硫煤迎铸粘探临薄旬善福纵择礼愿伏残雷延烟句纯渐耕跑泽慢栽鲁赤繁境潮横掉锥希池败船假亮谓托伙哲怀割摆贡呈劲财仪沉炼麻罪祖息车穿货销齐鼠抽画饲龙库守筑房歌寒喜哥洗蚀废纳腹乎录镜妇恶脂庄擦险赞钟摇典柄辩竹谷卖乱虚桥奥伯赶垂途额壁网截野遗静谋弄挂课镇妄盛耐援扎虑键归符庆聚绕摩忙舞遇索顾胶羊湖钉仁音迹碎伸灯避泛亡答勇频皇柳哈揭甘诺概宪浓岛袭谁洪谢炮浇斑讯懂灵蛋闭孩释乳巨徒私银伊景坦累匀霉杜乐勒隔弯绩招绍胡呼痛峰零柴簧午跳居尚丁秦稍追梁折耗碱殊岗挖氏刃剧堆赫荷胸衡勤膜篇登驻案刊秧缓凸役剪川雪链渔啦脸户洛孢勃盟买杨宗焦赛旗滤硅炭股坐蒸凝竟陷枪黎救冒暗洞犯筒您宋弧爆谬涂味津臂障褐陆啊健尊豆拔莫抵桑坡缝警挑污冰柬嘴啥饭塑寄赵喊垫康遵牧遭幅园腔订香肉弟屋敏恢忘衣孙龄岭骗休借丹渡耳刨虎笔稀昆浪萨茶滴浅拥穴覆伦娘吨浸袖珠雌妈紫戏塔锤震岁貌洁剖牢锋疑霸闪埔猛诉刷狠忽灾闹乔唐漏闻沈熔氯荒茎男凡抢像浆旁玻亦忠唱蒙予纷捕锁尤乘乌智淡允叛畜俘摸锈扫毕璃宝芯爷鉴秘净蒋钙肩腾枯抛轨堂拌爸循诱祝励肯酒绳穷塘燥泡袋朗喂铝软渠颗惯贸粪综墙趋彼届墨碍启逆卸航雾冠丙街莱贝辐肠付吉渗瑞惊顿挤秒悬姆烂森糖圣凹陶词迟蚕亿矩" ; private Random random = new Random(); private int _frameCount = 4; private int _delay = 900; private int _noiseCount = 15; private int _width = 150, _height = 60; public int Width { get { return _width; } } public int Height { get { return _height; } } public string IdentifyingCode { get { return new string (_identifyingCode); } } public VerificationCode( int width, int height) { _width = width < 1 ? 1 : width; _height = height < 1 ? 1 : height; coder.SetSize(Width, Height); coder.SetRepeat(0); } private void GenerateIdentifyingCode( int codeLength) { if (codeLength < 1) codeLength = _defaultIdentifyingCodeLen; List< char > codes = new List< char >(); for ( int i = 0; i < codeLength; i++) { codes.Add(_availableLetters[random.Next(0, _availableLetters.Length)]); } _identifyingCode = new char [codes.Count]; codes.CopyTo(_identifyingCode); } public Stream Create(Stream stream) { coder.Start(stream); Process(); return stream; } public MemoryStream Create() { MemoryStream stream = new MemoryStream(); coder.Start(stream); Process(); return stream; } private void Process() { GenerateIdentifyingCode(_defaultIdentifyingCodeLen); Brush br = Brushes.White; Rectangle rect = new Rectangle(0, 0, Width, Height); Font f = new Font(FontFamily.GenericSansSerif, 14, FontStyle.Bold); for ( int i = 0; i < _frameCount; i++) { Image im = new Bitmap(Width, Height); Graphics ga = Graphics.FromImage(im); ga.FillRectangle(br, rect); int fH = ( int )f.GetHeight(); int fW = ( int )ga.MeasureString(IdentifyingCode, f).Width; AddNoise(ga); ga.DrawString(IdentifyingCode, f, SystemBrushes.Desktop, new PointF(random.Next(1, Width - 1 - fW), random.Next(1, Height - 1 - fH))); ga.Flush(); coder.SetDelay(_delay); coder.AddFrame(im); im.Dispose(); } coder.Finish(); } private void AddNoise(Graphics ga) { Pen pen = new Pen(SystemColors.GrayText); Point[] ps = new Point[_noiseCount]; for ( int i = 0; i < _noiseCount; i++) { ps[i] = new Point(random.Next(1, Width - 1), random.Next(1, Height - 1)); } ga.DrawLines(pen, ps); } public void Create( string path) { //coder.Start(path);用它的这个方法,比用 stream 生成的要大! FileStream fs = new FileStream(path, FileMode.Create); coder.Start(fs); Process(); fs.Close(); } public void ProcessRequest(HttpContext context) { context.Response.ClearContent(); context.Response.ContentType = "image/Gif" ; var stream = Create(); context.Response.BinaryWrite(stream.ToArray()); stream.Dispose(); } } } |
2:使用验证码类
3: 运行结果图