Passed
Push — master ( 48d769...5ccf6e )
by Michael
07:14
created

phpthumb_bmp::GD2BMPstring()   B

Complexity

Conditions 4
Paths 5

Size

Total Lines 40
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 4
eloc 29
c 2
b 0
f 0
nc 5
nop 1
dl 0
loc 40
rs 8.5806
1
<?php
2
/////////////////////////////////////////////////////////////////
3
/// getID3() by James Heinrich <[email protected]>               //
4
//  available at http://getid3.sourceforge.net                 //
5
//            or http://www.getid3.org                         //
6
/////////////////////////////////////////////////////////////////
7
// See readme.txt for more details                             //
8
/////////////////////////////////////////////////////////////////
9
//                                                             //
10
// module.graphic.bmp.php                                      //
11
// module for analyzing BMP Image files                        //
12
// dependencies: NONE                                          //
13
//                                                            ///
14
/////////////////////////////////////////////////////////////////
15
//                                                             //
16
// Modified for use in phpThumb() - James Heinrich 2004.07.27  //
17
//                                                             //
18
/////////////////////////////////////////////////////////////////
19
20
/**
21
 * Class phpthumb_bmp
22
 */
23
class phpthumb_bmp
24
{
25
    /**
26
     * @param      $BMPdata
27
     * @param bool $truecolor
28
     * @return bool|resource
29
     */
30
    public function phpthumb_bmp2gd(&$BMPdata, $truecolor = true)
31
    {
32
        $ThisFileInfo = [];
33
        if ($this->getid3_bmp($BMPdata, $ThisFileInfo, true, true)) {
34
            $gd = $this->PlotPixelsGD($ThisFileInfo['bmp'], $truecolor);
35
36
            return $gd;
37
        }
38
39
        return false;
40
    }
41
42
    /**
43
     * @param      $filename
44
     * @param bool $truecolor
45
     * @return bool|resource
46
     */
47
    public function phpthumb_bmpfile2gd($filename, $truecolor = true)
48
    {
49
        if ($fp = @fopen($filename, 'rb')) {
50
            $BMPdata = fread($fp, filesize($filename));
51
            fclose($fp);
52
53
            return $this->phpthumb_bmp2gd($BMPdata, $truecolor);
54
        }
55
56
        return false;
57
    }
58
59
    /**
60
     * @param $gd_image
61
     * @return string
62
     */
63
    public function GD2BMPstring(&$gd_image)
64
    {
65
        $imageX = imagesx($gd_image);
66
        $imageY = imagesy($gd_image);
67
68
        $BMP = '';
69
        for ($y = ($imageY - 1); $y >= 0; $y--) {
70
            $thisline = '';
71
            for ($x = 0; $x < $imageX; $x++) {
72
                $argb     = phpthumb_functions::GetPixelColor($gd_image, $x, $y);
73
                $thisline .= chr($argb['blue']) . chr($argb['green']) . chr($argb['red']);
74
            }
75
            while (strlen($thisline) % 4) {
76
                $thisline .= "\x00";
77
            }
78
            $BMP .= $thisline;
79
        }
80
81
        $bmpSize = strlen($BMP) + 14 + 40;
82
        // BITMAPFILEHEADER [14 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_62uq.asp
83
        $BITMAPFILEHEADER = 'BM';                                                           // WORD    bfType;
84
        $BITMAPFILEHEADER .= phpthumb_functions::LittleEndian2String($bmpSize, 4); // DWORD   bfSize;
85
        $BITMAPFILEHEADER .= phpthumb_functions::LittleEndian2String(0, 2); // WORD    bfReserved1;
86
        $BITMAPFILEHEADER .= phpthumb_functions::LittleEndian2String(0, 2); // WORD    bfReserved2;
87
        $BITMAPFILEHEADER .= phpthumb_functions::LittleEndian2String(54, 4); // DWORD   bfOffBits;
88
89
        // BITMAPINFOHEADER - [40 bytes] http://msdn.microsoft.com/library/en-us/gdi/bitmaps_1rw2.asp
90
        $BITMAPINFOHEADER = phpthumb_functions::LittleEndian2String(40, 4); // DWORD  biSize;
91
        $BITMAPINFOHEADER .= phpthumb_functions::LittleEndian2String($imageX, 4); // LONG   biWidth;
92
        $BITMAPINFOHEADER .= phpthumb_functions::LittleEndian2String($imageY, 4); // LONG   biHeight;
93
        $BITMAPINFOHEADER .= phpthumb_functions::LittleEndian2String(1, 2); // WORD   biPlanes;
94
        $BITMAPINFOHEADER .= phpthumb_functions::LittleEndian2String(24, 2); // WORD   biBitCount;
95
        $BITMAPINFOHEADER .= phpthumb_functions::LittleEndian2String(0, 4); // DWORD  biCompression;
96
        $BITMAPINFOHEADER .= phpthumb_functions::LittleEndian2String(0, 4); // DWORD  biSizeImage;
97
        $BITMAPINFOHEADER .= phpthumb_functions::LittleEndian2String(2835, 4); // LONG   biXPelsPerMeter;
98
        $BITMAPINFOHEADER .= phpthumb_functions::LittleEndian2String(2835, 4); // LONG   biYPelsPerMeter;
99
        $BITMAPINFOHEADER .= phpthumb_functions::LittleEndian2String(0, 4); // DWORD  biClrUsed;
100
        $BITMAPINFOHEADER .= phpthumb_functions::LittleEndian2String(0, 4); // DWORD  biClrImportant;
101
102
        return $BITMAPFILEHEADER . $BITMAPINFOHEADER . $BMP;
103
    }
104
105
    /**
106
     * @param      $BMPdata
107
     * @param      $ThisFileInfo
108
     * @param bool $ExtractPalette
109
     * @param bool $ExtractData
110
     * @return bool
111
     */
112
    public function getid3_bmp(&$BMPdata, &$ThisFileInfo, $ExtractPalette = false, $ExtractData = false)
113
    {
114
115
        // shortcuts
116
        $ThisFileInfo['bmp']['header']['raw'] = [];
117
        $thisfile_bmp                         =& $ThisFileInfo['bmp'];
118
        $thisfile_bmp_header                  =& $thisfile_bmp['header'];
119
        $thisfile_bmp_header_raw              =& $thisfile_bmp_header['raw'];
120
121
        // BITMAPFILEHEADER [14 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_62uq.asp
122
        // all versions
123
        // WORD    bfType;
124
        // DWORD   bfSize;
125
        // WORD    bfReserved1;
126
        // WORD    bfReserved2;
127
        // DWORD   bfOffBits;
128
129
        $offset        = 0;
130
        $overalloffset = 0;
131
        $BMPheader     = substr($BMPdata, $overalloffset, 14 + 40);
132
        $overalloffset += (14 + 40);
133
134
        $thisfile_bmp_header_raw['identifier'] = substr($BMPheader, $offset, 2);
135
        $offset                                += 2;
136
137
        if ('BM' !== $thisfile_bmp_header_raw['identifier']) {
138
            $ThisFileInfo['error'][] = 'Expecting "BM" at offset ' . (int)(@$ThisFileInfo['avdataoffset']) . ', found "' . $thisfile_bmp_header_raw['identifier'] . '"';
139
            unset($ThisFileInfo['fileformat']);
140
            unset($ThisFileInfo['bmp']);
141
142
            return false;
143
        }
144
145
        $thisfile_bmp_header_raw['filesize']    = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
146
        $offset                                 += 4;
147
        $thisfile_bmp_header_raw['reserved1']   = $this->LittleEndian2Int(substr($BMPheader, $offset, 2));
148
        $offset                                 += 2;
149
        $thisfile_bmp_header_raw['reserved2']   = $this->LittleEndian2Int(substr($BMPheader, $offset, 2));
150
        $offset                                 += 2;
151
        $thisfile_bmp_header_raw['data_offset'] = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
152
        $offset                                 += 4;
153
        $thisfile_bmp_header_raw['header_size'] = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
154
        $offset                                 += 4;
155
156
        // check if the hardcoded-to-1 "planes" is at offset 22 or 26
157
        $planes22 = $this->LittleEndian2Int(substr($BMPheader, 22, 2));
158
        $planes26 = $this->LittleEndian2Int(substr($BMPheader, 26, 2));
159
        if ((1 == $planes22) && (1 != $planes26)) {
160
            $thisfile_bmp['type_os']      = 'OS/2';
161
            $thisfile_bmp['type_version'] = 1;
162
        } elseif ((1 == $planes26) && (1 != $planes22)) {
163
            $thisfile_bmp['type_os']      = 'Windows';
164
            $thisfile_bmp['type_version'] = 1;
165
        } elseif (12 == $thisfile_bmp_header_raw['header_size']) {
166
            $thisfile_bmp['type_os']      = 'OS/2';
167
            $thisfile_bmp['type_version'] = 1;
168
        } elseif (40 == $thisfile_bmp_header_raw['header_size']) {
169
            $thisfile_bmp['type_os']      = 'Windows';
170
            $thisfile_bmp['type_version'] = 1;
171
        } elseif (84 == $thisfile_bmp_header_raw['header_size']) {
172
            $thisfile_bmp['type_os']      = 'Windows';
173
            $thisfile_bmp['type_version'] = 4;
174
        } elseif (100 == $thisfile_bmp_header_raw['header_size']) {
175
            $thisfile_bmp['type_os']      = 'Windows';
176
            $thisfile_bmp['type_version'] = 5;
177
        } else {
178
            $ThisFileInfo['error'][] = 'Unknown BMP subtype (or not a BMP file)';
179
            unset($ThisFileInfo['fileformat']);
180
            unset($ThisFileInfo['bmp']);
181
182
            return false;
183
        }
184
185
        $ThisFileInfo['fileformat']                  = 'bmp';
186
        $ThisFileInfo['video']['dataformat']         = 'bmp';
187
        $ThisFileInfo['video']['lossless']           = true;
188
        $ThisFileInfo['video']['pixel_aspect_ratio'] = (float)1;
189
190
        if ('OS/2' === $thisfile_bmp['type_os']) {
191
192
            // OS/2-format BMP
193
            // http://netghost.narod.ru/gff/graphics/summary/os2bmp.htm
194
195
            // DWORD  Size;             /* Size of this structure in bytes */
196
            // DWORD  Width;            /* Bitmap width in pixels */
197
            // DWORD  Height;           /* Bitmap height in pixel */
198
            // WORD   NumPlanes;        /* Number of bit planes (color depth) */
199
            // WORD   BitsPerPixel;     /* Number of bits per pixel per plane */
200
201
            $thisfile_bmp_header_raw['width']          = $this->LittleEndian2Int(substr($BMPheader, $offset, 2));
202
            $offset                                    += 2;
203
            $thisfile_bmp_header_raw['height']         = $this->LittleEndian2Int(substr($BMPheader, $offset, 2));
204
            $offset                                    += 2;
205
            $thisfile_bmp_header_raw['planes']         = $this->LittleEndian2Int(substr($BMPheader, $offset, 2));
206
            $offset                                    += 2;
207
            $thisfile_bmp_header_raw['bits_per_pixel'] = $this->LittleEndian2Int(substr($BMPheader, $offset, 2));
208
            $offset                                    += 2;
209
210
            $ThisFileInfo['video']['resolution_x']    = $thisfile_bmp_header_raw['width'];
211
            $ThisFileInfo['video']['resolution_y']    = $thisfile_bmp_header_raw['height'];
212
            $ThisFileInfo['video']['codec']           = 'BI_RGB ' . $thisfile_bmp_header_raw['bits_per_pixel'] . '-bit';
213
            $ThisFileInfo['video']['bits_per_sample'] = $thisfile_bmp_header_raw['bits_per_pixel'];
214
215
            if ($thisfile_bmp['type_version'] >= 2) {
216
                // DWORD  Compression;      /* Bitmap compression scheme */
217
                // DWORD  ImageDataSize;    /* Size of bitmap data in bytes */
218
                // DWORD  XResolution;      /* X resolution of display device */
219
                // DWORD  YResolution;      /* Y resolution of display device */
220
                // DWORD  ColorsUsed;       /* Number of color table indices used */
221
                // DWORD  ColorsImportant;  /* Number of important color indices */
222
                // WORD   Units;            /* Type of units used to measure resolution */
223
                // WORD   Reserved;         /* Pad structure to 4-byte boundary */
224
                // WORD   Recording;        /* Recording algorithm */
225
                // WORD   Rendering;        /* Halftoning algorithm used */
226
                // DWORD  Size1;            /* Reserved for halftoning algorithm use */
227
                // DWORD  Size2;            /* Reserved for halftoning algorithm use */
228
                // DWORD  ColorEncoding;    /* Color model used in bitmap */
229
                // DWORD  Identifier;       /* Reserved for application use */
230
231
                $thisfile_bmp_header_raw['compression']      = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
232
                $offset                                      += 4;
233
                $thisfile_bmp_header_raw['bmp_data_size']    = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
234
                $offset                                      += 4;
235
                $thisfile_bmp_header_raw['resolution_h']     = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
236
                $offset                                      += 4;
237
                $thisfile_bmp_header_raw['resolution_v']     = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
238
                $offset                                      += 4;
239
                $thisfile_bmp_header_raw['colors_used']      = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
240
                $offset                                      += 4;
241
                $thisfile_bmp_header_raw['colors_important'] = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
242
                $offset                                      += 4;
243
                $thisfile_bmp_header_raw['resolution_units'] = $this->LittleEndian2Int(substr($BMPheader, $offset, 2));
244
                $offset                                      += 2;
245
                $thisfile_bmp_header_raw['reserved1']        = $this->LittleEndian2Int(substr($BMPheader, $offset, 2));
246
                $offset                                      += 2;
247
                $thisfile_bmp_header_raw['recording']        = $this->LittleEndian2Int(substr($BMPheader, $offset, 2));
248
                $offset                                      += 2;
249
                $thisfile_bmp_header_raw['rendering']        = $this->LittleEndian2Int(substr($BMPheader, $offset, 2));
250
                $offset                                      += 2;
251
                $thisfile_bmp_header_raw['size1']            = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
252
                $offset                                      += 4;
253
                $thisfile_bmp_header_raw['size2']            = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
254
                $offset                                      += 4;
255
                $thisfile_bmp_header_raw['color_encoding']   = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
256
                $offset                                      += 4;
257
                $thisfile_bmp_header_raw['identifier']       = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
258
                $offset                                      += 4;
259
260
                $thisfile_bmp_header['compression'] = $this->BMPcompressionOS2Lookup($thisfile_bmp_header_raw['compression']);
261
262
                $ThisFileInfo['video']['codec'] = $thisfile_bmp_header['compression'] . ' ' . $thisfile_bmp_header_raw['bits_per_pixel'] . '-bit';
263
            }
264
        } elseif ('Windows' === $thisfile_bmp['type_os']) {
265
266
            // Windows-format BMP
267
268
            // BITMAPINFOHEADER - [40 bytes] http://msdn.microsoft.com/library/en-us/gdi/bitmaps_1rw2.asp
269
            // all versions
270
            // DWORD  biSize;
271
            // LONG   biWidth;
272
            // LONG   biHeight;
273
            // WORD   biPlanes;
274
            // WORD   biBitCount;
275
            // DWORD  biCompression;
276
            // DWORD  biSizeImage;
277
            // LONG   biXPelsPerMeter;
278
            // LONG   biYPelsPerMeter;
279
            // DWORD  biClrUsed;
280
            // DWORD  biClrImportant;
281
282
            $thisfile_bmp_header_raw['width']            = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
283
            $offset                                      += 4;
284
            $thisfile_bmp_header_raw['height']           = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
285
            $offset                                      += 4;
286
            $thisfile_bmp_header_raw['planes']           = $this->LittleEndian2Int(substr($BMPheader, $offset, 2));
287
            $offset                                      += 2;
288
            $thisfile_bmp_header_raw['bits_per_pixel']   = $this->LittleEndian2Int(substr($BMPheader, $offset, 2));
289
            $offset                                      += 2;
290
            $thisfile_bmp_header_raw['compression']      = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
291
            $offset                                      += 4;
292
            $thisfile_bmp_header_raw['bmp_data_size']    = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
293
            $offset                                      += 4;
294
            $thisfile_bmp_header_raw['resolution_h']     = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
295
            $offset                                      += 4;
296
            $thisfile_bmp_header_raw['resolution_v']     = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
297
            $offset                                      += 4;
298
            $thisfile_bmp_header_raw['colors_used']      = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
299
            $offset                                      += 4;
300
            $thisfile_bmp_header_raw['colors_important'] = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
301
            $offset                                      += 4;
302
303
            $thisfile_bmp_header['compression']       = $this->BMPcompressionWindowsLookup($thisfile_bmp_header_raw['compression']);
304
            $ThisFileInfo['video']['resolution_x']    = $thisfile_bmp_header_raw['width'];
305
            $ThisFileInfo['video']['resolution_y']    = $thisfile_bmp_header_raw['height'];
306
            $ThisFileInfo['video']['codec']           = $thisfile_bmp_header['compression'] . ' ' . $thisfile_bmp_header_raw['bits_per_pixel'] . '-bit';
307
            $ThisFileInfo['video']['bits_per_sample'] = $thisfile_bmp_header_raw['bits_per_pixel'];
308
309
            if (($thisfile_bmp['type_version'] >= 4) || (3 == $thisfile_bmp_header_raw['compression'])) {
310
                // should only be v4+, but BMPs with type_version==1 and BI_BITFIELDS compression have been seen
311
                $BMPheader     .= substr($BMPdata, $overalloffset, 44);
312
                $overalloffset += 44;
313
314
                // BITMAPV4HEADER - [44 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_2k1e.asp
315
                // Win95+, WinNT4.0+
316
                // DWORD        bV4RedMask;
317
                // DWORD        bV4GreenMask;
318
                // DWORD        bV4BlueMask;
319
                // DWORD        bV4AlphaMask;
320
                // DWORD        bV4CSType;
321
                // CIEXYZTRIPLE bV4Endpoints;
322
                // DWORD        bV4GammaRed;
323
                // DWORD        bV4GammaGreen;
324
                // DWORD        bV4GammaBlue;
325
                $thisfile_bmp_header_raw['red_mask']     = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
326
                $offset                                  += 4;
327
                $thisfile_bmp_header_raw['green_mask']   = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
328
                $offset                                  += 4;
329
                $thisfile_bmp_header_raw['blue_mask']    = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
330
                $offset                                  += 4;
331
                $thisfile_bmp_header_raw['alpha_mask']   = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
332
                $offset                                  += 4;
333
                $thisfile_bmp_header_raw['cs_type']      = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
334
                $offset                                  += 4;
335
                $thisfile_bmp_header_raw['ciexyz_red']   = substr($BMPheader, $offset, 4);
336
                $offset                                  += 4;
337
                $thisfile_bmp_header_raw['ciexyz_green'] = substr($BMPheader, $offset, 4);
338
                $offset                                  += 4;
339
                $thisfile_bmp_header_raw['ciexyz_blue']  = substr($BMPheader, $offset, 4);
340
                $offset                                  += 4;
341
                $thisfile_bmp_header_raw['gamma_red']    = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
342
                $offset                                  += 4;
343
                $thisfile_bmp_header_raw['gamma_green']  = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
344
                $offset                                  += 4;
345
                $thisfile_bmp_header_raw['gamma_blue']   = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
346
                $offset                                  += 4;
347
348
                $thisfile_bmp_header['ciexyz_red']   = $this->FixedPoint2_30(strrev($thisfile_bmp_header_raw['ciexyz_red']));
349
                $thisfile_bmp_header['ciexyz_green'] = $this->FixedPoint2_30(strrev($thisfile_bmp_header_raw['ciexyz_green']));
350
                $thisfile_bmp_header['ciexyz_blue']  = $this->FixedPoint2_30(strrev($thisfile_bmp_header_raw['ciexyz_blue']));
351
            }
352
353
            if ($thisfile_bmp['type_version'] >= 5) {
354
                $BMPheader     .= substr($BMPdata, $overalloffset, 16);
355
                $overalloffset += 16;
356
357
                // BITMAPV5HEADER - [16 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_7c36.asp
358
                // Win98+, Win2000+
359
                // DWORD        bV5Intent;
360
                // DWORD        bV5ProfileData;
361
                // DWORD        bV5ProfileSize;
362
                // DWORD        bV5Reserved;
363
                $thisfile_bmp_header_raw['intent']              = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
364
                $offset                                         += 4;
365
                $thisfile_bmp_header_raw['profile_data_offset'] = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
366
                $offset                                         += 4;
367
                $thisfile_bmp_header_raw['profile_data_size']   = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
368
                $offset                                         += 4;
369
                $thisfile_bmp_header_raw['reserved3']           = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
370
                $offset                                         += 4;
371
            }
372
        } else {
373
            $ThisFileInfo['error'][] = 'Unknown BMP format in header.';
374
375
            return false;
376
        }
377
378
        if ($ExtractPalette || $ExtractData) {
379
            $PaletteEntries = 0;
380
            if ($thisfile_bmp_header_raw['bits_per_pixel'] < 16) {
381
                $PaletteEntries = 2 ** $thisfile_bmp_header_raw['bits_per_pixel'];
382
            } elseif (isset($thisfile_bmp_header_raw['colors_used']) && ($thisfile_bmp_header_raw['colors_used'] > 0)
383
                      && ($thisfile_bmp_header_raw['colors_used'] <= 256)) {
384
                $PaletteEntries = $thisfile_bmp_header_raw['colors_used'];
385
            }
386
            if ($PaletteEntries > 0) {
387
                $BMPpalette    = substr($BMPdata, $overalloffset, 4 * $PaletteEntries);
388
                $overalloffset += 4 * $PaletteEntries;
389
390
                $paletteoffset = 0;
391
                for ($i = 0; $i < $PaletteEntries; $i++) {
392
                    // RGBQUAD          - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_5f8y.asp
393
                    // BYTE    rgbBlue;
394
                    // BYTE    rgbGreen;
395
                    // BYTE    rgbRed;
396
                    // BYTE    rgbReserved;
397
                    $blue  = $this->LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1));
398
                    $green = $this->LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1));
399
                    $red   = $this->LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1));
