Subversion Repositories group.electronics

Rev

Rev 185 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
182 pfowler 1
using System;
2
using System.Collections;
3
using System.Collections.Generic;
4
using System.Drawing;
5
using System.IO;
6
using System.Linq;
7
using System.Text;
8
using System.Threading.Tasks;
9
 
10
namespace nitdcscore {
11
    public class Oled {
12
        public const int LCD_WIDTH = 128;
13
        public const int LCD_HEIGHT = 64;
14
 
15
        public const int EXTERNALVCC = 0x01;
16
        public const int SWITCHCAPVCC = 0x02;
17
        public const int SETLOWCOLUMN = 0x00;
18
        public const int SETHIGHCOLUMN = 0x10;
19
        public const int MEMORYMODE = 0x20;
20
        public const int COLUMNADDR = 0x21;
21
        public const int PAGEADDR = 0x22;
22
        public const int DEACTIVATESCROLL = 0x2E;
23
        public const int SETSTARTLINE = 0x40;
24
 
25
        public const int SETCONTRAST = 0x81;
26
        public const int CHARGEPUMP = 0x8D;
27
 
28
        public const int SEGREMAP = 0xA0;
29
        public const int DISPLAYALLON_RESUME = 0xA4;
30
        public const int DISPLAYALLON = 0xA5;
31
        public const int NORMALDISPLAY = 0xA6;
32
        public const int INVERTDISPLAY = 0xA7;
33
        public const int SETMULTIPLEX = 0xA8;
34
        public const int DISPLAYOFF = 0xAE;
35
        public const int DISPLAYON = 0xAF;
36
 
37
        public const int COMSCANINC = 0xC0;
38
        public const int COMSCANDEC = 0xC8;
39
 
40
        public const int SETDISPLAYOFFSET = 0xD3;
41
        public const int SETCOMPINS = 0xDA;
42
        public const int SETVCOMDETECT = 0xDB;
43
        public const int SETDISPLAYCLOCKDIV = 0xD5;
44
        public const int SETPRECHARGE = 0xD9;
45
 
184 pfowler 46
        public byte[] buffer = new byte[Oled.LCD_WIDTH / 8 * Oled.LCD_HEIGHT];
182 pfowler 47
 
48
        public int vccstate { get; set; }
184 pfowler 49
        public byte i2caddr { get; set; }
182 pfowler 50
 
51
        public i2cmaster i2c { get; set; }
52
 
184 pfowler 53
        public Oled(int vccstate, byte i2caddr, i2cmaster i2c) {
182 pfowler 54
            this.vccstate = vccstate;
55
            this.i2caddr = i2caddr;
56
            this.i2c = i2c;
184 pfowler 57
 
58
 
186 pfowler 59
            for (int t = 0; t < (LCD_WIDTH * LCD_HEIGHT / 8); t++) {
60
                buffer[t] = new byte();
61
                buffer[t] = 0x00;
184 pfowler 62
            }
186 pfowler 63
 
64
 
183 pfowler 65
        }
182 pfowler 66
 
183 pfowler 67
        public void init() {
182 pfowler 68
            // Init sequence
184 pfowler 69
 
182 pfowler 70
            oled_command(DISPLAYOFF);
71
            oled_command(SETDISPLAYCLOCKDIV);
72
            oled_command(0x80); // Suggested ratio
73
 
74
            oled_command(SETMULTIPLEX);
75
            oled_command(LCD_HEIGHT - 1);
76
 
77
            oled_command(SETDISPLAYOFFSET);
78
            oled_command(0x00); // No offset
79
            oled_command(SETSTARTLINE | 0x00); // Start line 0
80
            oled_command(CHARGEPUMP);
81
            if (this.vccstate == EXTERNALVCC)
82
                oled_command(0x10);
83
            else
84
                oled_command(0x14);
85
 
86
            oled_command(MEMORYMODE);
87
            oled_command(0x00);
88
            oled_command(SEGREMAP | 0x01);
89
            oled_command(COMSCANDEC);
90
 
91
            // 128-64 specific
92
            oled_command(SETCOMPINS);
93
            oled_command(0x12);
94
            oled_command(SETCONTRAST);
95
            if (this.vccstate == EXTERNALVCC)
96
                oled_command(0x9F);
97
            else
98
                oled_command(0xCF);
99
 
100
            oled_command(SETPRECHARGE);
101
            if (this.vccstate == EXTERNALVCC)
102
                oled_command(0x22);
103
            else
104
                oled_command(0xF1);
105
 
106
            oled_command(SETVCOMDETECT);
107
            oled_command(0x40);
108
            oled_command(DISPLAYALLON_RESUME);
109
            oled_command(NORMALDISPLAY);
110
            oled_command(DEACTIVATESCROLL);
111
 
112
            oled_command(DISPLAYON);
113
 
114
        }
115
 
116
        public void display() {
186 pfowler 117
            oled_command(COLUMNADDR);           
182 pfowler 118
            oled_command(0x00);         // Column start address
119
            oled_command(LCD_WIDTH - 1);  // Column end address
186 pfowler 120
 
182 pfowler 121
 
186 pfowler 122
 
182 pfowler 123
            oled_command(PAGEADDR);
124
            oled_command(0x00); // Page start address
125
            oled_command(7);    // Page end address (7 for 64 pixels)
126
 
186 pfowler 127
            // 1024 -  388ms
128
            //   16 - 1190ms
129
 
185 pfowler 130
            const int BYTES_TO_SEND = 1024;
131
 
182 pfowler 132
            for (int i = 0; i < (LCD_WIDTH * LCD_HEIGHT / 8); i++) {
185 pfowler 133
                byte[] data = new byte[BYTES_TO_SEND + 1];
134
                data[0] = 0x40;
135
                for (int j = 1; j < BYTES_TO_SEND + 1; j++) {
182 pfowler 136
                    data[j] = buffer[i];
137
                    i++;
138
                }
139
                i--;
185 pfowler 140
                i2c.WriteI2cData(i2cUtils.addressToWrite(this.i2caddr), data, BYTES_TO_SEND + 1);
182 pfowler 141
            }
186 pfowler 142
 
182 pfowler 143
        }
144
 
145
        public int oled_command(byte c) {
186 pfowler 146
            byte[] data = { 0x00, c };
147
 
184 pfowler 148
            i2c.WriteI2cData(i2cUtils.addressToWrite(this.i2caddr), data, 2); ;
186 pfowler 149
 
182 pfowler 150
            return 0;
151
        }
152
    }
153
 
154
    public class BmpImage {
155
        public string filename;     // The image filename
156
        public int filesize;        // Total size of the 
157
        public int datastart;       // Location of the start of image data
158
        public int imagesize;       // The size of actual image data
159
        public int width;           // Width of the image
160
        public int height;          // Height of the image
161
        public int bpp;             // Bits per pixel of the image
162
        public int bytepad;         // Bytes padded to align image row
163
        public byte[] data;         // The bmp image data
164
        public BitArray[] bitdata;  // Data in bitarray format
165
 
166
        public BmpImage(string filename) {
167
            this.filename = filename;
168
            filesize = 0;
169
            datastart = 0xffffff;
170
            imagesize = 0;
171
            width = 0;
172
            height = 0;
173
            bpp = 0;
174
            bytepad = 0;
175
            data = new byte[8192];
176
            bitdata = new BitArray[1];
177
 
178
            this.load();
179
        }
180
 
181
        public int load() {
182
            using (BinaryReader b = new BinaryReader(File.Open(this.filename, FileMode.Open))) {
183
                int pos = 0;
184
 
185
                int readLen = (int)b.BaseStream.Length;
186
                while (pos < readLen) {
187
                    // Read the image data from the file
188
                    if (pos >= this.datastart) {
189
 
190
                        // BMP format stored in 'data'
191
                        int imgptr = 0;
192
                        while (imgptr < this.imagesize) {
193
                            this.data[imgptr++] = b.ReadByte();
194
                        }
195
                        //Console.WriteLine("Read " + imgptr.ToString() + " bytes");
196
 
197
                        // Raw decoded data stored in 'bitdata'
198
                        this.bitdata = new BitArray[this.height];
199
                        int x = 0;      // Cursor X position
200
                        int y = 0;      // Cursor Y position
201
                        int i = 0;    // Current byte position
202
                        //Console.WriteLine("W:{0} H:{1}", img.width.ToString(), img.height.ToString());
203
 
204
                        for (y = this.height - 1; y >= 0; y--) {
205
 
206
                            this.bitdata[y] = new BitArray(this.width);
207
                            x = 0;
208
                            while (x < this.width) {
209
                                if (x >= this.width)
210
                                    break;
211
                                // Reverse the bit cause its stored back to front in bmp format
212
                                byte br;
213
                                br = this.data[i];
214
                                br = (byte)((br * 0x0202020202 & 0x010884422010) % 1023);
215
 
216
                                for (int bitidx = 0; bitidx < 8; bitidx++) {
217
                                    int bitpos = x + bitidx;
218
                                    if (bitpos >= this.width)
219
                                        break;
220
                                    int val = br >> bitidx & 0x01;
221
                                    //Console.WriteLine("X:{0} Y:{1}", x.ToString(), y.ToString());
222
                                    this.bitdata[y].Set(bitpos, Convert.ToBoolean(val));
223
                                }
224
                                x += 8;
225
                                i++;
226
                            }
227
                            i += this.bytepad; // Account for the padding
228
                        }
229
                        break;
230
                    }
231
 
232
                    // Read the header data from the file
233
                    switch (pos) {
234
                        // Magic number header ("BM")
235
                        case 0x00: {
236
                                byte t1 = b.ReadByte();
237
                                byte t2 = b.ReadByte();
238
                                pos += 2;
239
                                string text = ((char)t1).ToString();
240
                                text += ((char)t2).ToString();
241
                            }
242
                            break;
243
                        // The size of the image file
244
                        case 0x02: {
245
                                this.filesize = (int)b.ReadUInt32();
246
                                pos += 4;
247
                                if (this.filesize != b.BaseStream.Length)
248
                                    Console.WriteLine("Size mismatch: " + this.filesize.ToString() + ":" + b.BaseStream.Length.ToString());
249
                                else
250
                                    Console.WriteLine("Size: " + this.filesize.ToString());
251
                            }
252
                            break;
253
                        // The start of image data location
254
                        case 0x0a: {
255
                                this.datastart = (int)b.ReadUInt32();
256
                                pos += 4;
257
                            }
258
                            break;
259
                        // The DIB header file size
260
                        case 0x0e: {
261
                                //UInt32 dibhs = b.ReadUInt32();
262
                                b.ReadUInt32();
263
                                pos += 4;
264
                            }
265
                            break;
266
                        // Bitmap width in pixels
267
                        case 0x12: {
268
                                this.width = (int)b.ReadInt32();
269
                                pos += 4;
270
 
271
                                // Rows aligned to a DWORD
272
                                int bitsOver = this.width % 32;
273
                                if (bitsOver > 0) {
274
                                    this.bytepad = (32 - bitsOver) / 8;
275
                                }
276
                            }
277
                            break;
278
                        // Bitmap height in pixels
279
                        case 0x16: {
280
                                this.height = (int)b.ReadInt32();
281
                                pos += 4;
282
                            }
283
                            break;
284
                        // Bitmap bytes per pixel
285
                        case 0x1c: {
286
                                this.bpp = (int)b.ReadUInt16();
287
                                pos += 2;
288
                            }
289
                            break;
290
                        // Bitmap size
291
                        case 0x22: {
292
                                this.imagesize = (int)b.ReadUInt32();
293
                                pos += 4;
294
                            }
295
                            break;
296
 
297
                        // Not an important piece of data; dump it
298
                        default:
299
                            b.ReadByte();
300
                            pos++;
301
                            break;
302
                    }
303
                }
304
            }
305
            return 0;
306
        }
307
 
308
    }
309
 
310
    public class BitImage {
311
 
312
        public BitArray[] bitdata;
313
        public int width;
314
        public int height;
315
 
316
        public BitImage(int width, int height) {
317
            this.width = width;
318
            this.height = height;
319
            this.bitdata = new BitArray[this.height];
320
 
321
            for (int i = 0; i < this.height; i++) {
322
                this.bitdata[i] = new BitArray(this.width);
323
            }
324
        }
325
 
326
        public BitImage(BitArray[] matrix) {
327
            this.width = matrix[0].Length;
328
            this.height = matrix.Length;
329
            this.bitdata = BitImage.copy(matrix);
330
        }
331
 
332
        public BitImage(BmpImage bmp) {
333
            this.width = bmp.width;
334
            this.height = bmp.height;
335
            this.bitdata = BitImage.copy(bmp.bitdata);
336
        }
337
 
338
        public BitImage(BitImage bit) {
339
            this.width = bit.width;
340
            this.height = bit.height;
341
            this.bitdata = BitImage.copy(bit.bitdata);
342
        }
343
 
344
        public BitImage(Bitmap bmp) {
345
            //Bitmap bmp = new Bitmap(nitdcscore.Properties.Resources.flap_bg);
346
            //BitImage bi = new BitImage(new Bitmap(Resources.flap_needle));
347
            this.width = bmp.Width;
348
            this.height = bmp.Height;
349
            this.bitdata = new BitArray[this.height];
350
 
351
            for (int y = 0; y < this.height; y++) {
352
                this.bitdata[y] = new BitArray(this.width);
186 pfowler 353
                for (int x = 0; x < this.width; x++) {
182 pfowler 354
                    Color c = bmp.GetPixel(x, y);
355
 
356
                    if (c.GetBrightness() == 0)
357
                        this.bitdata[y].Set(x, false);
358
                    else
359
                        this.bitdata[y].Set(x, true);
360
                }
361
            }
362
        }
363
 
364
 
365
 
366
        public void fillAll(bool color) {
367
            for (int i = 0; i < this.height; i++) {
368
                this.bitdata[i].SetAll(color);
369
            }
370
        }
371
 
372
        public void drawPixel(int x, int y, bool color) {
373
            if (x < 0 || y < 0 || x >= this.width || y >= this.height)
374
                return;
375
            this.bitdata[y].Set(x, color);
376
        }
377
 
378
        public void drawVLine(int x, int y, int h, bool color) {
379
 
380
            if (x < 0 || x >= this.width)
381
                return;
382
 
383
            if (y < 0) {
384
                h += y;
385
                y = 0;
386
            }
387
 
388
            if ((y + h) > this.height)
389
                h = this.height - y;
390
 
391
            if (h <= 0)
392
                return;
393
 
394
            for (int i = y; i < y + h; i++) {
395
                this.bitdata[i].Set(x, color);
396
            }
397
        }
398
 
399
        public void drawHLine(int x, int y, int w, bool color) {
400
            if (y < 0 || y >= this.height)
401
                return;
402
            if (x < 0) {
403
                w += x;
404
                x = 0;
405
            }
406
 
407
            if ((x + w) > this.width)
408
                w = this.width - x;
409
 
410
            if (w <= 0)
411
                return;
412
 
413
            for (int i = x; i < x + height; i++) {
414
                this.bitdata[y].Set(i, color);
415
            }
416
        }
417
 
418
 
419
        public void drawLine(int x0, int y0, int x1, int y1, bool color) {
420
            bool steep = Math.Abs(y1 - y0) > Math.Abs(x1 - x0);
421
            if (steep) {
422
                swap(ref x0, ref y0);
423
                swap(ref x1, ref y1);
424
            }
425
 
426
            if (x0 > x1) {
427
                swap(ref x0, ref x1);
428
                swap(ref y0, ref y1);
429
            }
430
 
431
            int dx, dy;
432
            dx = x1 - x0;
433
            dy = Math.Abs(y1 - y0);
434
 
435
            int err = dx / 2;
436
            int ystep;
437
 
438
            if (y0 < y1)
439
                ystep = 1;
440
            else
441
                ystep = -1;
442
 
443
            for (; x0 <= x1; x0++) {
444
                if (steep)
445
                    drawPixel(y0, x0, color);
446
                else
447
                    drawPixel(x0, y0, color);
448
 
449
                err -= dy;
450
                if (err < 0) {
451
                    y0 += ystep;
452
                    err += dx;
453
                }
454
            }
455
        }
456
 
457
        public void drawRect(int x, int y, int w, int h, bool color) {
458
            drawHLine(x, y, w, color);
459
            drawHLine(x, y + h - 1, w, color);
460
            drawVLine(x, y, h, color);
461
            drawVLine(x + w - 1, y, h, color);
462
        }
463
 
464
        public void fillRect(int x, int y, int w, int h, bool color) {
465
            for (int i = x; i < x + w; i++) {
466
                drawVLine(i, y, h, color);
467
            }
468
        }
469
 
470
 
471
        public void drawCircle(int x0, int y0, int r, bool color) {
472
            int f = 1 - r;
473
            int ddF_x = 1;
474
            int ddF_y = -2 * r;
475
            int x = 0;
476
            int y = r;
477
 
478
            drawPixel(x0, y0 + r, color);
479
            drawPixel(x0, y0 - r, color);
480
            drawPixel(x0 + r, y0, color);
481
            drawPixel(x0 - r, y0, color);
482
 
483
            while (x < y) {
484
                if (f >= 0) {
485
                    y--;
486
                    ddF_y += 2;
487
                    f += ddF_y;
488
                }
489
                x++;
490
                ddF_x += 2;
491
                f += ddF_x;
492
 
493
                drawPixel(x0 + x, y0 + y, color);
494
                drawPixel(x0 - x, y0 + y, color);
495
                drawPixel(x0 + x, y0 - y, color);
496
                drawPixel(x0 - x, y0 - y, color);
497
                drawPixel(x0 + y, y0 + x, color);
498
                drawPixel(x0 - y, y0 + x, color);
499
                drawPixel(x0 + y, y0 - x, color);
500
                drawPixel(x0 - y, y0 - x, color);
501
            }
502
        }
503
 
504
        public void fillCircle(int x0, int y0, int r, bool color) {
505
            drawVLine(x0, y0 - r, 2 * r + 1, color);
506
            fillCircleHelper(x0, y0, r, 3, 0, color);
507
        }
508
 
509
        public void fillCircleHelper(int x0, int y0, int r, int corner, int delta, bool color) {
510
            int f = 1 - r;
511
            int ddF_x = 1;
512
            int ddF_y = -2 * r;
513
            int x = 0;
514
            int y = r;
515
 
516
            while (x < y) {
517
                if (f >= 0) {
518
                    y--;
519
                    ddF_y += 2;
520
                    f += ddF_y;
521
                }
522
                x++;
523
                ddF_x += 2;
524
                f += ddF_x;
525
 
526
                if ((corner & 0x01) > 0) {
527
                    drawVLine(x0 + x, y0 - y, 2 * y + 1 + delta, color);
528
                    drawVLine(x0 + y, y0 - x, 2 * x + 1 + delta, color);
529
                }
530
 
531
                if ((corner & 0x02) > 0) {
532
                    drawVLine(x0 - x, y0 - y, 2 * y + 1 + delta, color);
533
                    drawVLine(x0 - y, y0 - x, 2 * x + 1 + delta, color);
534
                }
535
            }
536
        }
537
 
538
        public void drawTriangle(int x0, int y0, int x1, int y1, int x2, int y2, bool color) {
539
            drawLine(x0, y0, x1, y1, color);
540
            drawLine(x1, y1, x2, y2, color);
541
            drawLine(x2, y2, x0, y0, color);
542
        }
543
 
544
        public void drawPoly(Point[] points, bool color) {
545
            int idx = 1;
546
            int c = points.Length;
547
            while (idx < c) {
548
                drawLine(points[idx - 1].X, points[idx - 1].Y, points[idx].X, points[idx].Y, color);
549
                idx++;
550
            }
551
            drawLine(points[c - 1].X, points[c - 1].Y, points[0].X, points[0].Y, color);
552
        }
553
 
554
        public void drawChar(int x, int y, byte c, bool color, int size) {
555
            for (int i = 0; i < 6; i++) {
556
                byte line;
557
                if (i < 5)
558
                    line = Font.classic[c * 5 + i];
559
                else
560
                    line = 0x00;
561
                for (int j = 0; j < 8; j++, line >>= 1) {
562
                    if ((line & 0x01) > 0) {
563
                        if (size == 1)
564
                            drawPixel(x + i, y + j, color);
565
                        else
566
                            fillRect(x + (i * size), y + (j * size), size, size, color);
567
                    }
568
                    /*
569
                    } else {
570
                        if (size == 1)
571
                            drawPixel(x + i, y + j, !color);
572
                        else
573
                            fillRect(x+i*size, y+j*size, size, size, !color);
574
                    }
575
                    */
576
                }
577
 
578
            }
579
        }
580
 
581
        public void write(string text, int x, int y, bool color, int size) {
582
            Point cur = new Point(x, y);
583
            foreach (byte c in text) {
584
                if (c == '\n') {
585
                    cur.Y += size * 8;
586
                    cur.X = x;
587
                } else if (c == '\r') {
588
 
589
                } else if (c == ' ') {
590
                    // Quicker then calling drawChar function
591
                    cur.X += size * 6;
592
                } else {
593
                    drawChar(cur.X, cur.Y, c, color, size);
594
                    cur.X += size * 6;
595
                }
596
            }
597
        }
598
 
599
        public static void swap(ref int i, ref int j) {
600
            int t = i; i = j; j = t;
601
        }
602
 
603
 
604
        /// <summary>
605
        /// Copies the provided image onto the objects image, at position specified
606
        /// by the ox and oy parms. Only copies lit bits (not dark)
607
        /// </summary>
608
        /// <param name="bit">The bit image to paste onto this image</param>
609
        /// <param name="ox">The X origin</param>
610
        /// <param name="oy">The Y origin</param>
611
        public void blit(BitImage bit, int ox, int oy) {
612
            int x = 0;
613
            int y = 0;
614
 
615
            for (y = 0; y < bit.height; y++) {
616
                for (x = 0; x < bit.width; x++) {
617
                    if (bit.bitdata[y].Get(x)) {
186 pfowler 618
                        if (oy + y > this.height -1  || ox + x > this.width)
619
                            return;
182 pfowler 620
                        this.bitdata[oy + y].Set(ox + x, true);
621
                    }
622
                }
623
            }
624
        }
625
 
626
        /// <summary>
627
        /// Rotate the image by the specified degrees.
628
        /// </summary>
629
        /// <param name="degrees">Degrees to rotate</param>
630
        public void rotate(int degrees) {
631
            this.bitdata = (BitArray[])BitImage.rotateMatrix(this.bitdata, degrees).bitdata;
632
            this.width = this.bitdata[0].Length;
633
            this.height = this.bitdata.Length;
634
        }
635
 
636
        public byte[] toByteArray() {
637
            return BitImage.toByteArray(this.bitdata);
638
        }
639
 
640
        public static BitArray[] copy(BitArray[] ba) {
641
            int width = ba[0].Length;
642
            int height = ba.Length;
643
 
644
            BitArray[] newba = new BitArray[height];
645
 
646
            for (int y = 0; y < height; y++) {
647
                newba[y] = new BitArray(width);
648
                for (int x = 0; x < width; x++) {
649
                    if (ba[y].Get(x)) {
650
                        newba[y].Set(x, true);
651
                    }
652
                }
653
            }
654
            return newba;
655
        }
656
 
657
        public static byte[] toByteArray(BitArray[] ba) {
658
            int width = ba[0].Length;
659
            int height = ba.Length;
660
 
661
            int size = width * height / 8;
662
            byte[] buffer = new byte[size];
663
            if (size % 8 != 0) {
664
                Console.WriteLine("toByteArray only supports mod 8 array (size: {0}, misalinged by {1})", size, size % 8);
665
                return null;
666
            }
667
 
186 pfowler 668
            BitArray data = new BitArray(width * height);
669
            int i = 0;
670
            for (int y = 0; y < ba.Length; y += 8) {
671
                for (int x = 0; x < width; x++) {
672
                    for (int j = 0; j < 8; j++) {
673
                        data.Set(i, ba[y+j].Get(x));
674
                        i++;
675
                    }
182 pfowler 676
                }
677
            }
186 pfowler 678
            data.CopyTo(buffer, 0);
182 pfowler 679
            return buffer;
680
        }
681
 
682
        /// <summary>
683
        /// Rotates a matrix by provided degrees. Note that the size of the
684
        ///  image may change with this process
685
        /// </summary>
686
        /// <returns>A matrix with the rotated elements</returns>
687
        /// <param name="matrix">The BitArray matrix to be rotated</param>
688
        /// <param name="degrees">The degress to rotate the matrix by</param>
689
        public static BitImage rotateMatrix(BitArray[] matrix, int degrees) {
690
            // Widths of the matrix
691
            int oldwidth = matrix[0].Length;
692
            int oldheight = matrix.Length;
693
 
694
            // If no rotation nessecary, just return a new BitImage
695
            if (degrees == 0 || degrees == 360) {
696
                BitImage bit = new BitImage(oldwidth, oldheight);
697
                bit.bitdata = (BitArray[])matrix;
698
                return bit;
699
            }
700
 
701
            // Calc the new image meta data
702
            double rads = degrees * Math.PI / 180;
703
            double tcos = Math.Cos(rads);
704
            double tsin = Math.Sin(rads);
705
 
706
            Point p1 = new Point((int)(-oldheight * tsin), (int)(oldheight * tcos));
707
            Point p2 = new Point((int)(oldwidth * tcos - oldheight * tsin),
708
                (int)(oldheight * tcos + oldwidth * tsin));
709
            Point p3 = new Point((int)(oldwidth * tcos), (int)(oldwidth * tsin));
710
            Point min = new Point(Math.Min(0, Math.Min(p1.X, Math.Min(p2.X, p3.X))),
711
                Math.Min(0, Math.Min(p1.Y, Math.Min(p2.Y, p3.Y))));
712
            Point max = new Point(Math.Max(p1.X, Math.Max(p2.X, p3.X)),
713
                Math.Max(p1.Y, Math.Max(p2.Y, p3.Y)));
714
            Point size = new Point(max.X - min.X, max.Y - min.Y);
715
 
716
            // Prepopulate the bitarray
717
            BitArray[] bitmatrix = new BitArray[size.Y];
718
            for (int y = 0; y < size.Y; y++) {
719
                bitmatrix[y] = new BitArray(size.X);
720
            }
721
 
722
            // Transform pixel by pixel
723
            for (int y = 0; y < size.Y - 1; y++) {
724
                for (int x = 0; x < size.X - 1; x++) {
725
                    int sourcex = (int)((x + min.X) * tcos + (y + min.Y) * tsin);
726
                    int sourcey = (int)((y + min.Y) * tcos - (x + min.X) * tsin);
727
 
728
                    if (sourcex < 0 || sourcex > oldwidth - 1 || sourcey < 0 || sourcey > oldheight - 1)
729
                        continue;
730
                    if (x < 0 || x > size.X - 1 || y < 0 || y > size.Y - 1)
731
                        continue;
732
 
733
                    bitmatrix[y].Set(x, matrix[sourcey].Get(sourcex));
734
                }
735
            }
736
 
737
            BitImage bi = new BitImage(bitmatrix[0].Length, bitmatrix.Length);
738
            bi.bitdata = (BitArray[])bitmatrix;
739
            return bi;
740
        }
741
 
742
    }
743
 
744
    public struct Point {
745
        private int x;
746
        private int y;
747
 
748
        public int X {
749
            get {
750
                return this.x;
751
            }
752
            set {
753
                this.x = value;
754
            }
755
        }
756
 
757
        public int Y {
758
            get {
759
                return this.y;
760
            }
761
            set {
762
                this.y = value;
763
            }
764
        }
765
 
766
        public Point(int x, int y) {
767
            this.x = x;
768
            this.y = y;
769
        }
770
    }
771
 
772
    public class Font {
773
        public Font() {
774
        }
775
 
776
        public static byte[] classic = new byte[] {
777
            0x00, 0x00, 0x00, 0x00, 0x00,
778
            0x3E, 0x5B, 0x4F, 0x5B, 0x3E,
779
            0x3E, 0x6B, 0x4F, 0x6B, 0x3E,
780
            0x1C, 0x3E, 0x7C, 0x3E, 0x1C,
781
            0x18, 0x3C, 0x7E, 0x3C, 0x18,
782
            0x1C, 0x57, 0x7D, 0x57, 0x1C,
783
            0x1C, 0x5E, 0x7F, 0x5E, 0x1C,
784
            0x00, 0x18, 0x3C, 0x18, 0x00,
785
            0xFF, 0xE7, 0xC3, 0xE7, 0xFF,
786
            0x00, 0x18, 0x24, 0x18, 0x00,
787
            0xFF, 0xE7, 0xDB, 0xE7, 0xFF,
788
            0x30, 0x48, 0x3A, 0x06, 0x0E,
789
            0x26, 0x29, 0x79, 0x29, 0x26,
790
            0x40, 0x7F, 0x05, 0x05, 0x07,
791
            0x40, 0x7F, 0x05, 0x25, 0x3F,
792
            0x5A, 0x3C, 0xE7, 0x3C, 0x5A,
793
            0x7F, 0x3E, 0x1C, 0x1C, 0x08,
794
            0x08, 0x1C, 0x1C, 0x3E, 0x7F,
795
            0x14, 0x22, 0x7F, 0x22, 0x14,
796
            0x5F, 0x5F, 0x00, 0x5F, 0x5F,
797
            0x06, 0x09, 0x7F, 0x01, 0x7F,
798
            0x00, 0x66, 0x89, 0x95, 0x6A,
799
            0x60, 0x60, 0x60, 0x60, 0x60,
800
            0x94, 0xA2, 0xFF, 0xA2, 0x94,
801
            0x08, 0x04, 0x7E, 0x04, 0x08,
802
            0x10, 0x20, 0x7E, 0x20, 0x10,
803
            0x08, 0x08, 0x2A, 0x1C, 0x08,
804
            0x08, 0x1C, 0x2A, 0x08, 0x08,
805
            0x1E, 0x10, 0x10, 0x10, 0x10,
806
            0x0C, 0x1E, 0x0C, 0x1E, 0x0C,
807
            0x30, 0x38, 0x3E, 0x38, 0x30,
808
            0x06, 0x0E, 0x3E, 0x0E, 0x06,
809
            0x00, 0x00, 0x00, 0x00, 0x00,
810
            0x00, 0x00, 0x5F, 0x00, 0x00,
811
            0x00, 0x07, 0x00, 0x07, 0x00,
812
            0x14, 0x7F, 0x14, 0x7F, 0x14,
813
            0x24, 0x2A, 0x7F, 0x2A, 0x12,
814
            0x23, 0x13, 0x08, 0x64, 0x62,
815
            0x36, 0x49, 0x56, 0x20, 0x50,
816
            0x00, 0x08, 0x07, 0x03, 0x00,
817
            0x00, 0x1C, 0x22, 0x41, 0x00,
818
            0x00, 0x41, 0x22, 0x1C, 0x00,
819
            0x2A, 0x1C, 0x7F, 0x1C, 0x2A,
820
            0x08, 0x08, 0x3E, 0x08, 0x08,
821
            0x00, 0x80, 0x70, 0x30, 0x00,
822
            0x08, 0x08, 0x08, 0x08, 0x08,
823
            0x00, 0x00, 0x60, 0x60, 0x00,
824
            0x20, 0x10, 0x08, 0x04, 0x02,
825
            0x3E, 0x51, 0x49, 0x45, 0x3E,
826
            0x00, 0x42, 0x7F, 0x40, 0x00,
827
            0x72, 0x49, 0x49, 0x49, 0x46,
828
            0x21, 0x41, 0x49, 0x4D, 0x33,
829
            0x18, 0x14, 0x12, 0x7F, 0x10,
830
            0x27, 0x45, 0x45, 0x45, 0x39,
831
            0x3C, 0x4A, 0x49, 0x49, 0x31,
832
            0x41, 0x21, 0x11, 0x09, 0x07,
833
            0x36, 0x49, 0x49, 0x49, 0x36,
834
            0x46, 0x49, 0x49, 0x29, 0x1E,
835
            0x00, 0x00, 0x14, 0x00, 0x00,
836
            0x00, 0x40, 0x34, 0x00, 0x00,
837
            0x00, 0x08, 0x14, 0x22, 0x41,
838
            0x14, 0x14, 0x14, 0x14, 0x14,
839
            0x00, 0x41, 0x22, 0x14, 0x08,
840
            0x02, 0x01, 0x59, 0x09, 0x06,
841
            0x3E, 0x41, 0x5D, 0x59, 0x4E,
842
            0x7C, 0x12, 0x11, 0x12, 0x7C,
843
            0x7F, 0x49, 0x49, 0x49, 0x36,
844
            0x3E, 0x41, 0x41, 0x41, 0x22,
845
            0x7F, 0x41, 0x41, 0x41, 0x3E,
846
            0x7F, 0x49, 0x49, 0x49, 0x41,
847
            0x7F, 0x09, 0x09, 0x09, 0x01,
848
            0x3E, 0x41, 0x41, 0x51, 0x73,
849
            0x7F, 0x08, 0x08, 0x08, 0x7F,
850
            0x00, 0x41, 0x7F, 0x41, 0x00,
851
            0x20, 0x40, 0x41, 0x3F, 0x01,
852
            0x7F, 0x08, 0x14, 0x22, 0x41,
853
            0x7F, 0x40, 0x40, 0x40, 0x40,
854
            0x7F, 0x02, 0x1C, 0x02, 0x7F,
855
            0x7F, 0x04, 0x08, 0x10, 0x7F,
856
            0x3E, 0x41, 0x41, 0x41, 0x3E,
857
            0x7F, 0x09, 0x09, 0x09, 0x06,
858
            0x3E, 0x41, 0x51, 0x21, 0x5E,
859
            0x7F, 0x09, 0x19, 0x29, 0x46,
860
            0x26, 0x49, 0x49, 0x49, 0x32,
861
            0x03, 0x01, 0x7F, 0x01, 0x03,
862
            0x3F, 0x40, 0x40, 0x40, 0x3F,
863
            0x1F, 0x20, 0x40, 0x20, 0x1F,
864
            0x3F, 0x40, 0x38, 0x40, 0x3F,
865
            0x63, 0x14, 0x08, 0x14, 0x63,
866
            0x03, 0x04, 0x78, 0x04, 0x03,
867
            0x61, 0x59, 0x49, 0x4D, 0x43,
868
            0x00, 0x7F, 0x41, 0x41, 0x41,
869
            0x02, 0x04, 0x08, 0x10, 0x20,
870
            0x00, 0x41, 0x41, 0x41, 0x7F,
871
            0x04, 0x02, 0x01, 0x02, 0x04,
872
            0x40, 0x40, 0x40, 0x40, 0x40,
873
            0x00, 0x03, 0x07, 0x08, 0x00,
874
            0x20, 0x54, 0x54, 0x78, 0x40,
875
            0x7F, 0x28, 0x44, 0x44, 0x38,
876
            0x38, 0x44, 0x44, 0x44, 0x28,
877
            0x38, 0x44, 0x44, 0x28, 0x7F,
878
            0x38, 0x54, 0x54, 0x54, 0x18,
879
            0x00, 0x08, 0x7E, 0x09, 0x02,
880
            0x18, 0xA4, 0xA4, 0x9C, 0x78,
881
            0x7F, 0x08, 0x04, 0x04, 0x78,
882
            0x00, 0x44, 0x7D, 0x40, 0x00,
883
            0x20, 0x40, 0x40, 0x3D, 0x00,
884
            0x7F, 0x10, 0x28, 0x44, 0x00,
885
            0x00, 0x41, 0x7F, 0x40, 0x00,
886
            0x7C, 0x04, 0x78, 0x04, 0x78,
887
            0x7C, 0x08, 0x04, 0x04, 0x78,
888
            0x38, 0x44, 0x44, 0x44, 0x38,
889
            0xFC, 0x18, 0x24, 0x24, 0x18,
890
            0x18, 0x24, 0x24, 0x18, 0xFC,
891
            0x7C, 0x08, 0x04, 0x04, 0x08,
892
            0x48, 0x54, 0x54, 0x54, 0x24,
893
            0x04, 0x04, 0x3F, 0x44, 0x24,
894
            0x3C, 0x40, 0x40, 0x20, 0x7C,
895
            0x1C, 0x20, 0x40, 0x20, 0x1C,
896
            0x3C, 0x40, 0x30, 0x40, 0x3C,
897
            0x44, 0x28, 0x10, 0x28, 0x44,
898
            0x4C, 0x90, 0x90, 0x90, 0x7C,
899
            0x44, 0x64, 0x54, 0x4C, 0x44,
900
            0x00, 0x08, 0x36, 0x41, 0x00,
901
            0x00, 0x00, 0x77, 0x00, 0x00,
902
            0x00, 0x41, 0x36, 0x08, 0x00,
903
            0x02, 0x01, 0x02, 0x04, 0x02,
904
            0x3C, 0x26, 0x23, 0x26, 0x3C,
905
            0x1E, 0xA1, 0xA1, 0x61, 0x12,
906
            0x3A, 0x40, 0x40, 0x20, 0x7A,
907
            0x38, 0x54, 0x54, 0x55, 0x59,
908
            0x21, 0x55, 0x55, 0x79, 0x41,
909
            0x22, 0x54, 0x54, 0x78, 0x42, // a-umlaut
910
            0x21, 0x55, 0x54, 0x78, 0x40,
911
            0x20, 0x54, 0x55, 0x79, 0x40,
912
            0x0C, 0x1E, 0x52, 0x72, 0x12,
913
            0x39, 0x55, 0x55, 0x55, 0x59,
914
            0x39, 0x54, 0x54, 0x54, 0x59,
915
            0x39, 0x55, 0x54, 0x54, 0x58,
916
            0x00, 0x00, 0x45, 0x7C, 0x41,
917
            0x00, 0x02, 0x45, 0x7D, 0x42,
918
            0x00, 0x01, 0x45, 0x7C, 0x40,
919
            0x7D, 0x12, 0x11, 0x12, 0x7D, // A-umlaut
920
            0xF0, 0x28, 0x25, 0x28, 0xF0,
921
            0x7C, 0x54, 0x55, 0x45, 0x00,
922
            0x20, 0x54, 0x54, 0x7C, 0x54,
923
            0x7C, 0x0A, 0x09, 0x7F, 0x49,
924
            0x32, 0x49, 0x49, 0x49, 0x32,
925
            0x3A, 0x44, 0x44, 0x44, 0x3A, // o-umlaut
926
            0x32, 0x4A, 0x48, 0x48, 0x30,
927
            0x3A, 0x41, 0x41, 0x21, 0x7A,
928
            0x3A, 0x42, 0x40, 0x20, 0x78,
929
            0x00, 0x9D, 0xA0, 0xA0, 0x7D,
930
            0x3D, 0x42, 0x42, 0x42, 0x3D, // O-umlaut
931
            0x3D, 0x40, 0x40, 0x40, 0x3D,
932
            0x3C, 0x24, 0xFF, 0x24, 0x24,
933
            0x48, 0x7E, 0x49, 0x43, 0x66,
934
            0x2B, 0x2F, 0xFC, 0x2F, 0x2B,
935
            0xFF, 0x09, 0x29, 0xF6, 0x20,
936
            0xC0, 0x88, 0x7E, 0x09, 0x03,
937
            0x20, 0x54, 0x54, 0x79, 0x41,
938
            0x00, 0x00, 0x44, 0x7D, 0x41,
939
            0x30, 0x48, 0x48, 0x4A, 0x32,
940
            0x38, 0x40, 0x40, 0x22, 0x7A,
941
            0x00, 0x7A, 0x0A, 0x0A, 0x72,
942
            0x7D, 0x0D, 0x19, 0x31, 0x7D,
943
            0x26, 0x29, 0x29, 0x2F, 0x28,
944
            0x26, 0x29, 0x29, 0x29, 0x26,
945
            0x30, 0x48, 0x4D, 0x40, 0x20,
946
            0x38, 0x08, 0x08, 0x08, 0x08,
947
            0x08, 0x08, 0x08, 0x08, 0x38,
948
            0x2F, 0x10, 0xC8, 0xAC, 0xBA,
949
            0x2F, 0x10, 0x28, 0x34, 0xFA,
950
            0x00, 0x00, 0x7B, 0x00, 0x00,
951
            0x08, 0x14, 0x2A, 0x14, 0x22,
952
            0x22, 0x14, 0x2A, 0x14, 0x08,
953
            0x55, 0x00, 0x55, 0x00, 0x55, // #176 (25% block) missing in old code
954
            0xAA, 0x55, 0xAA, 0x55, 0xAA, // 50% block
955
            0xFF, 0x55, 0xFF, 0x55, 0xFF, // 75% block
956
            0x00, 0x00, 0x00, 0xFF, 0x00,
957
            0x10, 0x10, 0x10, 0xFF, 0x00,
958
            0x14, 0x14, 0x14, 0xFF, 0x00,
959
            0x10, 0x10, 0xFF, 0x00, 0xFF,
960
            0x10, 0x10, 0xF0, 0x10, 0xF0,
961
            0x14, 0x14, 0x14, 0xFC, 0x00,
962
            0x14, 0x14, 0xF7, 0x00, 0xFF,
963
            0x00, 0x00, 0xFF, 0x00, 0xFF,
964
            0x14, 0x14, 0xF4, 0x04, 0xFC,
965
            0x14, 0x14, 0x17, 0x10, 0x1F,
966
            0x10, 0x10, 0x1F, 0x10, 0x1F,
967
            0x14, 0x14, 0x14, 0x1F, 0x00,
968
            0x10, 0x10, 0x10, 0xF0, 0x00,
969
            0x00, 0x00, 0x00, 0x1F, 0x10,
970
            0x10, 0x10, 0x10, 0x1F, 0x10,
971
            0x10, 0x10, 0x10, 0xF0, 0x10,
972
            0x00, 0x00, 0x00, 0xFF, 0x10,
973
            0x10, 0x10, 0x10, 0x10, 0x10,
974
            0x10, 0x10, 0x10, 0xFF, 0x10,
975
            0x00, 0x00, 0x00, 0xFF, 0x14,
976
            0x00, 0x00, 0xFF, 0x00, 0xFF,
977
            0x00, 0x00, 0x1F, 0x10, 0x17,
978
            0x00, 0x00, 0xFC, 0x04, 0xF4,
979
            0x14, 0x14, 0x17, 0x10, 0x17,
980
            0x14, 0x14, 0xF4, 0x04, 0xF4,
981
            0x00, 0x00, 0xFF, 0x00, 0xF7,
982
            0x14, 0x14, 0x14, 0x14, 0x14,
983
            0x14, 0x14, 0xF7, 0x00, 0xF7,
984
            0x14, 0x14, 0x14, 0x17, 0x14,
985
            0x10, 0x10, 0x1F, 0x10, 0x1F,
986
            0x14, 0x14, 0x14, 0xF4, 0x14,
987
            0x10, 0x10, 0xF0, 0x10, 0xF0,
988
            0x00, 0x00, 0x1F, 0x10, 0x1F,
989
            0x00, 0x00, 0x00, 0x1F, 0x14,
990
            0x00, 0x00, 0x00, 0xFC, 0x14,
991
            0x00, 0x00, 0xF0, 0x10, 0xF0,
992
            0x10, 0x10, 0xFF, 0x10, 0xFF,
993
            0x14, 0x14, 0x14, 0xFF, 0x14,
994
            0x10, 0x10, 0x10, 0x1F, 0x00,
995
            0x00, 0x00, 0x00, 0xF0, 0x10,
996
            0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
997
            0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
998
            0xFF, 0xFF, 0xFF, 0x00, 0x00,
999
            0x00, 0x00, 0x00, 0xFF, 0xFF,
1000
            0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
1001
            0x38, 0x44, 0x44, 0x38, 0x44,
1002
            0xFC, 0x4A, 0x4A, 0x4A, 0x34, // sharp-s or beta
1003
            0x7E, 0x02, 0x02, 0x06, 0x06,
1004
            0x02, 0x7E, 0x02, 0x7E, 0x02,
1005
            0x63, 0x55, 0x49, 0x41, 0x63,
1006
            0x38, 0x44, 0x44, 0x3C, 0x04,
1007
            0x40, 0x7E, 0x20, 0x1E, 0x20,
1008
            0x06, 0x02, 0x7E, 0x02, 0x02,
1009
            0x99, 0xA5, 0xE7, 0xA5, 0x99,
1010
            0x1C, 0x2A, 0x49, 0x2A, 0x1C,
1011
            0x4C, 0x72, 0x01, 0x72, 0x4C,
1012
            0x30, 0x4A, 0x4D, 0x4D, 0x30,
1013
            0x30, 0x48, 0x78, 0x48, 0x30,
1014
            0xBC, 0x62, 0x5A, 0x46, 0x3D,
1015
            0x3E, 0x49, 0x49, 0x49, 0x00,
1016
            0x7E, 0x01, 0x01, 0x01, 0x7E,
1017
            0x2A, 0x2A, 0x2A, 0x2A, 0x2A,
1018
            0x44, 0x44, 0x5F, 0x44, 0x44,
1019
            0x40, 0x51, 0x4A, 0x44, 0x40,
1020
            0x40, 0x44, 0x4A, 0x51, 0x40,
1021
            0x00, 0x00, 0xFF, 0x01, 0x03,
1022
            0xE0, 0x80, 0xFF, 0x00, 0x00,
1023
            0x08, 0x08, 0x6B, 0x6B, 0x08,
1024
            0x36, 0x12, 0x36, 0x24, 0x36,
1025
            0x06, 0x0F, 0x09, 0x0F, 0x06,
1026
            0x00, 0x00, 0x18, 0x18, 0x00,
1027
            0x00, 0x00, 0x10, 0x10, 0x00,
1028
            0x30, 0x40, 0xFF, 0x01, 0x01,
1029
            0x00, 0x1F, 0x01, 0x01, 0x1E,
1030
            0x00, 0x19, 0x1D, 0x17, 0x12,
1031
            0x00, 0x3C, 0x3C, 0x3C, 0x3C,
1032
            0x00, 0x00, 0x00, 0x00, 0x00  // #255 NBSP
1033
        };
1034
    }
1035
}