【问题标题】:Navigation/Scrolling in between the bmp Image in C在 C 中的 bmp 图像之间导航/滚动
【发布时间】:2019-01-15 05:44:19
【问题描述】:

我已经能够按照以下属性读取图像的 Bmp 标题。

图像位深:1 图片属性:1

我想在黑白图像(位深 1)之间滚动/导航。无需关闭并重新打开它(bmp 图像)。

1) 就像 input == f 或 F 一样,像素数据一个接一个地前进 Y0,Y1,Y2,Y3,Y4,....Yn

2) 就像输入 == r 或 R 一样,像素数据一个接一个地向后方向 Y123,Y122,Y121,Y120,Y119,......Y0

3) 另外我不想从开始 (On Every Read) 读取像素。 我想在两者之间阅读(仅限垂直)。 下面是我的代码。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct BitMap {
    short     Type;
    long      Size;
    short     Reserve1;
    short     Reserve2;
    long      OffBits;
    long      biSize;
    long      biWidth;
    long      biHeight;
    short     biPlanes;
    short    biBitCount;
    long      biCompression;
    long      biSizeImage;
    long      biXPelsPerMeter;
    long      biYPelsPerMeter;
    long      biClrUsed;
    long      biClrImportant; } Header;

unsigned char DummyValueRead ; unsigned char pixelValue =0 ;

int Horizontal= 0 ,Vertical = 0 ;

long  myPalette[2]; long  HeaderBytes;

unsigned char bPadding ;  long wBytesPerRow ;  unsigned char
bAdditionalBitsPerRow ;  FILE  *BMPFile;  void SendPixelValues();
unsigned char input ;

int main( void ) {
    BMPFile = fopen ("mul.bmp", "r");
    if (BMPFile == NULL)
    {
        printf("Image Not Found !!!!!!");
        return -1;
    }

    fread(&Header.Type,                                    sizeof(Header.Type), 1, BMPFile);
    fread(&Header.Size,                                       sizeof(Header.Size), 1, BMPFile);
    fread(&Header.Reserve1,                           sizeof(Header.Reserve1) , 1, BMPFile);
    fread(&Header.Reserve2,                           sizeof(Header.Reserve2) , 1, BMPFile);
    fread(&Header.OffBits,                                sizeof(Header.OffBits), 1, BMPFile);
    fread(&Header.biSize,                                  sizeof(Header.biSize), 1, BMPFile);
    fread(&Header.biWidth,                             sizeof(Header.biWidth), 1, BMPFile);
    fread(&Header.biHeight,                            sizeof(Header.biHeight) , 1, BMPFile);

    fread(&Header.biPlanes,                           sizeof(Header.biClrUsed),  1, BMPFile);
    fread(&Header.biBitCount,                      sizeof(Header.biBitCount), 1, BMPFile);
    fread(&Header.biCompression,              sizeof(Header.biCompression), 1, BMPFile);
    fread(&Header.biSizeImage,                    sizeof(Header.biSizeImage), 1, BMPFile);
    fread(&Header.biXPelsPerMeter,         sizeof(Header.biXPelsPerMeter), 1, BMPFile);
    fread(&Header.biYPelsPerMeter,         sizeof(Header.biYPelsPerMeter), 1, BMPFile);

    fread(&Header.biClrUsed,                        sizeof(Header.biClrUsed), 1, BMPFile);
    fread(&Header.biClrImportant,             sizeof(Header.biClrImportant),  1, BMPFile);

    fseek(BMPFile,Header.OffBits,SEEK_SET) ;

    printf("\nType:%hd   and Type in  %x\n", Header.Type,Header.Type);
    printf("Size:%ld\n", Header.Size);
    printf("Reserve1:%hd\n", Header.Reserve1);
    printf("Reserve2:%hd\n", Header.Reserve2);
    printf("OffBits:%ld\n", Header.OffBits);
    printf("biSize:%ld\n", Header.biSize);
    printf("Width:                         %ld\n", Header.biWidth);
    printf("Height:                         %ld\n", Header.biHeight);
    printf("biPlanes:%hd\n", Header.biPlanes);
    printf("biBitCount:%hd\n", Header.biBitCount);
    printf("biCompression:%ld\n", Header.biCompression);
    printf("biSizeImage:%ld\n", Header.biSizeImage);
    printf("biXPelsPerMeter:%ld\n", Header.biXPelsPerMeter);
    printf("biYPelsPerMeter:%ld\n", Header.biYPelsPerMeter);
    printf("biClrUsed:%ld\n", Header.biClrUsed);
    printf("biClrImportant:%ld\n\n", Header.biClrImportant);

    wBytesPerRow =Header.biWidth/8;
    bAdditionalBitsPerRow = Header.biWidth    %    8;
    bPadding = (4 - ((wBytesPerRow + (bAdditionalBitsPerRow?1:0)   ) % 4  )   )    %4;
    HeaderBytes = Header.biWidth/8  ;

    for(Vertical = 0 ;    Vertical <  Header.biHeight ;  Vertical ++)
    {
        printf("Sr. No. %d  \n",Vertical) ;
        scanf("%c",&input) ;
        if(input =='r' || input =='R' )          // Reverse Direction
        {
            //   fseek(BMPFile,((4*968) + 3), SEEK_SET );
            SendPixelValues() ;
        }
        if(input =='f' || input =='F' )          // Forward Direction
            SendPixelValues() ;
        printf("\n")  ;

    }
    fclose(BMPFile);

    return 0;
}