400
                    if (('OS/2' === $thisfile_bmp['type_os']) && (1 == $thisfile_bmp['type_version'])) {
401
                        // no padding byte
402
                    } else {
403
                        $paletteoffset++; // padding byte
404
                    }
405
                    $thisfile_bmp['palette'][$i] = (($red << 16) | ($green << 8) | $blue);
406
                }
407
            }
408
        }
409
410
        if ($ExtractData) {
411
            $RowByteLength = ceil(($thisfile_bmp_header_raw['width'] * ($thisfile_bmp_header_raw['bits_per_pixel'] / 8)) / 4) * 4; // round up to nearest DWORD boundry
412
413
            $BMPpixelData  = substr($BMPdata, $thisfile_bmp_header_raw['data_offset'], $thisfile_bmp_header_raw['height'] * $RowByteLength);
0 ignored issues
show
Bug introduced by
$thisfile_bmp_header_raw...ight'] * $RowByteLength of type double is incompatible with the type integer expected by parameter $length of substr(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

413
            $BMPpixelData  = substr($BMPdata, $thisfile_bmp_header_raw['data_offset'], /** @scrutinizer ignore-type */ $thisfile_bmp_header_raw['height'] * $RowByteLength);
Loading history...
414
            $overalloffset = $thisfile_bmp_header_raw['data_offset'] + ($thisfile_bmp_header_raw['height'] * $RowByteLength);
0 ignored issues
show
Unused Code introduced by
The assignment to $overalloffset is dead and can be removed.
Loading history...
415
416
            $pixeldataoffset = 0;
417
            switch (@$thisfile_bmp_header_raw['compression']) {
418
419
                case 0: // BI_RGB
420
                    switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
421
                        case 1:
422
                            for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
423
                                for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col = $col) {
424
                                    $paletteindexbyte = ord($BMPpixelData{$pixeldataoffset++});
425
                                    for ($i = 7; $i >= 0; $i--) {
426
                                        $paletteindex                     = ($paletteindexbyte & (0x01 << $i)) >> $i;
427
                                        $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
428
                                        $col++;
429
                                    }
430
                                }
431
                                while (0 != ($pixeldataoffset % 4)) {
432
                                    // lines are padded to nearest DWORD
433
                                    $pixeldataoffset++;
434
                                }
435
                            }
