728x90

자바스크립트에서 숫자는 모두 Number 타입으로 Double로 취급된다.

 

비트 연산자 (Bitwise Operator) >>> 사용 시 Unsigned 32-bit Integer로 변환되기 때문에

 

다음과 같이 h를 Unsigned 32-bit Integer로 변환할 수 있다.

 

h >>>= 0;

 

Reference:

http://stackoverflow.com/questions/1908492/unsigned-integer-in-javascript

 

Unsigned Integer in Javascript

I'm working on a page that processes IP address information, but it's choking on the fact that integers are signed. I am using bitwise operators to speed it up, but the 64th bit (signed/unsigned fl...

stackoverflow.com

 

 

하지만 객체를 이용해서 Uint32Arrary 를 쓰는게 더 좋다.

728x90

HEX 파일

일반적으로 아두이노를 사용할 때 소스코드외에 만들어지는 파일에 대해서는 관심이 없다. 사실 관심을 가질 필요가 거의 없다. 다만, 강의자료를 만드는 입장에서 아두이노라는 임베디드 시스템에 프로그램이 들어가는 과정, 그 안에 있는 프로그램을 밖으로 꺼내는 과정등을 설명할 때 아주 잠간이지만 hex 파일이라는 것을 소개하게 된다.

이 글은 hex 파일에 대해 간략한 소개와 함께 아두이노 사용시 만들어지는 hex 파일에 대한 겉핧기식의 정보를 제공한다.

아두이노 HEX 파일 위치

아두이노 IDE 를 실행시킨 후 다음과 같은 간단한 프로그램을 만들어서 컴파일 한 후 만들어지는 hex 파일을 찾도록 한다.

윈도우10 운영체제를 사용하고 있다면 [윈도우]키를 누른다음 %temp% 를 입력하면 폴더가 검색된다. 내 컴퓨터의 경우 C:\Users\event\AppData\Local\Temp 폴더가 나온다.

폴더를 찾아 간 다음 수정한 날짜를 최신으로 설정하면 방금 만든 파일과 폴더가 나온다. 폴더를 찾아서 내부에 보면 아두이노로 만든 파일들이 나온다.

파일 중 확장자가 hex 인 것이 헥사파일이다. 즉 아두이노에 들어갈 이진파일의 내용이다.

HEX 파일 내용 (Format)

hex 파일은 소스파일을 제대로 컴파일 했을때만 만들어진다. 즉, 오류가 발생하거나 아직 컴파일하지 않은 소스파일에 대해서는 hex 파일이 만들어지지 않는다.

hex 파일은 다음과 같은 규칙을 가진다. (LINK)

  1. Start code, one character, an ASCII colon ‘:’.
  2. Byte count, two hex digits (one hex digit pair), indicating the number of bytes (hex digit pairs) in the data field. The maximum byte count is 255 (0xFF). 16 (0x10) and 32 (0x20) are commonly used byte counts.
  3. Address, four hex digits, representing the 16-bit beginning memory address offset of the data. The physical address of the data is computed by adding this offset to a previously established base address, thus allowing memory addressing beyond the 64 kilobyte limit of 16-bit addresses. The base address, which defaults to zero, can be changed by various types of records. Base addresses and address offsets are always expressed as big endian values.
  4. Record type (see record types below), two hex digits, 00 to 05, defining the meaning of the data field.
  5. Data, a sequence of n bytes of data, represented by 2n hex digits. Some records omit this field (n equals zero). The meaning and interpretation of data bytes depends on the application.
  6. Checksum, two hex digits, a computed value that can be used to verify the record has no errors.

위의 소스코드로 만들어진 hex 파일은 다음과 같다.

:100000000C9435000C945D000C945D000C945D0024 :100010000C945D000C945D000C945D000C945D00EC :100020000C945D000C945D000C945D000C945D00DC :100030000C945D000C945D000C945D000C945D00CC :100040000C94C2010C945D000C9432020C940C02CE :100050000C945D000C945D000C945D000C945D00AC :100060000C945D000C945D00000311241FBECFEFC3 :10007000D8E0DEBFCDBF11E0A0E0B1E0EEEAF6E0EF :1000800002C005900D92A631B107D9F721E0A6E193 :10009000B1E001C01D92AC3BB207E1F710E0C5E34F :1000A000D0E004C02197FE010E944F03C433D10762 :1000B000C9F70E9464020C9455030C940000AF929F :1000C000BF92CF92DF92EF92FF920F931F93CF9345 :1000D000DF936C017B018B01040F151FEB015E01A7 :1000E000AE18BF08C017D10759F06991D601ED913C :1000F000FC910190F081E02DC6010995892B79F7DB :10010000C501DF91CF911F910F91FF90EF90DF908C :10011000CF90BF90AF900895FC01538D448D252F53 :1001200030E0842F90E0821B930B541710F0CF9691 :10013000089501970895FC01918D828D981761F0C3 :10014000A28DAE0FBF2FB11D5D968C91928D9F5FDA :100150009F73928F90E008958FEF9FEF0895FC01B9 :10016000918D828D981731F0828DE80FF11D858D6C :1001700090E008958FEF9FEF0895FC01918D228DFF :10018000892F90E0805C9F4F821B91098F73992784 :1001900008958FE191E00E94BD0021E0892B09F4D0 :1001A00020E0822F089580E090E0892B29F00E94C2 :1001B000C90081110C9400000895FC01A48DA80FC2 :1001C000B92FB11DA35ABF4F2C91848D90E0019699 :1001D0008F739927848FA689B7892C93A089B189B9 :1001E0008C91837080648C93938D848D981306C05A :1001F0000288F389E02D80818F7D80830895EF92BE :10020000FF920F931F93CF93DF93EC0181E0888FD0 :100210009B8D8C8D98131AC0E889F989808185FFA0 :1002200015C09FB7F894EE89FF896083E889F98942 :1002300080818370806480839FBF81E090E0DF9144 :10024000CF911F910F91FF90EF900895F62E0B8D97 :1002500010E00F5F1F4F0F731127E02E8C8D8E1152 :100260000CC00FB607FCFACFE889F989808185FFB9 :10027000F5CFCE010E94DD00F1CFEB8DEC0FFD2F0D :10028000F11DE35AFF4FF0829FB7F8940B8FEA8974 :10029000FB8980818062CFCFCF93DF93EC01888D83 :1002A0008823B9F0AA89BB89E889F9898C9185FDF1 :1002B00003C0808186FD0DC00FB607FCF7CF8C917F :1002C00085FFF2CF808185FFEDCFCE010E94DD005A :1002D000E9CFDF91CF9108958F929F92AF92BF9215 :1002E0000F931F93CF93DF93CDB7DEB7A1970FB6D0 :1002F000F894DEBF0FBECDBF19A2423008F44AE029 :100300008E010F5D1F4F842E912CB12CA12CA501C5 :1003100094010E942D03E62FB901CA01EA3044F589 :10032000E05DD801EE938D01232B242B252B79F74B :1003300090E080E0109769F0FD0101900020E9F75E :100340003197AF014A1B5B0BBD018FE191E00E9429 :100350005F00A1960FB6F894DEBF0FBECDBFDF9150 :10036000CF911F910F91BF90AF909F908F90089564 :10037000E95CD7CF42E050E062E171E08FE191E0CB :100380000C945F001F920F920FB60F9211242F93BF :100390003F938F939F93AF93BF9380911B01909155 :1003A0001C01A0911D01B0911E0130911A0123E0A2 :1003B000230F2D3758F50196A11DB11D20931A0169 :1003C00080931B0190931C01A0931D01B0931E010B :1003D0008091160190911701A0911801B091190117 :1003E0000196A11DB11D8093160190931701A09352 :1003F0001801B0931901BF91AF919F918F913F91D7 :100400002F910F900FBE0F901F90189526E8230F85 :100410000296A11DB11DD2CF1F920F920FB60F925F :1004200011242F933F934F935F936F937F938F93F9 :100430009F93AF93BF93EF93FF938FE191E00E945F :10044000DD00FF91EF91BF91AF919F918F917F91CF :100450006F915F914F913F912F910F900FBE0F9031 :100460001F9018951F920F920FB60F9211242F9381 :100470008F939F93EF93FF93E0912F01F0913001C1 :100480008081E0913501F091360182FD1BC09081A1 :10049000809138018F5F8F7320913901821741F06D :1004A000E0913801F0E0E15EFE4F958F80933801D6 :1004B000FF91EF919F918F912F910F900FBE0F9011 :1004C0001F9018958081F4CF789484B5826084BDA4 :1004D00084B5816084BD85B5826085BD85B5816048 :1004E00085BD80916E00816080936E0010928100C6 :1004F0008091810082608093810080918100816081 :100500008093810080918000816080938000809141 :10051000B10084608093B1008091B00081608093CD :10052000B00080917A00846080937A0080917A0094 :10053000826080937A0080917A00816080937A0053 :1005400080917A00806880937A001092C100E091D7 :100550002F01F091300182E08083E0912B01F09136 :100560002C011082E0912D01F0912E018FEC8083FF :1005700010923701E0913301F091340186E08083DD :10058000E0913101F0913201808180618083E091BE :100590003101F0913201808188608083E0913101E6 :1005A000F0913201808180688083E0913101F09187 :1005B000320180818F7D808364E78FE191E00E942A :1005C000FF000E94BA014AE06EED70E080E090E02A :1005D0000E946C010E94BA014AE066E174E080E08A :1005E00090E00E946C010E94BA01C0E0D0E0209728 :1005F000F1F30E94C9008823D1F30E940000F7CFD5 :10060000EFE1F1E01382128288EE93E0A0E0B0E027 :1006100084839583A683B78384E091E0918380836C :1006200085EC90E09587848784EC90E097878687B7 :1006300080EC90E0918B808B81EC90E0938B828BAF :1006400082EC90E0958B848B86EC90E0978B868B88 :10065000118E128E138E148E0895A1E21A2EAA1BEB :10066000BB1BFD010DC0AA1FBB1FEE1FFF1FA21762 :10067000B307E407F50720F0A21BB30BE40BF50B5F :10068000661F771F881F991F1A9469F760957095E8 :10069000809590959B01AC01BD01CF010895EE0FAF :0E06A000FF1F0590F491E02D0994F894FFCF10 :1006AE0000000000FF005F008C004C01BD009B00AD :0606BE00AF000D0A000070 :00000001FF

첫번째 줄에 대해서 해석해보면 다음과 같다. 편의상 의미가 나누어지는 곳을 띄워쓰기로 한다.

: 10 0000 00 0C943500 0C945D00 0C945D00 0C945D00 24

: --> 시작코드 10 --> 바이트수(16진수), 16개(0x10) 0000 --> 시작주소, 4자리(16진수) 00 --> 레코드타입, 00 에서 05 중 하나, data field 의미, 00은 데이터, 01은 파일의 끝 0C943500 0C945D00 0C945D00 0C945D00 --> 데이터 16(=4x4)개 바이트(16진수 2개가 1바이트, 16진수 32개, 2진수 128개), 24 --> 체크섬, 2자리

hex 파일을 notepad++ 등의 에디터에서 열어보면 색상으로 구별지어 보여준다.

v1, v2, v3 값을 1씩 크게 만들어 다시 컴파일한 다음 이전과 새로 만들어진 hex 파일을 비교해보면 다음과 같다.

// 원래 값 char v1 = 't'; int v2 = 222; long v3 = 1046;// 변경된 부분 char v1 = 't'; int v2 = 222; long v3 = 1046;

두개의 hex 파일을 비교해보면 전체 110 라인 중 3개 라인만 다르다. 비교를 위해 notepad++ 의 Compare 플러그인을 사용했으며, 그 부분은 다음과 같다.

:1005B000320180818F7D808364E78FE191E00E942A :1005B000320180818F7D808365E78FE191E00E9429 ..........................#..............-- *******(1) :1005C000FF000E94BA014AE06EED70E080E090E02A :1005C000FF000E94BA014AE06FED70E080E090E029 ..........................#..............-- *******(2) :1005D0000E946C010E94BA014AE066E174E080E08A :1005D0000E946C010E94BA014AE067E174E080E089 ..............................#..........-- *******(3)

# 표시한 부분이 다르다. 다른 이유는 다음과 같다.

OLD NEW OLD NEW ============================== 't' 'u' 0x74 0x75 222 223 0xDE 0xDF 1046 1047 0x416 0x417

‘t’ 의 아스키코드는 0x74 고, ‘u’ 의 아스크코드는 0x75 다. 즉 4와 5가 다르다. (1) 에서 이 부분을 확인할 수 있다. 223 을 16진수로 고치면 0xDE 이고, 224를 16진수로 고치면 0xDF 이다. E와 F가 다르가 나오는 부분이 (2)이다. 마찬가지로 1046 을 16진수로 고치면 0x416 이고 1을 더한 값이 0x417 이다. (3)에서 6과 7이 다르게 나온다.

여기까지 아두이노 코드를 PC 에서 아두이노로 넘길 때 avr-gcc 를 사용해서 만들어지는 hex 파일에 대해 간략히 살펴보았다. 이 내용은 추후에 아두이노안에 들어있는 이진 파일을 받아온 후 어셈블리코드로 재구성할 때 도움이 된다.

사실 최근들어 어셈블리코드는 일반적으로 거의 사용되지 않는다. 사용되지 않는 이유는 첫째 C 컴파일러의 성능이 좋아졌기 때문이다. 불과 몇년전만 하더라도 C로 만들어진 8051 이나 AVR 코드를 신뢰하지 못하는 개발자들이 있었다. 그래서 시간이 걸려도 직접 어셈블러로 코드를 만들곤 했다. 하지만 컴파일러의 성능이 좋아지면서 이제는 C로 만들거나 어셈블러로 개발자가 직접 최적화를 한 것이 큰 차이를 가지지 않게 되었다. 또한 MCU 들의 성능이 과거에 비해 좋아지고 있다. 한 비트의 의미가 예전같지 않게 된 것이다.

아두이노가 대표적이다. 아두이노 우노는 Atmega328 AVR 칩을 사용하고 플래시메모리가 32kB 나 된다. SRAM 2kB, EEPROM 1kB 를 가지고 있다. 2000년대 초반에 8051을 사용할 때 저정도의 메모리는 상상하기 힘든 것이었다. 한참 8051 에 빠져있을때 AT89C51 을 사용해서 기존과 다른 8051 보드를 직접 만들어 사용한 적이 있다. AT89C51 은 4kB 플래시메모리를 가지고 있었고, 그 당시 이정도면 매우 훌륭한 MCU 였다. 아두이노 메가는 Atmega2560 칩을 사용하고, 메모리는 플래시 256kB 를 가지고 있다. Atmega2560 칩은 3D 프린터의 제어기로 일반적으로 사용된다.

728x90

JavaScript typed arrays are array-like objects that provide a mechanism for reading and writing raw binary data in memory buffers. As you may already know, Array objects grow and shrink dynamically and can have any JavaScript value. JavaScript engines perform optimizations so that these arrays are fast.

However, as web applications become more and more powerful, adding features such as audio and video manipulation, access to raw data using WebSockets, and so forth, it has become clear that there are times when it would be helpful for JavaScript code to be able to quickly and easily manipulate raw binary data. This is where typed arrays come in. Each entry in a JavaScript typed array is a raw binary value in one of a number of supported formats, from 8-bit integers to 64-bit floating-point numbers.

However, typed arrays are not to be confused with normal arrays, as calling Array.isArray() on a typed array returns false. Moreover, not all methods available for normal arrays are supported by typed arrays (e.g. push and pop).

Buffers and views: typed array architecture

To achieve maximum flexibility and efficiency, JavaScript typed arrays split the implementation into buffers and views. A buffer (implemented by the ArrayBuffer object) is an object representing a chunk of data; it has no format to speak of and offers no mechanism for accessing its contents. In order to access the memory contained in a buffer, you need to use a view. A view provides a context — that is, a data type, starting offset, and the number of elements — that turns the data into a typed array.

ArrayBuffer

The ArrayBuffer is a data type that is used to represent a generic, fixed-length binary data buffer. You can't directly manipulate the contents of an ArrayBuffer; instead, you create a typed array view or a DataView which represents the buffer in a specific format, and use that to read and write the contents of the buffer.

Typed array views

Typed array views have self-descriptive names and provide views for all the usual numeric types like Int8, Uint32, Float64 and so forth. There is one special typed array view, the Uint8ClampedArray. It clamps the values between 0 and 255. This is useful for Canvas data processing, for example.

TypeValue RangeSize in bytesDescriptionWeb IDL typeEquivalent C type

Int8Array -128 to 127 1 8-bit two's complement signed integer byte int8_t
Uint8Array 0 to 255 1 8-bit unsigned integer octet uint8_t
Uint8ClampedArray 0 to 255 1 8-bit unsigned integer (clamped) octet uint8_t
Int16Array -32768 to 32767 2 16-bit two's complement signed integer short int16_t
Uint16Array 0 to 65535 2 16-bit unsigned integer unsigned short uint16_t
Int32Array -2147483648 to 2147483647 4 32-bit two's complement signed integer long int32_t
Uint32Array 0 to 4294967295 4 32-bit unsigned integer unsigned long uint32_t
Float32Array 1.2×10-38 to 3.4×1038 4 32-bit IEEE floating point number (7 significant digits e.g., 1.123456) unrestricted float float
Float64Array 5.0×10-324 to 1.8×10308 8 64-bit IEEE floating point number (16 significant digits e.g., 1.123...15) unrestricted double double
BigInt64Array -263 to 263-1 8 64-bit two's complement signed integer bigint int64_t (signed long long)
BigUint64Array 0 to 264-1 8 64-bit unsigned integer bigint uint64_t (unsigned long long)

DataView

The DataView is a low-level interface that provides a getter/setter API to read and write arbitrary data to the buffer. This is useful when dealing with different types of data, for example. Typed array views are in the native byte-order (see Endianness) of your platform. With a DataView you are able to control the byte-order. It is big-endian by default and can be set to little-endian in the getter/setter methods.

Web APIs using typed arrays

These are some examples of APIs that make use of typed arrays; there are others, and more are being added all the time.

FileReader.prototype.readAsArrayBuffer()The FileReader.prototype.readAsArrayBuffer() method starts reading the contents of the specified Blob or File.XMLHttpRequest.prototype.send()XMLHttpRequest instances' send() method now supports typed arrays and ArrayBuffer objects as argument.ImageData.dataIs a Uint8ClampedArray representing a one-dimensional array containing the data in the RGBA order, with integer values between 0 and 255 inclusive.

Examples

Using views with buffers

First of all, we will need to create a buffer, here with a fixed length of 16-bytes:

let buffer = new ArrayBuffer(16);

At this point, we have a chunk of memory whose bytes are all pre-initialized to 0. There's not a lot we can do with it, though. We can confirm that it is indeed 16 bytes long, and that's about it:

if (buffer.byteLength === 16) { console.log("Yes, it's 16 bytes."); } else { console.log("Oh no, it's the wrong size!"); }

Before we can really work with this buffer, we need to create a view. Let's create a view that treats the data in the buffer as an array of 32-bit signed integers:

let int32View = new Int32Array(buffer);

Now we can access the fields in the array just like a normal array:

for (let i = 0; i < int32View.length; i++) { int32View[i] = i * 2; }

This fills out the 4 entries in the array (4 entries at 4 bytes each makes 16 total bytes) with the values 0, 2, 4, and 6.

Multiple views on the same data

Things start to get really interesting when you consider that you can create multiple views onto the same data. For example, given the code above, we can continue like this:

let int16View = new Int16Array(buffer); for (let i = 0; i < int16View.length; i++) { console.log('Entry ' + i + ': ' + int16View[i]); }

Here we create a 16-bit integer view that shares the same buffer as the existing 32-bit view and we output all the values in the buffer as 16-bit integers. Now we get the output 0, 0, 2, 0, 4, 0, 6, 0.

You can go a step farther, though. Consider this:

int16View[0] = 32; console.log('Entry 0 in the 32-bit array is now ' + int32View[0]);

The output from this is "Entry 0 in the 32-bit array is now 32".

In other words, the two arrays are indeed simply viewed on the same data buffer, treating it as different formats. You can do this with any view types.

Working with complex data structures

By combining a single buffer with multiple views of different types, starting at different offsets into the buffer, you can interact with data objects containing multiple data types. This lets you, for example, interact with complex data structures from WebGL, data files, or C structures you need to use while using js-ctypes.

Consider this C structure:

struct someStruct { unsigned long id; char username[16]; float amountDue; };

You can access a buffer containing data in this format like this:

let buffer = new ArrayBuffer(24); // ... read the data into the buffer ... let idView = new Uint32Array(buffer, 0, 1); let usernameView = new Uint8Array(buffer, 4, 16); let amountDueView = new Float32Array(buffer, 20, 1);

Then you can access, for example, the amount due with amountDueView[0].

Note: The data structure alignment in a C structure is platform-dependent. Take precautions and considerations for these padding differences.

Conversion to normal arrays

After processing a typed array, it is sometimes useful to convert it back to a normal array in order to benefit from the Array prototype. This can be done using Array.from(), or using the following code where Array.from() is unsupported.

let typedArray = new Uint8Array([1, 2, 3, 4]), normalArray = Array.prototype.slice.call(typedArray); normalArray.length === 4; normalArray.constructor === Array;

Specifications

Specification

ECMAScript (ECMA-262)
The definition of 'TypedArray Objects' in that specification.

Browser compatibility

Update compatibility data on GitHub

DesktopMobileServerChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome for AndroidFirefox for AndroidOpera for AndroidSafari on iOSSamsung InternetNode.jsInt8ArrayInt8Array() constructor

Full support7 Full support12 Full support4 Full support10 Full support11.6 Full support5.1 Full support4 Full support18 Full support4 Full support12 Full support4.2 Full support1.0 Full support0.10
Full support7 Full support12 Full support4 Full support10 Full support11.6 Full support5.1 Full support4 Full support18 Full support4 Full support12 Full support4.2 Full support1.0 Full support0.10

What are we missing?

Legend

Full support Full support

See also

Metadata

Related Topics

  1. JavaScript
  2. Tutorials:
  3. Complete beginners
  4. JavaScript Guide
  5. Intermediate
  6. Advanced
    1. Inheritance and the prototype chain
    2. Strict mode
    3. JavaScript typed arrays
    4. Memory Management
    5. Concurrency model and Event Loop
  7. References:
  8. Built-in objects
  9. Expressions & operators
  10. Statements & declarations
  11. Functions
  12. Classes
  13. Errors
  14. Misc

Learn the best of web development

Get the latest and greatest from MDN delivered straight to your inbox.

E-mail

Sign up now

Hide Newsletter Sign-up

MDN Web Docs

MDN

  •  
  •  

Mozilla

  •  
  •  

© 2005-2020 Mozilla and individual contributors. Content is available under these licenses.

 

728x90

1. 사전 지식

  • Blob

    • 정의
      • Blob 는 일반적으로 미디어(이미지, 사운드, 비디오) 파일과 같은 큰 용량의 파일을 말한다.
    • Blob Object

      • Blob Object 는 File 과 같은 불변 객체를 나타내며, raw data 를 가진다.

        • 추가로 File 인터페이스  Blob 인터페이스 의 모든 특성들을 상속받는다.
    • Blob API in MDN
    • Blob in Terms
    • Blob in Can I Use
  • JavaScript Typed Array

    • 정의

      • Typed Array 는 raw binary data 에 접근하기 위한 방법을 제공한다.

        • 즉 자바스크립트로 binary data 를 다루기 위해 사용한다.
      • 유연성 효율성을 위해 buffer  view 로 나눠 구현되어있다.

        • buffer

          • ArrayBuffer 는 고정된 크기의 raw binary data 를 나타내기 위해 사용된다.
          • ArrayBuffer 클래스 통해 생성된 buffer  데이터 청크를 나타내는 객체이다.

            // 12 bytes buffer 나타낸다 var buffer = new ArrayBuffer(12);

          • buffer  저장된 데이터를 접근하기 위한 방법을 제공하지 않는다.

          • 데이터를 다루기 위해서는 반드시 view 를 사용해야한다.
        • view

          • DataView

            DataView view  buffer 에 저장된 데이터로 부터 값을 읽고, 쓰기 위한 low-level 인터페이스 를 제공한다.(getter/setter API 제공)

            // 12 bytes byffer var buffer = new ArrayBuffer(12); // view 를 생성한다. var view = new DataView(buffer, 2, 2); // 해당 view 가 시작하는 위치를 반환한다. console.log(view.byteOffset); // 2

            데이터를 다루기위한 DataView 의 특성들은 아래와 같다.

          • Typed Array Views

            DataView 를 상속한 아래 클래스들을 통해 buffer 에 저장된 데이터를 다룰 수 있게된다.

            Int8Array, Uint8Array, Int32Array, Uint32Array 등 …

            위 클래스 중 Int32Array 를 통해 생성된 view 는 아래와 같은 특성들을 가지게된다.

            아래 그림은 각 view 에 따라 나눠지는 메모리 공간을 나타낸다.

          • /* ArrayBuffer(20 bytes) 8bit == 1 byte ArrayBuffer / 1 byte = 20; */ var buffer = new ArrayBuffer(20); // 부호 없는 1 byte 정수 배열 var uint8View = new Uint8Array(buffer); console.log(uint8View.length); // 20 /* ArrayBuffer(20 bytes) 32bit == 4 byte ArrayBuffer / 4 byte = 5; */ var buffer = new ArrayBuffer(20); // 부호 없는 4 byte 정수 배열 var uint32View = new Uint32Array(buffer); console.log(uint32View.length); // 5

            unsigned or signed view test

            // unsigned int 8(1 bytes) var buffer = new ArrayBuffer(20); var uint8View = new Uint8Array(buffer); // 0 ~ 255(unsigned int 8(1 bytes) 로 표현 가능한 수) uint8View[0] = 0; uint8View[1] = 255; console.log(uint8View); // [0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] // signed int 8(1 bytes) var buffer = new ArrayBuffer(20); var int8View = new Int8Array(buffer); // -127 ~ 128(signed int 8(1 bytes) 로 표현 가능한 수) // signed 의 경우 부호(양수/음수)를 나타내기 위해 총 8bit 중 1 비트(0: 양수, 1: 음수) 사용하기 때문에, 나머지 7bit(-127 ~ 128(표현 가능한 수))를 통해 숫자를 표현하게 된다. int8View[0] = -128; int8View[1] = 127; console.log(int8View); // [-128, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] // unsigned int 16(2 bytes) var buffer = new ArrayBuffer(20); var uint16View = new Uint16Array(buffer); // 0 ~ 65535(unsigned int 16(2 bytes) 로 표현 가능한 수) uint16View[0] = 65535; console.log(uint16View); // [65535, 0, 0, 0, 0, 0, 0, 0, 0, 0]

      • ArrayBuffer

      • DataView

      • DataView API Test

      • JavaScript Typed Arrays

      • JavaScript Typed Arrays(번역)

      • signed 와 unsigned 의 차이

      • signed 가 음수 표현하는 방법(상세 설명)

      • 나는 unsigned 가 싫어요

      • signed or unsigned 자료형의 범위

      • Binary Convert

  • Little-Endian or Big-Endian

    • 정의

      • Endian 은 컴퓨터에서 데이터가 저장되는 순서(byte order)를 말한다.

      • 정리:

        • 메모리는 하위 주소에서 상위 주소로 데이터가 저장된다.

        • Little Endian: 하위 바이트부터 데이터가 저장되는 방식.

          • Little Endian 방식의 장점: 산술연산유닛(ALU)에서 메모리를 읽는 방식이 메모리 주소가 낮은 쪽에서부터 높은 쪽으로 읽기 때문에 산술 연산의 수행이 더 쉽다.(연산 처리 과정에서 이런 장점이 있는 정도로만 알고 넘어가자…)
        • Big Endian: 상위 바이트부터 데이터가 저장되는 방식.

    • 적용 이유:

      •  **CPU**(Intel / Spac) **타입**에 따라 차이를 보이는 byte order(**데이터 저장 순서**)는, 동일한 시스템 안에서만 데이터를 주고 받는다면, Endian 에 대해 전혀 신경쓸 필요가 없지만, 이기종간에 데이터를 주고 받을 경우, 서로간의 데이터 저장 방식 차이로 인해 전혀 엉뚱한 결과를 반환하게 된다.
    • 서로 다른 Endian 간의 데이터 통신 해결책:

      • 공통되는 Endian(약속된 Endian 규칙)으로 변환 후, 데이타를 주고/받는 방법.

        • 즉 서로간에 사용할 Endian(Little Endian or Big Endian) 을 하나로 통일시켜 데이터를 주고 받는 것이다.
      • 또 하나의 방법은 byte order(바이트 저장 순서) 를 신경쓸 필요가 없는, 데이터 타입을 사용하는 것이다. char 타입은 1byte 의 크기를 가지기때문에, byte order 에 대해 전혀 신경쓸 필요가 없다. 예를 들면 12345678 을 int 형으로 보내는 대신 문자열 “12345678” 로 변환시켜 전송하면 된다.

    • 엔디언

    • Little-Endian or Big-Endian(개념 잡기 좋은 문서)

    • Little-Endian or Big-Endian 개념

    • Endian 에 대해서

2. JavaScript 를 통해 Binary Data 조작하기

  • 예제 소스에서는 NodeJS  Socket.IO 와 관련된 내용은 최대한 배제 하였습니다.(특별히 포스트 내용과 관련 없다고 판단한 내용)

  • 파일 업로드

    • File  FileReader API 를 지원하는 브라우저를 통해 파일 업로드 기능을 만들 수 있다.

      • 하지만 IE(10/11 포함) 브라우저는 지원하지 않는다고 보면된다.

      • Source Example

        • Cliend Side(use JS)

        • 먼저 저장소로 부터 내려받은 파일을 include 한다.

          <script src="siofu_client.js"></script>

          // socket 서버에 연결 var socket = io.connect('http://localhost:9090'); // socket 객체를 SocketIOFileUpload 클래스로 전달한다. var uploader = new SocketIOFileUpload(socket); // listenOnSubmit 메서드에 input[type="button"] 및 input[type="file"] Element 를 전달한다. uploader.listenOnSubmit($('#btn_upload').get(0), $('#siofu_input').get(0)); // KiB === byte 단위 // KB === KByte 단위 // 한번에 로드될 chunks 파일 사이즈 // chunkSize 를 0으로 할당하면, chunk 를 사용하지 않게 된다. uploader.chunkSize = 1024 * 100; // 102400 byte 로 chunk 단위를 나눈다. uploader.addEventListener("start", function(event){ console.log('started upload of file'); }); // progress 이벤트를 통해 현재 진행 상황을 볼 수 있다. uploader.addEventListener("progress", function(event){ var percent = event.bytesLoaded / event.file.size * 100; console.log("File is", percent.toFixed(2), "percent loaded"); }); // 파일 업로드가 끝날을때 이벤트가 발생한다. uploader.addEventListener("complete", function(event){ console.log('completed file upload'); });

        • Server Side(use nodeJS)

        var uploader = new siofu(); uploader.dir = "uploads"; uploader.listen(socket); // Do something when a file is saved: uploader.on("saved", function(event){ console.log(event.file); }); // Error handler: uploader.on("error", function(event){ console.log("Error from uploader", event); });

      • 참고 사이트

        socket io file upload module

        File API

        FileReader API

  • 이미지 효과

    • 서버에서 내려받은 ArrayBuffer(이미지 데이터) 로 view(uInt8Array) 를 생성 후, 버퍼에 저장된 데이터를 조작한다.

    • Source Example

      • Cliend Side(use JS)

        var cw = 327; var ch = 125; // canvas Element 를 가져온다. var canvas = document.querySelector('canvas'); // context 를 생성한다. var ctx = canvas.getContext('2d'); // view(부호 없는 1byte 정수 배열)를 생성한다. var uInt8Array = new Uint8Array(payload.buffer); // view를 통해 Blob Object 를 생성한다. var blob = new Blob([uInt8Array], {type: 'image/jpeg'}); var originalImgData = null; // Blob Object를 참조하는 URL를 생성한다. var url = URL.createObjectURL(blob); var img = new Image; // 이미지 로드 이벤트 $(img).bind('load', function(){ canvas.width = img.width; canvas.height = img.height; // 캔버스에 해당 이미지를 그린다. ctx.drawImage(img, 0, 0, img.width, img.height); // 각 px 에 대한 정보(r,g,b,a)가 담긴 이미지 데이터를 가져온다. originalImgData = ctx.getImageData(0, 0, canvas.width, canvas.height); // 반전 효과를 준다. // invert(); // 흑백 효과를 준다. empty(); }); // Blob 객체를 참조하는 URL을 img.src 에 할당 후 로드한다. img.src = url; // px 단위의 이미지 데이터를 조작하여, 반전 효과를 준다. function invert(){ originalImgData = ctx.getImageData(0, (canvas.height / 2), canvas.width, canvas.height); var data = originalImgData.data; for (var i = 0; i < data.length; i += 4) { data[i] = 255 - data[i]; // red data[i + 1] = 255 - data[i + 1]; // green data[i + 2] = 255 - data[i + 2]; // blue } ctx.putImageData(originalImgData, 0, (canvas.height / 2)); }; // px 단위의 이미지 데이터를 조작하여, 흑백 효과를 준다. function empty(){ originalImgData = ctx.getImageData(0, 0, canvas.width, canvas.height); var data = originalImgData.data; for (var i = 0; i < data.length; i += 4) { // 각 픽셀의 밝기만 조사하여 R, G, B 색상 요소를 균일하게 만들면 회색이 된다.(색상 정보를 아래 공식(각 요소(R, G, B)가 밝기에 미치는 영향은 29:58:11로 전문가에 의해 계산되어 있다)으로 R,G,B 요소에서 제거한다) // 128 이상은 흰색으로, 128 이하는 검정색으로 만들어 버림으로써, 흰색과 검정색 두 가지만 남긴다. 경계값인 128을 조정하면 밝기가 달라진다. var gray = data[i] * 0.299 + data[i + 1] * 0.587 + data[i + 2] * 0.114; if (gray > 128){ gray = 255; } else{ gray = 0; } data[i] = gray; // red data[i + 1] = gray; // green data[i + 2] = gray; // blue } ctx.putImageData(originalImgData, 0, 0); };

      • Server Side(use nodeJS)

        var fs = require('fs'); // 파일을 읽은 후 클라이언트로 버퍼를 전달한다. fs.readFile('./lib/img/nmms_20823487.jpg', function (err, buf) { // it's possible to embed binary data // within arbitrarily-complex objects socket.emit('onSocketMsg', { type: 'resultImageData', payload: { buffer: buf } }); });

    • 적용 결과

      • 원본 이미지

      • invert 함수 적용 이미지

      • empty 함수 적용 이미지

    • 참고 사이트

  • ArrayBuffer 로 내려받은 비디오 플레이

    • 서버에서 내려받은 ArrayBuffer(영상 데이터) 로 view(in Typed Array Views) 를 생성 후, 버퍼에 저장된 데이터를 조작한다.

      • 영상 및 오디오 데이터의 경우, 브라우저 지원 여부  지원 포맷에 대해 반드시 확인해봐야한다.

      • 아래 소스는 Chrome 브라우저에서 *.mp4  *.webm 포맷으로만 테스트되었습니다.

    • Source Example

      • Cliend Side(use JS)

        var vw = 327; var vh = 125; // video Element 를 가져온다. var video = document.querySelector('video'); video.width = vw; video.height = vh; // view(부호 없는 1byte 정수 배열)를 생성한다. var uInt8Array = new Uint8Array(payload.buffer); // view를 통해 Blob Object 를 생성한다. var blob = new Blob([uInt8Array], {type: 'video/webm'}); //var blob = new Blob([uInt8Array], {type: 'video/mp4'}); // Blob Object를 참조하는 URL 를 생성한다. var url = URL.createObjectURL(blob); // Blob 객체를 참조하는 URL을 video.src 에 할당 후 로드한다. video.src = url;

      • Server Side(use nodeJS)

        fs.readFile('redcliff450.webm', function (err, buf) { socket.emit('onSocketMsg', { type: 'resultVideoData', payload: { buffer: buf } }); });

  • Chunk 방식으로 내려받은 비디오 플레이

    • 서버에서 Chunk 방식으로 내려받은 ArrayBuffer(영상 데이터) 로 view(in Typed Array Views) 를 생성 후, 버퍼에 저장된 데이터를 조작한다.

    • MediaSource API 를 통해 내려받은 영상 데이터를 조작할 수 있다.

    • 영상 및 오디오 데이터의 경우, 브라우저 지원 여부  지원 포맷에 대해 반드시 확인해봐야한다.

    • 아래 소스는 Chrome 브라우저에서 *.webm(vorbis 및 vp8 코덱) 포맷으로만 테스트되었습니다.

    • Source Example

      • Cliend Side(use JS)

      • 저장소로 부터 내려받은 파일을 include 한다.

        <script src="socket.io-stream.js"></script>

        // stream 메서드에 socket 객체를 전달 후 해당 이벤트를 바인딩한다. ss(socket).on('onSocketMsg', function(data) { data = data || {}; var type = data.type; var payload = data.payload; if (type === 'resultChunkVideoData') { var vw = 1024; var vh = 768; // video Element 를 가져온다. var video = document.querySelector('video'); video.width = vw; video.height = vh; console.log(payload.stream); // 내려받은 stream 데이터 // MediaSource 객체를 생성한다. var ms = new MediaSource(); // MediaSource 객체를 참조하는 URL 를 생성한다. var url = URL.createObjectURL(ms); // MediaSource 객체를 참조하는 URL을 video.src 에 할당 후 로드한다. video.src = url; // MediaSource 객체에 각 이벤트를 바인딩 시킨다. ms.addEventListener('sourceopen', callback, false); // ms.addEventListener('webkitsourceopen', callback, false); ms.addEventListener('sourceended', function(e) { console.log('mediaSource readyState: ' + this.readyState); }, false); function callback() { // 재생하려는 영상 소스를 추가한다. var sourceBuffer = ms.addSourceBuffer('video/webm; codecs="vp8"'); // var sourceBuffer = ms.addSourceBuffer('video/webm; codecs="vp8,vorbis"'); sourceBuffer.addEventListener('updatestart', function (e) { // console.log('updatestart: ' + ms.readyState); }); sourceBuffer.addEventListener('update', function () { // console.log('update: ' + ms.readyState); }, false); sourceBuffer.addEventListener('updateend', function (e) { console.log('updateend: ' + ms.readyState); }); sourceBuffer.addEventListener('error', function (e) { console.log('error: ' + ms.readyState); }); sourceBuffer.addEventListener('abort', function (e) { console.log('abort: ' + ms.readyState); }); payload.stream.on('data', function (data) { // chunk data console.log(data); // 버퍼에 내려받은 스트림 데이터를 할당한다. sourceBuffer.appendBuffer(data); }); // 데이터 전송이 완료되었을 경우 발생한다. payload.stream.on('end', function () { console.log('endOfStream call'); // 스트림을 종료한다. ms.endOfStream(); }); } } });

      • Server Side(use nodeJS)

        var ss = require('socket.io-stream'); ss(socket).on('onSocketMsg', function(data) { data = data || {}; var type = data.type; var payload = data.payload; var stream = ss.createStream(); if (type === 'downloadChunkVideo') { // webm 포맷의 영상을 가져온다. var filename = path.basename('feelings_vp9-20130806-244.webm'); // 파일 스트림을 생성한다. fs.createReadStream(filename).pipe(stream); ss(socket).emit('onSocketMsg', { type: 'resultChunkVideoData', payload: { stream: stream } }); } });

      • 테스트 결과

    • 참고 사이트

+ Recent posts