What is the process for converting BitmapData from Flash into HTML canvas?

Currently facing a significant challenge as I transition from using Flash to JS. The issue lies in handling SOAP returned data, specifically when dealing with images stored as strings that need to be converted into BitmapData for use in Flash. Despite trying various approaches, the best result achieved is a green image with noise on the canvas. Below are snippets of code that may prove helpful:

Flash Code:

        private function encode(bitmap:Bitmap):ByteArray{
            var encoder:JPGEncoder = new JPGEncoder(QUALITY);
            return encoder.encode(bitmap.bitmapData);
        }

        public function decodeBytes(bm:Bitmap):void{
            _bitmap = bm;
            _bytesData = encode(_bitmap);
            var imgConventer:ArrayDataConventer = new ArrayDataConventer();
            imgConventer.addEventListener(ImageConvertCompleteEvent.IMAGE_CONVERT_COMPLETE, convertCompleteHandler);
            imgConventer.decByteArrToHexStr(bytesData);
        }   

The decByteArrToHexStr function returns a string where two hex characters represent a byte. This string is then sent via SOAP and retrieved when needed. Thus concludes the Flash part.

Now, the objective is to convert this string into image data suitable for placement onto a canvas.

I have a method for converting a string to Uint8Array:

  public hexStrToDecByteArr(str: string): Uint8Array {
    const byteArr: Uint8Array = new Uint8Array(str.length / 2);

    for (let i: number = 0; i < str.length; i = i + 2) {
      const n: number = parseInt('0x' + str.substr(i, 2), 0);

      if (!isNaN(n)) {
        byteArr[i] = n;
      }
    }

    return data;
  }

Subsequently, in the response handler, the following steps are performed:

const decodes: ArrayDataConverter = new ArrayDataConverter();
        const data = decodes.hexStrToDecByteArr(downloadedImage.sData);
        const encoder: any = new JPGEncoder(100);
        const encoded = encoder.encode({width: 400, height: 300, data});

        const context = this.canvas.nativeElement.getContext('2d');
        context.clearRect(0, 0, 400, 300);

        const image = new Image();
        image.onload = () => {
          context.drawImage(image, 0, 0);
        };
        image.src = encoded;