436
                            break;
437
438
                        case 4:
439
                            for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
440
                                for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col = $col) {
441
                                    $paletteindexbyte = ord($BMPpixelData{$pixeldataoffset++});
442
                                    for ($i = 1; $i >= 0; $i--) {
443
                                        $paletteindex                     = ($paletteindexbyte & (0x0F << (4 * $i))) >> (4 * $i);
444
                                        $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
445
                                        $col++;
446
                                    }
447
                                }
448
                                while (0 != ($pixeldataoffset % 4)) {
449
                                    // lines are padded to nearest DWORD
450
                                    $pixeldataoffset++;
451
                                }
452
                            }
453
                            break;
454
455
                        case 8:
456
                            for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
457
                                for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
458
                                    $paletteindex                     = ord($BMPpixelData{$pixeldataoffset++});
459
                                    $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
460
                                }
461
                                while (0 != ($pixeldataoffset % 4)) {
462
                                    // lines are padded to nearest DWORD
463
                                    $pixeldataoffset++;
464
                                }
465
                            }
466
                            break;
467
468
                        case 24:
469
                            for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
470
                                for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
471
                                    $thisfile_bmp['data'][$row][$col] = (ord($BMPpixelData{$pixeldataoffset + 2}) << 16) | (ord($BMPpixelData{$pixeldataoffset + 1}) << 8) | ord($BMPpixelData{$pixeldataoffset});
