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

Error: The object is not defined (evaluating '_$$_REQUIRE(_dependencyMap[32], "react-native-safe-area-context").SafeAreaView')

I am currently working on developing a chat application using react-native with the following dependencies: "dependencies": { "@react-native-async-storage/async-storage": "~1.17.3", "@react-native-community/masked ...

TypeScript encountered an error with code TS2554, indicating that it was expecting 0 arguments but instead received 1 in an Ionic application

Hello everyone! I'm encountering an issue in my project involving a Type Script error TS2554: Expected 0 arguments, but got 1. This error is preventing me from being able to select other options for custom input pop up. In this forum post, I have shar ...

Sorting through items within a container object

I am currently working with an object named 'docs' that contains multiple objects within it. I am attempting to determine the count of entries that have specific values for both 'exopp_rooms_id_c' and 'is_active'. While this m ...

Typescript: Declaring object properties with interfaces

Looking for a solution to create the childTitle property in fooDetail interface by combining two properties from fooParent interface. export interface fooParent { appId: string, appName: string } export interface fooDetail { childTitle: fooParent. ...

Different Angular 2 components are resolved by routes

Consider this scenario: Upon navigating to the URL /product/123, the goal is to display the ProductComponent. This is how it's currently configured: RouterModule.forRoot([ { path: 'product/:productId', ...

Common Errors in Angular 2 due to TSLint

I am encountering multiple errors in my code. I am using Angular 2 with TSLint: constructor(http: Http) { this.http = http; --> let currentUser = JSON.parse(localStorage.getItem("currentUser")); this.token = currentUser && currentUser.t ...

Integrate a service component into another service component by utilizing module exports

After diving into the nestjs docs and exploring hierarchical injection, I found myself struggling to properly implement it within my project. Currently, I have two crucial modules at play. AuthModule is responsible for importing the UserModule, which conta ...

fade transitions for website images using jQuery

I'm a beginner in the world of jQuery and I am searching for a simple script that can smoothly transition between 3 or 4 background images within a header. The catch is, these images are transparent PNGs, so many standard sliders do not work for this ...

Transforming Geo-Tiff to ECW format?

Is there a library available, either open-source or paid, that allows the conversion of GeoTiff imagery to ECW imagery? The ideal component would take a GeoTiff file as input and generate a corresponding ECW image as output. It should have native support ...

Slim API receives a request from Ionic 5

Seeking assistance with making a GET request from my Ionic application to an API constructed using the Slim Framework. Below is the code snippet of the API: <?php header('Access-Control-Allow-Origin: *'); header('Content-Type: applicati ...

When utilizing Google Analytics in conjunction with Next.Js, encountering the error message "window.gtag is not

Encountering an error on page load with the message: window.gtag is not a function Using Next.js version 14.0.4. All existing solutions seem to hinder data collection, preventing the website from setting cookie consent correctly. I am uncertain about the ...

Angular 12 web version displays error message: "404 not found" for the requested URL

I recently completed my first website using Angular and uploaded it to the server successfully. When browsing through the pages, everything seems fine. However, I encountered an issue when trying to access specific URLs by copying and pasting them into the ...

The information retrieved from the API is not appearing as expected within the Angular 9 ABP framework

I am facing an issue with populating data in my select control, which is located in the header child component. The data comes from an API, but for some reason, it is not displaying correctly. https://i.stack.imgur.com/6JMzn.png. ngOnInit() { thi ...

"Experience the power of utilizing TypeScript with the seamless compatibility provided by the

I'm attempting to utilize jsymal.safeDump(somedata). So far, I've executed npm install --save-dev @types/js-yaml I've also configured my tsconfig file as: { "compilerOptions": { "types": [ "cypress" ...

Bind the change event of an Angular input to a variable that contains a custom function

Is there a way to achieve something similar to the following? <input (input)="doSomething($event)" /> <input (input)="boolVar = $event.target.value > 5" /> I would like to accomplish it by defining a function, like this: funcVar = (e) =&g ...

Update Observable by assigning it a new value of transformed information using the async pipe and RXJS

My service always returns data in the form of Observable<T>, and unfortunately, I am unable to modify this service. I have a button that triggers a method call to the service whenever it is clicked. This action results in a new Observable being retu ...

The Jasmine test is having trouble locating the imported variable

In my Angular project, I have a class set up as follows: import { USERS } from "./data/users"; // imports an Array of Objects export class User { constructor(name: string) { const user = USERS.find(e => e.name === name); } ... } Every ...

What is the best way to convert one array of types to another array of types in Typescript?

Imagine you have the following: type AwesomeTuple = [string, number, boolean] Now, you're looking to transform that type using a generic approach: type AmazingGeneric<T extends any[]> = ... In this scenario: AmazingGeneric<AwesomeType> w ...

How can you retrieve the keys of an object that conforms to an interface?

In the following demonstration, we have two objects - KEYS and KEYS2. When importing KEYS in index.ts, autocomplete suggestions are available for K1 and K2 because KEYS does not adhere to an interface. On the other hand, with KEYS2, autocomplete is not pr ...

Bars of varying heights (Google Chart)

I have incorporated a Google chart within a mat-grid-tile. In this setup, one column displays a value of 50, while the other showcases a value of 30. These particular values are sourced from myService and are accurate. Although when I hover over the bars i ...