unsigned int bAdditionalBitsPerRowCount =
        0,bPaddingCount=0; void SendPixelValues() {

    for(Horizontal = 0 ; Horizontal <  HeaderBytes ;  Horizontal++)
    {
        fread(&pixelValue, sizeof(pixelValue), 1, BMPFile);
        printf("0x%x  ",pixelValue)  ;
    }
    if(bAdditionalBitsPerRow > 0)
    {
        fread(&DummyValueRead , sizeof(DummyValueRead ), 1, BMPFile);
        bAdditionalBitsPerRow++;
        printf("bAdditionalBitsPerRowCount %d",bAdditionalBitsPerRowCount);
    }
    for(Horizontal = 0 ;   Horizontal <  bPadding;  Horizontal++)
    {
        fread(&DummyValueRead , sizeof(DummyValueRead ), 1, BMPFile);
        bPaddingCount++;
    }
    printf("bPaddingCount = %d",bPaddingCount) ;
}

谢谢 卡兰

【问题讨论】:

  • 请在代码中不带前导 &gt; 的情况下重新移植。
  • 代码引用中的&gt; 破坏了您的minimal reproducible example。请删除它们。
  • 为什么你不一次阅读整个标题fread(&amp;Header, sizeof Header, 1, BMPFile);
  • @i486 我还需要图像的宽度和高度。如何在图像之间导航?
  • 您的文件头错误,您正在跳过颜色表,这是 1 位位图的问题。如果您不知道自己在做什么,也很难在 1 位位图中偏移 x/y 值。我建议使用图片库。

标签: c printf


【解决方案1】:

1 位位图格式的调色板有 8 个字节,您必须在读取像素之前读取这 8 个字节。

一个字节包含 8 个像素。您必须分开这些位并相应地写入它们。位图可以有宽度填充,你必须计算输入文件和输出文件的填充。

确保以二进制格式读取/写入文件(这在 Windows 中很重要)。

例子:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#pragma pack(push, 1)
struct BITMAPFILEHEADER {
    short bfType;
    int bfSize;
    short bfReserved1;
    short bfReserved2;
    int bfOffBits;
};