472
                                    $pixeldataoffset                  += 3;
473
                                }
474
                                while (0 != ($pixeldataoffset % 4)) {
475
                                    // lines are padded to nearest DWORD
476
                                    $pixeldataoffset++;
477
                                }
478
                            }
479
                            break;
480
481
                        case 32:
482
                            for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
483
                                for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
484
                                    $thisfile_bmp['data'][$row][$col] = (ord($BMPpixelData{$pixeldataoffset + 3}) << 24) | (ord($BMPpixelData{$pixeldataoffset + 2}) << 16) | (ord($BMPpixelData{$pixeldataoffset + 1}) << 8) | ord($BMPpixelData{$pixeldataoffset});
485
                                    $pixeldataoffset                  += 4;
486
                                }
487
                                while (0 != ($pixeldataoffset % 4)) {
488
                                    // lines are padded to nearest DWORD
489
                                    $pixeldataoffset++;
490
                                }
491
                            }
492
                            break;
493
494
                        case 16:
495
                            // ?
496
                            break;
497
498
                        default:
499
                            $ThisFileInfo['error'][] = 'Unknown bits-per-pixel value (' . $thisfile_bmp_header_raw['bits_per_pixel'] . ') - cannot read pixel data';
500
                            break;
501
                    }
502
                    break;
