2011年12月6日火曜日

( Qt C++ )バイナリの生データの書き込み


今日は10時からのガイアの夜明けでIKEAが出るそうです。私は別にIKEA好きではありませんが、あの物がバーッと整然と美しく並んでいる感じが大好きです。ですから私は大きなホームセンターなんかに行くと心躍ります。
...とはいっても買うものは洗剤とか、しょうもないモノだけですけどね。すでに私の買い物はほとんどamazonでまとめ買いです。(店員さんスイマセン。だって安いんだもの。)

さて、今日は前回の続きバイナリの生データを扱います。今回は書き込みです。
プログラムは前回のものを少し変更して使います。流れとしてはPNGかどうか確認し、
PNGならサイズを改変して取り出すという流れになります。改変するので、必ずどうでもいいPNG画像を使用してください。ではコードを

QSize getPngImageSize( QIODevice *device )
{
    quint32 width = 0;
    quint32 height = 0;
    char signature[8];
    char chunkType[4];
    char custumSize[8] = { 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00};

    QDataStream in( device );
    in.readRawData( signature, 8 );

    if ( memcmp(signature, "\211PNG\r\n\32\n", 8) == 0 ) {
        while ( !in.atEnd() ) {
            device->seek(device->pos() + 4);
            in.readRawData( chunkType, 4 );

            if ( memcmp(chunkType, "IHDR", 4) == 0 ) {
                in.writeRawData(custumSize, 8);//サイズ変更(256×256)
               device->seek(device->pos() - 8);//書込み時に進んでしまうので位置を戻す
                in >> width >> height;
                break;
            }
            // jump to the next chunk
            device->seek(device->pos() + 4);
        }
    }
    return QSize( width, height );
}

宣言部は前回とほぼ同じです。custumSizeのみ追加しています。これに縦横のサイズをいれます。今回は256×256になるようにしています。
その後のin.writeRawDataの位置までは前回と同じです。PNGフォーマットかどうかを確認し、そうならループに突入。"IHDR"の位置に入ったらサイズを変更してから取り出します。in.writeRawDataでサイズ変更しています。一応リファレンスを

int QDataStream::writeRawData ( const char * s, int len )
sをlenバイトを書き込む。書込みが成功すると書き込んだバイト数が返る。エラーなら-1が返る。データはエンコードされない。(リファレンスへ)

です。後の説明は前回と同じなので省きます。
でgetPngImageSizeを使うには

void sample()//上のgetPngImageSizeを使用する関数
{

    QFile file(tr("/home/ubuntu001/io.png"));
    if ( file.open(QIODevice::ReadWrite) )//読み書きモードで開けたかチェック
   {
        QSize size = getPngImageSize( &file );//サイズ取得 
        ui->lineEdit->setText(tr("%1: %L2 x %L3").arg("io.png").arg(size.width()).arg(size.height()));/*size表示*/
    }
    else
    {
        ui->lineEdit->setText("error");//オープン失敗
    }
}

 のようにします。file.open(QIODevice::ReadWrite)のところ以外は前回と同じです。

はい、以上です。次回からはテキストデータの読み書きをやっていきます。