Subversion Repositories group.electronics

Rev

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