503
504
                case 1: // BI_RLE8 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp
505
                    switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
506
                        case 8:
507
                            $pixelcounter = 0;
508
                            while ($pixeldataoffset < strlen($BMPpixelData)) {
509
                                $firstbyte  = $this->LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
510
                                $secondbyte = $this->LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
511
                                if (0 == $firstbyte) {
512
513
                                    // escaped/absolute mode - the first byte of the pair can be set to zero to
514
                                    // indicate an escape character that denotes the end of a line, the end of
515
                                    // a bitmap, or a delta, depending on the value of the second byte.
516
                                    switch ($secondbyte) {
517
                                        case 0:
518
                                            // end of line
519
                                            // no need for special processing, just ignore
520
                                            break;
521
522
                                        case 1:
523
                                            // end of bitmap
524
                                            $pixeldataoffset = strlen($BMPpixelData); // force to exit loop just in case
525
                                            break;
526
527
                                        case 2:
528
                                            // delta - The 2 bytes following the escape contain unsigned values
529
                                            // indicating the horizontal and vertical offsets of the next pixel
530
                                            // from the current position.
531
                                            $colincrement = $this->LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
532
                                            $rowincrement = $this->LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
533
                                            $col          = ($pixelcounter % $thisfile_bmp_header_raw['width']) + $colincrement;
534
                                            $row          = ($thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width'])) - $rowincrement;
535
                                            $pixelcounter = ($row * $thisfile_bmp_header_raw['width']) + $col;
536
                                            break;
537
538
                                        default:
539
                                            // In absolute mode, the first byte is zero and the second byte is a
540
                                            // value in the range 03H through FFH. The second byte represents the
541
                                            // number of bytes that follow, each of which contains the color index
542
                                            // of a single pixel. Each run must be aligned on a word boundary.
543
                                            for ($i = 0; $i < $secondbyte; $i++) {
544
                                                $paletteindex                     = $this->LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
545
                                                $col                              = $pixelcounter % $thisfile_bmp_header_raw['width'];
546
                                                $row                              = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']);
547
                                                $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
548
                                                $pixelcounter++;
549
                                            }
550
                                            while (0 != ($pixeldataoffset % 2)) {
551
                                                // Each run must be aligned on a word boundary.
552
                                                $pixeldataoffset++;
553
                                            }
554
                                            break;
555
                                    }
556
                                } else {
557
558
                                    // encoded mode - the first byte specifies the number of consecutive pixels
559
                                    // to be drawn using the color index contained in the second byte.
560
                                    for ($i = 0; $i < $firstbyte; $i++) {
561
                                        $col                              = $pixelcounter % $thisfile_bmp_header_raw['width'];
562
                                        $row                              = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']);
563
                                        $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$secondbyte];
564
                                        $pixelcounter++;
565
                                    }
566
                                }
567
                            }