struct BITMAPINFOHEADER {
    int biSize;
    int biWidth;
    int biHeight;
    short biPlanes;
    short biBitCount;
    int biCompression;
    int biSizeImage;
    int biXPelsPerMeter;
    int biYPelsPerMeter;
    int biClrUsed;
    int biClrImportant;
};
#pragma pack(pop)

int main(void) 
{
    //set X and Y offset:
    int x0 = 10;
    int y0 = 10;

    if(sizeof(short) != 2 ||
        sizeof(int) != 4 ||
        sizeof(struct BITMAPFILEHEADER) != 14 ||
        sizeof(struct BITMAPINFOHEADER) != 40)
    {
        printf("Error, wrong structure size...");
        return -1;
    }

    FILE *fin = fopen("mul.bmp", "rb");
    FILE *fout = fopen("output.bmp", "wb");
    if(fin == NULL)
    {
        printf("Image Not Found !!!!!!");
        return -1;
    }

    struct BITMAPFILEHEADER header;
    struct BITMAPINFOHEADER info;

    fread(&header, sizeof(header), 1, fin);
    fread(&info, sizeof(info), 1, fin);

    if (info.biBitCount != 1)
    {
        printf("Error, not 1-bit bitmap\n");
        return -1;
    }

    int old_width = info.biWidth;
    int old_height = info.biHeight;
    int bitcount = info.biBitCount;
    int width_in_bytes = ((old_width * bitcount + 31) / 32) * 4;
    char palette[8];
    fread(palette, 1, sizeof(palette), fin);

    int new_width = old_width - x0;
    int new_height = old_height - y0;

    //convert to 24-bit bitmap for output file
    info.biBitCount = 24;
    info.biWidth = new_width;
    info.biHeight = new_height;
    info.biSizeImage = ((info.biHeight * bitcount + 31) / 32) * info.biWidth;
    header.bfSize = 54 + info.biSizeImage;
    header.bfOffBits = 54;

    fwrite(&header, 1, sizeof(header), fout);
    fwrite(&info, 1, sizeof(info), fout);

    char *bytes_read = malloc(width_in_bytes);
    char black[3] = { 0 };
    char white[3] = { 255,255,255 };
    for(int y = 0; y < old_height; y++)
    {
        fread(bytes_read, 1, width_in_bytes, fin);

        int width_index = 0;
        for(int i = 0; i < width_in_bytes; i++)
        {
            //8 pixels are packed in to 1 byte
            //separate the bits, write them as bytes in 24-bit format
            for(int j = 0; j < 8; j++)
            {
                width_index = i * 8 + j;
                if(width_index < x0) continue;
                if(width_index - x0 >= new_width) break;

                int pixel = (bytes_read[i] & (1 << (8 - j)));

                if(pixel)
                    fwrite(white, 1, 3, fout);
                else
                    fwrite(black, 1, 3, fout);
            }
        }

        //add padding to output file
        int m = width_index % 4;
        if(m)
            fwrite(black, 1, m, fout);
    }

    fclose(fin);
    fclose(fout);

    return 0;
}

【讨论】:

  • 感谢更新..@Barmak Shemirani 我真的需要调色板吗?有问题的代码对我很有用。另外我不想重绘图像(如您发布的示例)。可能需要重绘调色板。我只想使用 SendPixelValues() 中的像素数据和此代码中所需的修改,我必须将像素数据滚动为相关图像。像素数据一个接一个 前进方向 Y0,Y1,Y2,Y3,Y4,....Yn 像素数据一个接一个 后向 Y123,Y122,Y121,Y120,Y119, ......Y0 怎么做我为此计算偏移量。?谢谢卡兰请更新..
  • 我不明白你的评论。 1 位图像有一个 8 字节长的调色板。我展示了如何使用x0y0 设置偏移量,以及如何读取所有像素。
猜你喜欢
  • 2020-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-08
  • 2020-10-13
  • 2021-06-05
  • 2014-12-26
  • 1970-01-01
相关资源
最近更新 更多