The downloadedImage.sData contains a hex string. The JPGEncoder package utilized is a revamped version of the Flash JPGEncoder for JS (https://www.npmjs.com/package/@koba04/jpeg-encoder). Despite efforts, the result obtained remains a green image with some artifacts on the canvas.

Thank you in advance for any assistance provided.

Answer №1

It seems like you are trying to compress raw bitmap data into JPEG format and then load it into an HTML5 canvas?

This approach will not work because the Canvas requires pixel color values, not a JPEG compression algorithm.

Possible solution #1: Utilize AS3 pixel values in the Canvas...

In your AS3 code, avoid encoding into JPEG and instead directly write the pixel values as hex strings (from an array).

public function decodeBytes(bm:Bitmap):void
{
    //# get pixel values into an array named: _bytesData
    bm.bitmapData.copyPixelsToByteArray( bm.bitmapData.rect, _bytesData );
    
    var imgConventer:ArrayDataConventer = new ArrayDataConventer();
    imgConventer.addEventListener(ImageConvertCompleteEvent.IMAGE_CONVERT_COMPLETE, convertCompleteHandler);
    imgConventer.decByteArrToHexStr( _bytesData );
}

Then on the TypeScript (or JavaScript) side, read the received data into an array/buffer.

To display the image in an (HTML5) Canvas, iterate through the array using a for-loop.

var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
var imgData = ctx.createImageData(canvas.width, canvas.height);

//# notice the order is:
//# JS imagedata = R-G-B-A
//# AS3 bitmap   = A-R-G-B

for (var i=0; i < imgData.data.length; i += 4)
{
    imgData.data[i + 0] = downloadedImage.sData[i + 1]; //put RED
    imgData.data[i + 1] = downloadedImage.sData[i + 2]; //put GREEN
    imgData.data[i + 2] = downloadedImage.sData[i + 3]; //put BLUE
    imgData.data[i + 3] = downloadedImage.sData[i + 0]; //put ALPHA
}

//# Update canvas with the image data
ctx.putImageData(imgData, 0, 0);

This should render your image in the Canvas element with the id of myCanvas.

Possible solution #2: Using JPEG data in an array...

If sending raw bitmap data results in a large file, consider utilizing JPEG compression to load the data directly into an <Image> tag similar to loading a file.

Avoid double-encoding JPEG data (once in AS3 and then again in TypeScript) as it may corrupt the image data.

(1) Create the JPEG as done in the original AS3 code and then (2) Verify the first 3 values on the TypeScript or HTML side to ensure they match the expected JPEG header bytes...

downloadedImage.sData[0] //should be: 0xFF (or 255)
downloadedImage.sData[1] //should be: 0xD8 (or 216)
downloadedImage.sData[2] //should be: 0xFF (or 255)

These 3 values confirm the correct beginning bytes of a JPEG header, indicating valid image data.

In the <body> section of your HTML, include an <image> tag awaiting the image data to set its .src attribute...

<body>

<img id="myPic" src="none.jpg" width="600" height="400">

</body>

Next in JavaScript (you can convert this to TypeScript)...

<script>

//# Ensure downloadedImage.sData String resembles "0xFF,0xD8,0xFF" etc. (lowercase 'ff' also works)
var myArr = new Uint8Array([downloadedImage.sData]);

var blob = new Blob([downloadedImage.sData], { type: "image/jpeg" });
var urlCreator = window.URL || window.webkitURL;
var imageUrl = urlCreator.createObjectURL(blob);
var img = document.getElementById("myPic");
img.src = imageUrl;

</script>

This guide aims to assist in achieving a functional outcome.

PS: Here's a complete testable example code snippet (HTML/JS only, without TypeScript)...

<!DOCTYPE html>
<html>
<body>

<img id="myPic" src="none.jpg" width="600" height="400">

</body>

<script>

//# Fill the array properly and completely, the below values are just examples
var myArr = new Uint8Array([0xFF, 0xD8, 0xFF, 0xE0, 0x00 ... 0xFF, 0xD9]);

var blob = new Blob([myArr], { type: "image/jpeg" });
var urlCreator = window.URL || window.webkitURL;
var imageUrl = urlCreator.createObjectURL(blob);
var img = document.getElementById("myPic");
img.src = imageUrl;

</script>

</html>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

I am faced with a challenge involving an asynchronous function and the best approach to executing it synchronously

I devised the following plan: // Primary Function to Follow // Capture necessary local data // Transform into required editable format // Iterate through user's local images // Append image names to converted d ...

Overlap bug with Flash content

In both Google Chrome (16.0.912.75 m) and Safari (5.1.1), I am encountering the well-known flash / html overlay issue. Despite setting the wmode attribute to transparent as suggested here and here, along with trying opaque, the problem persists. Following ...

Trouble with Angular toggle switch in replicated form groups

Currently, I have a form group that contains multiple form controls, including a toggle switch. This switch is responsible for toggling a boolean value in the model between true and false. Depending on this value, an *ngIf statement determines whether cert ...

Issue with Cypress TypeScript: Unable to locate @angular/core module in my React application

I am currently in the process of updating my Cypress version from 9.70 to 10.7.0. Although I have fixed almost all the bugs, I have encountered a strange message stating that @angular/core or its corresponding type declarations cannot be found. My applica ...

How can I retrieve an array from an object containing both a property and an array in TypeScript?

One of my objects always consists of a property and an array. When I use the console.log(obj) method to print it out, it looks like the following example: ProjectName: MyTest1 [0] { foo: 1, bar: 2} [1] { foo: 3, bar: 4} [2] { foo: 5, bar: 6} Alternat ...

Troubles encountered when attempting to upload high-resolution images via ajax

Currently, I am utilizing ajax to send data, which includes an image, to my server-side. Everything works smoothly when the image size is below 1.35MB. However, when the image surpasses this limit, the other data gets overwritten. For example, when trying ...

Bringing in AuthError with TypeScript from Firebase

Is it possible to verify if an error is of type "AuthError" in TypeScript when using Firebase? I have a Https Callable function with a try/catch block that looks like this: try { await admin.auth().getUser(data.uid); // will throw error if user doesn& ...

Is it possible to retrieve a union type property as an array of values in order to conduct a flexible type validation process?

Currently, my code looks something like this: interface Apple { type: 'Apple' } interface Banana { type: 'Banana' } interface Coconut { type: 'Coconut' } type Fruit = Apple | Banana | Coconut type AppleOrBanana = App ...

Angular - Enhance User Experience with Persistent Autocomplete Suggestions Displayed

Is there a way to keep the autocomplete panel constantly enabled without needing to specifically focus on the input field? I attempted to set autofocus on the input, but found it to be clunky and the panel could still disappear if I hit escape. I also ...

The functionality to verify the presence of a child element is not functioning correctly when using

Trying to determine the existence of a child, I have created a new Firebase list observable and also attempted with an object observable. Upon creating the observable, I verify if it exists or not; however, it always returns false. Database Structure: {R ...

Integrate TypeScript into the current project

As a newcomer to Typescript, I am currently exploring the option of integrating it into my current project. In our MVC project, we have a single file that houses the definitions of all model objects. This file is downloaded to the client when the user fir ...

Angular2 Eclipse: Eclipse Oxygen's HTML editor detects TypeScript errors in real-time

After installing the Eclipse Oxygen plugin for Angular2, I created a project using the Angular CLI and opened it in Eclipse. However, when trying to convert the project to an Angular project, I couldn't find the option under configuration. Instead, th ...

Angular 6 issue: Data not found in MatTableDataSource

Working on implementing the MatTableDataSource to utilize the full functionality of the Material Data-Table, but encountering issues. Data is fetched from an API, stored in an object, and then used to create a new MatTableDataSource. However, no data is b ...

Displaying nested web service array data in Angular 4

I created a project that retrieves data from a web service API. However, the API contains nested arrays that also need to be displayed. How can I access the data from these nested JSON arrays? What is the correct way to extract this data within the HTML co ...

Troubleshooting an Angular application in Intellij using Chrome on a Windows operating system

I've been searching for a long time for a way to debug an Angular app in IntelliJ using Chrome on Windows. So far, I have not been successful in attaching a debugger to Chrome. I have tried launching Chrome with --remote-debugging-port=9222 and numer ...

The identifier 'name' is not found in the specified data type

How can I resolve the error 'Property 'name' does not exist on type' in TypeScript? Here is the code block : **Environment.prod.ts** export const environment = { production: true, name:"(Production)", apiUrl: 'https://tes ...

Do changes in Input fields reflect in the parent component?

I was under the impression that I could share data with child components using @Input() directive and communicate data back to the parent component with @Output() along with the appropriate emit. However, I recently discovered that modifications made to th ...

The where clause in the Typeorm query builder instance is not functioning properly after its common usage

When fetching data for my relations, I opted to use QueryBuilder. In order to validate certain get request parameters before the index, I established a common QueryBuilder instance as shown below. // Common Get Query const result = await this.reserva ...

Eliminating the need for RequireJS in the Typescript Visual Studio project template

After integrating RequireJS into my Typescript template using the nuget package manager, I found that it was more than what I needed and decided to uninstall it. Even though I removed the package through nuget and the files were deleted properly, my Typesc ...

Unpacking data types from an array of classes in TypeScript: A step-by-step guide

I am working on a function that takes an array or rest of Typescript classes as input and resolves, returning their instances. However, I'm struggling to ensure correct typing for it. If I take one class as an example: class Base { isBase = true ...