568
                            break;
569
570
                        default:
571
                            $ThisFileInfo['error'][] = 'Unknown bits-per-pixel value (' . $thisfile_bmp_header_raw['bits_per_pixel'] . ') - cannot read pixel data';
572
                            break;
573
                    }
574
                    break;
575
576
                case 2: // BI_RLE4 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp
577
                    switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
578
                        case 4:
579
                            $pixelcounter = 0;
580
                            while ($pixeldataoffset < strlen($BMPpixelData)) {
581
                                $firstbyte  = $this->LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
582
                                $secondbyte = $this->LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
583
                                if (0 == $firstbyte) {
584
585
                                    // escaped/absolute mode - the first byte of the pair can be set to zero to
586
                                    // indicate an escape character that denotes the end of a line, the end of
587
                                    // a bitmap, or a delta, depending on the value of the second byte.
588
                                    switch ($secondbyte) {
589
                                        case 0:
590
                                            // end of line
591
                                            // no need for special processing, just ignore
592
                                            break;
593
594
                                        case 1:
595
                                            // end of bitmap
596
                                            $pixeldataoffset = strlen($BMPpixelData); // force to exit loop just in case
597
                                            break;
598
599
                                        case 2:
600
                                            // delta - The 2 bytes following the escape contain unsigned values
601
                                            // indicating the horizontal and vertical offsets of the next pixel
602
                                            // from the current position.
603
                                            $colincrement = $this->LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
604
                                            $rowincrement = $this->LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
605
                                            $col          = ($pixelcounter % $thisfile_bmp_header_raw['width']) + $colincrement;
606
                                            $row          = ($thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width'])) - $rowincrement;
607
                                            $pixelcounter = ($row * $thisfile_bmp_header_raw['width']) + $col;
608
                                            break;
609
610
                                        default:
611
                                            // In absolute mode, the first byte is zero. The second byte contains the number
612
                                            // of color indexes that follow. Subsequent bytes contain color indexes in their
613
                                            // high- and low-order 4 bits, one color index for each pixel. In absolute mode,
614
                                            // each run must be aligned on a word boundary.
615
                                            $paletteindexes = [];
616
                                            for ($i = 0; $i < ceil($secondbyte / 2); $i++) {
617
                                                $paletteindexbyte = $this->LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
618
                                                $paletteindexes[] = ($paletteindexbyte & 0xF0) >> 4;
619
                                                $paletteindexes[] = ($paletteindexbyte & 0x0F);
620
                                            }
621
                                            while (0 != ($pixeldataoffset % 2)) {
622
                                                // Each run must be aligned on a word boundary.
623
                                                $pixeldataoffset++;
624
                                            }
625
626
                                            foreach ($paletteindexes as $dummy => $paletteindex) {
627
                                                $col                              = $pixelcounter % $thisfile_bmp_header_raw['width'];
628
                                                $row                              = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']);
629
                                                $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
630
                                                $pixelcounter++;
631
                                            }
632
                                            break;
633
                                    }
634
                                } else {
635
636
                                    // encoded mode - the first byte of the pair contains the number of pixels to be
637
                                    // drawn using the color indexes in the second byte. The second byte contains two
638
                                    // color indexes, one in its high-order 4 bits and one in its low-order 4 bits.
639
                                    // The first of the pixels is drawn using the color specified by the high-order
640
                                    // 4 bits, the second is drawn using the color in the low-order 4 bits, the third
641
                                    // is drawn using the color in the high-order 4 bits, and so on, until all the
642
                                    // pixels specified by the first byte have been drawn.
643
                                    $paletteindexes[0] = ($secondbyte & 0xF0) >> 4;
644
                                    $paletteindexes[1] = ($secondbyte & 0x0F);
645
                                    for ($i = 0; $i < $firstbyte; $i++) {
646
                                        $col                              = $pixelcounter % $thisfile_bmp_header_raw['width'];
647
                                        $row                              = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']);
648
                                        $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindexes[$i % 2]];
649
                                        $pixelcounter++;
650
                                    }
651
                                }
652
                            }
653
                            break;
654
655
                        default:
656
                            $ThisFileInfo['error'][] = 'Unknown bits-per-pixel value (' . $thisfile_bmp_header_raw['bits_per_pixel'] . ') - cannot read pixel data';
657
                            break;
658
                    }
659
                    break;
660
661
                case 3: // BI_BITFIELDS
662
                    switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
663
                        case 16:
664
                        case 32:
665
                            $redshift   = 0;
666
                            $greenshift = 0;
667
                            $blueshift  = 0;
