基本的にAndroid

Android初心者の備忘録のようなもの. 公開しているソースコードは主にgccでコンパイルされると想定されています.

フラッシュ 抽出したデータの取扱

後々にフラッシュの解析等も解説したいと思う.

艦これ(艦娘)のフラッシュには, 画像データがJPEGとして入っている場合がある.
フラッシュのJPEGタグについては下記のリンクを見ていただきたい.
Flash SWF format - Jpeg - Yoya Wiki

画像データの後ろにアルファ値, つまり透明色が配置されている.
その透明色のみを画像にすると(ここでは大淀さん)
f:id:calloc:20140825224729j:plain f:id:calloc:20140825224720p:plain
左が抽出したJPEGデータ, 右がアルファ値のみを画像としたデータ.
これをPNGに変換すると,
f:id:calloc:20140825232742p:plain

これがサンプルコード.
手順は
JPEGRGBを取得
・ALPHAの取得
・RGBA配列としてPNGに保存
のような感じです.

ちなみに013.jpg, 013.alphaなどがありますが'013'はswf内のイメージIDです.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <jpeglib.h>
#include <png.h>

#define JPEG_PATH  "./013.jpg"
#define ALPHA_PATH "./013.alpha"

/* src/main.c */
unsigned char **jpeg_src(
    int *width,
    int *height,
    unsigned char **src);

unsigned char **alpha_src(const int width,
    const int height,
    unsigned char **src);

int build_png(
    int width,
    int height,
    unsigned char **alpha,
    unsigned char **src);

int main(int argc, char *argv[])
{
  int i;
  int width = 0;
  int height = 0;
  unsigned char **alpha = NULL;
  unsigned char **jpeg = NULL;

  /* unsigned char **型のjpegデータの取得 */
  jpeg = jpeg_src(&width, &height, jpeg);
  /* unsigned char **型のalphaデータの取得 */
  alpha = alpha_src(width, height, alpha);

  build_png(width, height, alpha, jpeg);

  /* 終了処理 */
  for(i = 0; i < height; i++)
    free(jpeg[i]);
  free(jpeg);

  for(i = 0; i < height; i++)
    free(alpha[i]);
  free(alpha);

  return 0;
}

unsigned char **jpeg_src(
    int *width,
    int *height,
    unsigned char **src)
{
  int i;
  struct jpeg_decompress_struct cinfo;
  struct jpeg_error_mgr jerr;
  FILE *fp;

  if((fp = fopen(JPEG_PATH, "rb")) == NULL) {
    perror(JPEG_PATH);
    return NULL;
  }
  cinfo.err = jpeg_std_error(&jerr);
  jpeg_create_decompress(&cinfo);

  jpeg_stdio_src(&cinfo, fp);
  jpeg_read_header(&cinfo, TRUE);

  jpeg_start_decompress(&cinfo);

  *width = cinfo.output_width;
  *height = cinfo.output_height;

  src = (unsigned char **)calloc(
      *height, sizeof(unsigned char **));
  for(i = 0; i < *height; i++)
    src[i] = (unsigned char *)calloc(
        *width, sizeof(unsigned char *));

  while(cinfo.output_scanline < cinfo.output_height) {
    jpeg_read_scanlines(&cinfo,
        src + cinfo.output_scanline,
        cinfo.output_height - cinfo.output_scanline);
  }

  jpeg_finish_decompress(&cinfo);
  jpeg_destroy_decompress(&cinfo);

  return src;
}

unsigned char **alpha_src(
    const int width,
    const int height,
    unsigned char **src)
{
  int i;
  FILE *fp;
  size_t bytes = 0;

  if((fp = fopen(ALPHA_PATH, "r")) == NULL) {
    perror(ALPHA_PATH);
    return NULL;
  }

  src = (unsigned char **)calloc(height, sizeof(unsigned char **));
  for(i = 0; i < height; i++)
    src[i] = (unsigned char *)calloc(width, sizeof(unsigned char *));

  for(i = 0; i < height; i++) {
    if((bytes = fread(src[i], sizeof(unsigned char), width, fp)) != width) {
      return NULL;
    }

    if(bytes == 0) break;
  }

  fclose(fp);
  return src;
}

int build_png(
    int width,
    int height,
    unsigned char **alpha,
    unsigned char **src)
{
  int i, j;
  FILE *fp;
  png_structp png_ptr;
  png_infop info_ptr;
  unsigned char **data;

  if((fp = fopen("./013.png", "wb")) == NULL) {
    return EOF;
  }

  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
      NULL, NULL, NULL);
  info_ptr = png_create_info_struct(png_ptr);

  png_init_io(png_ptr, fp);

  png_set_IHDR(png_ptr, info_ptr,
      width, height,
      8, PNG_COLOR_TYPE_RGB_ALPHA,
      PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
      PNG_FILTER_TYPE_BASE);

  /* 画像データの変換 */
  data = (unsigned char **)calloc(height, sizeof(unsigned char **));
  for(i = 0; i < height; i++) {
    data[i] = (unsigned char *)calloc(width, sizeof(unsigned char *));

    for(j = 0; j < width; j++) {
      data[i][j * 4 + 0] = src[i][j * 3 + 0]; /* Red   */
      data[i][j * 4 + 1] = src[i][j * 3 + 1]; /* Green */
      data[i][j * 4 + 2] = src[i][j * 3 + 2]; /* Blue  */
      data[i][j * 4 + 3] = alpha[i][j];       /* Alpha */
    }
  }

  /* pngの書き込み */
  png_write_info(png_ptr, info_ptr);
  png_write_image(png_ptr, data);
  png_write_end(png_ptr, info_ptr);

  /* png_ptr等の破棄 */
  png_destroy_write_struct(&png_ptr, &info_ptr);

  /* data領域の解放 */
  for(i = 0; i < height; i++)
    free(data[i]);
  free(data);

  fclose(fp);
  return 1;
}