668
                            if (!$thisfile_bmp_header_raw['red_mask'] || !$thisfile_bmp_header_raw['green_mask']
669
                                || !$thisfile_bmp_header_raw['blue_mask']) {
670
                                $ThisFileInfo['error'][] = 'missing $thisfile_bmp_header_raw[(red|green|blue)_mask]';
671
672
                                return false;
673
                            }
674
                            while (0 == (($thisfile_bmp_header_raw['red_mask'] >> $redshift) & 0x01)) {
675
                                $redshift++;
676
                            }
677
                            while (0 == (($thisfile_bmp_header_raw['green_mask'] >> $greenshift) & 0x01)) {
678
                                $greenshift++;
679
                            }
680
                            while (0 == (($thisfile_bmp_header_raw['blue_mask'] >> $blueshift) & 0x01)) {
681
                                $blueshift++;
682
                            }
683
                            for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
684
                                for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
685
                                    $pixelvalue      = $this->LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset, $thisfile_bmp_header_raw['bits_per_pixel'] / 8));
686
                                    $pixeldataoffset += $thisfile_bmp_header_raw['bits_per_pixel'] / 8;
687
688
                                    $red                              = (int)round(((($pixelvalue & $thisfile_bmp_header_raw['red_mask']) >> $redshift) / ($thisfile_bmp_header_raw['red_mask'] >> $redshift)) * 255);
689
                                    $green                            = (int)round(((($pixelvalue & $thisfile_bmp_header_raw['green_mask']) >> $greenshift) / ($thisfile_bmp_header_raw['green_mask'] >> $greenshift)) * 255);
690
                                    $blue                             = (int)round(((($pixelvalue & $thisfile_bmp_header_raw['blue_mask']) >> $blueshift) / ($thisfile_bmp_header_raw['blue_mask'] >> $blueshift)) * 255);
691
                                    $thisfile_bmp['data'][$row][$col] = (($red << 16) | ($green << 8) | $blue);
692
                                }
693
                                while (0 != ($pixeldataoffset % 4)) {
694
                                    // lines are padded to nearest DWORD
695
                                    $pixeldataoffset++;
696
                                }
697
                            }
698
                            break;
699
700
                        default:
701
                            $ThisFileInfo['error'][] = 'Unknown bits-per-pixel value (' . $thisfile_bmp_header_raw['bits_per_pixel'] . ') - cannot read pixel data';
702
                            break;
703
                    }
704
                    break;
705
706
                default: // unhandled compression type
707
                    $ThisFileInfo['error'][] = 'Unknown/unhandled compression type value (' . $thisfile_bmp_header_raw['compression'] . ') - cannot decompress pixel data';
708
                    break;
709
            }
710
        }
711
712
        return true;
713
    }
714
715
    /**
716
     * @param $color
717
     * @return array
718
     */
719
    public function IntColor2RGB($color)
720
    {
721
        $red   = ($color & 0x00FF0000) >> 16;
722
        $green = ($color & 0x0000FF00) >> 8;
723
        $blue  = ($color & 0x000000FF);
724
725
        return [$red, $green, $blue];
726
    }
727
728
    /**
729
     * @param      $BMPdata
730
     * @param bool $truecolor
731
     * @return bool|resource
732
     */
733
    public function PlotPixelsGD(&$BMPdata, $truecolor = true)
734
    {
735
        $imagewidth  = $BMPdata['header']['raw']['width'];
736
        $imageheight = $BMPdata['header']['raw']['height'];
737
738
        if ($truecolor) {
739
            $gd = @imagecreatetruecolor($imagewidth, $imageheight);
740
        } else {
741
            $gd = @imagecreate($imagewidth, $imageheight);
742
            if (!empty($BMPdata['palette'])) {
743
                // create GD palette from BMP palette
744
                foreach ($BMPdata['palette'] as $dummy => $color) {
745
                    list($r, $g, $b) = $this->IntColor2RGB($color);
746
                    imagecolorallocate($gd, $r, $g, $b);
747
                }
748
            } else {
749
                // create 216-color websafe palette
750
                for ($r = 0x00; $r <= 0xFF; $r += 0x33) {
751
                    for ($g = 0x00; $g <= 0xFF; $g += 0x33) {
752
                        for ($b = 0x00; $b <= 0xFF; $b += 0x33) {
753
                            imagecolorallocate($gd, $r, $g, $b);
754
                        }
755
                    }
756
                }
757
            }
758
        }
759
        if (!is_resource($gd)) {
760
            return false;
761
        }
762
763
        foreach ($BMPdata['data'] as $row => $colarray) {
764
            if (!phpthumb_functions::FunctionIsDisabled('set_time_limit')) {
765
                set_time_limit(30);
766
            }
767
            foreach ($colarray as $col => $color) {
768
                list($red, $green, $blue) = $this->IntColor2RGB($color);
769
                if ($truecolor) {
770
                    $pixelcolor = imagecolorallocate($gd, $red, $green, $blue);
771
                } else {
772
                    $pixelcolor = imagecolorclosest($gd, $red, $green, $blue);
773
                }
774
                imagesetpixel($gd, $col, $row, $pixelcolor);
775
            }
776
        }
777
778
        return $gd;
779
    }
780
781
    /**
782
     * @param $BMPinfo
783
     * @return bool
784
     */
785
    public function PlotBMP(&$BMPinfo)
786
    {
787
        $starttime = time();
788
        if (!isset($BMPinfo['bmp']['data']) || !is_array($BMPinfo['bmp']['data'])) {
789
            echo 'ERROR: no pixel data<BR>';
790
791
            return false;
792
        }
793
        if (!phpthumb_functions::FunctionIsDisabled('set_time_limit')) {
794
            set_time_limit((int)round($BMPinfo['resolution_x'] * $BMPinfo['resolution_y'] / 10000));
795
        }
796
        $im = $this->PlotPixelsGD($BMPinfo['bmp']);
797
        if (headers_sent()) {
798
            echo 'plotted ' . ($BMPinfo['resolution_x'] * $BMPinfo['resolution_y']) . ' pixels in ' . (time() - $starttime) . ' seconds<BR>';
799
            imagedestroy($im);
0 ignored issues
show
Bug introduced by
It seems like $im can also be of type false; however, parameter $image of imagedestroy() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

799
            imagedestroy(/** @scrutinizer ignore-type */ $im);
Loading history...
800
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
801
        }
802
        header('Content-Type: image/png');
803
        imagepng($im);
0 ignored issues
show
Bug introduced by
It seems like $im can also be of type false; however, parameter $image of imagepng() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

803
        imagepng(/** @scrutinizer ignore-type */ $im);
Loading history...
804
        imagedestroy($im);
805
806
        return true;
807
    }
808
809
    /**
810
     * @param $compressionid
811
     * @return mixed|string
812
     */
813
    public function BMPcompressionWindowsLookup($compressionid)
814
    {
815
        static $BMPcompressionWindowsLookup = [
816
            0 => 'BI_RGB',
817
            1 => 'BI_RLE8',
818
            2 => 'BI_RLE4',
819
            3 => 'BI_BITFIELDS',
820
            4 => 'BI_JPEG',
821
            5 => 'BI_PNG'
822
        ];
823
824
        return (isset($BMPcompressionWindowsLookup[$compressionid]) ? $BMPcompressionWindowsLookup[$compressionid] : 'invalid');
825
    }
826
827
    /**
828
     * @param $compressionid
829
     * @return mixed|string
830
     */
831
    public function BMPcompressionOS2Lookup($compressionid)
832
    {
833
        static $BMPcompressionOS2Lookup = [
834
            0 => 'BI_RGB',
835
            1 => 'BI_RLE8',
836
            2 => 'BI_RLE4',
837
            3 => 'Huffman 1D',
838
            4 => 'BI_RLE24',
839
        ];
840
841
        return (isset($BMPcompressionOS2Lookup[$compressionid]) ? $BMPcompressionOS2Lookup[$compressionid] : 'invalid');
842
    }
843
844
    // from getid3.lib.php
845
846
    /**
847
     * @param $floatnumber
848
     * @return float|int
849
     */
850
    public function trunc($floatnumber)
851
    {
852
        // truncates a floating-point number at the decimal point
853
        // returns int (if possible, otherwise float)
854
        if ($floatnumber >= 1) {
855
            $truncatednumber = floor($floatnumber);
856
        } elseif ($floatnumber <= -1) {
857
            $truncatednumber = ceil($floatnumber);
858
        } else {
859
            $truncatednumber = 0;
860
        }
861
        if ($truncatednumber <= 1073741824) { // 2^30
862
            $truncatednumber = (int)$truncatednumber;
863
        }
864
865
        return $truncatednumber;
866
    }
867
868
    /**
869
     * @param $byteword
870
     * @return float|int
871
     */
872
    public function LittleEndian2Int($byteword)
873
    {
874
        $intvalue    = 0;
875
        $byteword    = strrev($byteword);
876
        $bytewordlen = strlen($byteword);
877
        for ($i = 0; $i < $bytewordlen; $i++) {
878
            $intvalue += ord($byteword{$i}) * (256 ** ($bytewordlen - 1 - $i));
879
        }
880
881
        return $intvalue;
882
    }
883
884
    /**
885
     * @param $byteword
886
     * @return float|int
887
     */
888
    public function BigEndian2Int($byteword)
889
    {
890
        return $this->LittleEndian2Int(strrev($byteword));
891
    }
892
893
    /**
894
     * @param $byteword
895
     * @return string
896
     */
897
    public function BigEndian2Bin($byteword)
898
    {
899
        $binvalue    = '';
900
        $bytewordlen = strlen($byteword);
901
        for ($i = 0; $i < $bytewordlen; $i++) {
902
            $binvalue .= str_pad(decbin(ord($byteword{$i})), 8, '0', STR_PAD_LEFT);
903
        }
904
905
        return $binvalue;
906
    }
907
908
    /**
909
     * @param $rawdata
910
     * @return float|int
911
     */
912
    public function FixedPoint2_30($rawdata)
913
    {
914
        $binarystring = $this->BigEndian2Bin($rawdata);
915
916
        return $this->Bin2Dec(substr($binarystring, 0, 2)) + ($this->Bin2Dec(substr($binarystring, 2, 30)) / 1073741824);
917
    }
918
919
    /**
920
     * @param      $binstring
921
     * @param bool $signed
922
     * @return float|int
923
     */
924
    public function Bin2Dec($binstring, $signed = false)
925
    {
926
        $signmult = 1;
927
        if ($signed) {
928
            if ('1' == $binstring{0}) {
929
                $signmult = -1;
930
            }
931
            $binstring = substr($binstring, 1);
932
        }
933
        $decvalue = 0;
934
        for ($i = 0; $i < strlen($binstring); $i++) {
935
            $decvalue += ((int)substr($binstring, strlen($binstring) - $i - 1, 1)) * (2 ** $i);
936
        }
937
938
        return $this->CastAsInt($decvalue * $signmult);
939
    }
940
941
    /**
942
     * @param $floatnum
943
     * @return float|int
944
     */
945
    public function CastAsInt($floatnum)
946
    {
947
        // convert to float if not already
948
        $floatnum = (float)$floatnum;
949
950
        // convert a float to type int, only if possible
951
        if ($this->trunc($floatnum) == $floatnum) {
952
            // it's not floating point
953
            if ($floatnum <= 1073741824) { // 2^30
954
                // it's within int range
955
                $floatnum = (int)$floatnum;
956
            }
957
        }
958
959
        return $floatnum;
960
    }
961
}
962