搜索
bottom↓
回复: 0

《DNK210使用指南 -SDK版 V1.0》第二十五章 照片拍摄实验

[复制链接]

出0入234汤圆

发表于 3 小时前 | 显示全部楼层 |阅读模式
2.jpg
1)实验平台:正点原子DNK210开发板
2)购买链接:https://detail.tmall.com/item.htm?id=782801398750
3)全套实验源码+手册+视频下载地址:http://openedv.com/thread-348335-1-1.html
4)正点原子官方B站:https://space.bilibili.com/394620890
5)正点原子手把手教你学DNK210快速入门视频教程:https://www.bilibili.com/video/BV1kD421G7fu
6)正点原子FPGA交流群:132780729
1.png
3.png

第二十五章 照片拍摄实验


       在前面的章节中,已经了解如何使用SDK编程技术获取摄像头输出的图像数据并在LCD上进行显示,本章将通过照片拍摄实验,介绍如何将摄像头输出的图像数据进行图像编码保存到文件系统中。通过本章的学习,读者将学会如何对摄像头输出的图像数据进行BMP编码并实现保存。
       本章分为如下几个小节:
       25.1 BMP编码简介
       25.2 硬件设计
       25.3 程序设计
       25.4 运行验证

       25.1 BMP编码简介
       本章,我们介绍最简单的图片编码方法:BMP图片编码。BMP文件是由文件头、位图信息头、颜色信息和图形数据等四部分组成。我们先来了解下这几个部分。

       1、BMP文件头(14字节):BMP文件头数据结构含有BMP文件的类型、文件大小和位图起始位置等信息。
  1. /* BMP头文件 */
  2. typedef struct
  3. {
  4.     WORD  bfType ;          /* 文件标志.只对'BM',用来识别BMP位图类型 */
  5.     DWORD  bfSize ;          /* 文件大小,占四个字节 */
  6.     WORD  bfReserved1 ;     /* 保留 */
  7.     WORD  bfReserved2 ;     /* 保留 */
  8.     DWORD  bfOffBits ;       /* 从文件开始到位图数据(bitmap data)开始之间的的偏移量 */
  9. }__attribute__((packed))BITMAPFILEHEADER1 ;
复制代码

       2、位图信息头(40字节):BMP位图信息头数据用于说明位图的尺寸等信息。
  1. /* BMP信息头 */
  2. typedef struct
  3. {
  4.     DWORD biSize ;           /* 说明BITMAPINFOHEADER结构所需要的字数。 */
  5.     DWORD  biWidth ;             /* 说明图象的宽度,以象素为单位 */
  6.     DWORD  biHeight ;            /* 说明图象的高度,以象素为单位 */
  7.     WORD  biPlanes ;        /* 为目标设备说明位面数,其值将总是被设为1 */
  8.     WORD  biBitCount ;      /* 说明比特数/象素,其值为1、4、8、16、24、或32 */
  9.     DWORD biCompression ;    /* 说明图象数据压缩的类型。其值可以是下述值之一
  10.                                  * BI_RGB      :没有压缩
  11.                                  * BI_RLE8     :每个象素8比特的RLE压缩编码,压缩格式由2字节组成(重复象素计数和颜色索引)
  12.                                  * BI_RLE4     :每个象素4比特的RLE压缩编码,压缩格式由2字节组成
  13.                                  * BI_BITFIELDS:每个象素的比特由指定的掩码决定
  14.                                  */
  15.     DWORD biSizeImage ;      /* 说明图象的大小,以字节为单位。当用BI_RGB格式时,可设置为0 */
  16.     DWORD  biXPelsPerMeter ;     /* 说明水平分辨率,用象素/米表示 */
  17.     DWORD  biYPelsPerMeter ;     /* 说明垂直分辨率,用象素/米表示 */
  18.     DWORD biClrUsed ;        /* 说明位图实际使用的彩色表中的颜色索引数 */
  19.     DWORD biClrImportant ;   /* 说明对图象显示有重要影响的颜色索引的数目,如果是0,表示都重要 */
  20. }__attribute__((packed))BITMAPINFOHEADER1 ;
复制代码

       3、颜色表:颜色表用于说明位图中的颜色,它有若干个表项,每一个表项是一个RGBQUAD1类型的结构,定义一种颜色。
  1. /* 彩色表  */
  2. typedef struct
  3. {
  4.     BYTE rgbBlue ;           /* 指定蓝色强度 */
  5.     BYTE rgbGreen ;          /* 指定绿色强度 */
  6.     BYTE rgbRed ;            /* 指定红色强度 */
  7.     BYTE rgbReserved ;       /* 保留,设置为0 */
  8. }__attribute__((packed))RGBQUAD1 ;
复制代码
       颜色表中RGBQUAD1结构数据的个数由biBitCount来确定:当biBitCount=1、4、8时,分别有2、16、256个表项;当biBitCount大于8时,没有颜色表项。
       BMP文件头、位图信息头和颜色表组成位图信息(我们将BMP文件头也加进来,方便处理),BITMAPINFO1结构定义如下:
  1. /* 位图信息头 */
  2. typedef struct
  3. {
  4.     BITMAPFILEHEADER1 bmfHeader;
  5.     BITMAPINFOHEADER1 bmiHeader;  
  6.     uint32_t RGB_MASK[3];       /* 调色板用于存放RGB掩码 */
  7.     //RGBQUAD bmiColors[256];
  8. } __attribute__((packed))BITMAPINFO1;
复制代码

       4、位图数据:位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数:
       当biBitCount=1时,8个像素占1个字节;
       当biBitCount=4时,2个像素占1个字节;
       当biBitCount=8时,1个像素占1个字节;
       当biBitCount=16时,1个像素占2个字节;
       当biBitCount=24时,1个像素占3个字节;
       当biBitCount=32时,1个像素占4个字节;
       biBitCount=1 表示位图最多有两种颜色,缺省情况下是黑色和白色,你也可以自己定义这两种颜色。图像信息头装调色板中将有两个调色板项,称为索引0和索引1。图象数据阵列中的每一位表示一个像素。如果一个位是0,显示时就使用索引0的RGB值,如果位是1,则使用索引1的RGB值。
       biBitCount=16 表示位图最多有65536种颜色。每个像素用16位(2个字节)表示。这种格式叫作高彩色,或叫增强型16位色,或64K色。它的情况比较复杂,当biCompression成员的值是BI_RGB时,它没有调色板。16位中,最低的5位表示蓝色分量,中间的5位表示绿色分量,高的5位表示红色分量,一共占用了15位,最高的一位保留,设为0。这种格式也被称作555 16位位图。如果biCompression成员的值是BI_BITFIELDS,那么情况就复杂了,首先是原来调色板的位置被三个DWORD变量占据,称为红、绿、蓝掩码。分别用于描述红、绿、蓝分量在16位中所占的位置。在Windows 95(或98)中,系统可接受两种格式的位域:555和565,在555格式下,红、绿、蓝的掩码分别是:0x7C00、0x03E0、0x001F,而在565格式下,它们则分别为:0xF800、0x07E0、0x001F。你在读取一个像素之后,可以分别用掩码“与”上像素值,从而提取出想要的颜色分量(当然还要再经过适当的左右移操作)。在NT系统中,则没有格式限制,只不过要求掩码之间不能有重叠。(注:这种格式的图像使用起来是比较麻烦的,不过因为它的显示效果接近于真彩,而图像数据又比真彩图像小的多,所以,它更多的被用于游戏软件)。
       biBitCount=32 表示位图最多有4294967296(2的32次方)种颜色。这种位图的结构与16位位图结构非常类似,当biCompression成员的值是BI_RGB时,它也没有调色板,32位中有24位用于存放RGB值,顺序是:最高位—保留,红8位、绿8位、蓝8位。这种格式也被成为888 32位图。如果 biCompression成员的值是BI_BITFIELDS时,原来调色板的位置将被三个DWORD变量占据,成为红、绿、蓝掩码,分别用于描述红、绿、蓝分量在32位中所占的位置。在Windows 95(or 98)中,系统只接受888格式,也就是说三个掩码的值将只能是:0xFF0000、0xFF00、0xFF。而NT系统,只要注意使掩码之间不产生重叠就行。(注:这种图像格式比较规整,因为它是DWORD对齐的,所以在内存中进行图像处理时可进行汇编级的代码优化(简单)。
       通过以上了解,我们对BMP有了一个比较深入的了解,本章,我们采用16位BMP编码(因为我们的LCD就是16位色的,而且16位BMP编码比24位BMP编码更省空间),故我们需要设置biBitCount的值为16,这样得到新的位图信息(BITMAPINFO1)结构体:
  1. /* 位图信息头 */
  2. typedef struct
  3. {
  4.     BITMAPFILEHEADER1 bmfHeader;
  5.     BITMAPINFOHEADER1 bmiHeader;  
  6.     uint32_t RGB_MASK[3];       /* 调色板用于存放RGB掩码 */
  7.     //RGBQUAD bmiColors[256];
  8. } __attribute__((packed))BITMAPINFO1;
复制代码
       其实就是颜色表由3个RGB掩码代替。最后,我们来看看将LCD的显存保存为BMP格式的图片文件的步骤:
       1)创建BMP位图信息,并初始化各个相关信息
       这里,我们要设置BMP图片的分辨率为LCD分辨率、BMP图片的大小(整个BMP文件大小)、BMP的像素位数(16位)和掩码等信息。
       2)创建新BMP文件,写入BMP位图信息
       我们要保存BMP,当然要存放在某个地方(文件),所以需要先创建文件,同时先保存BMP位图信息,之后才开始BMP数据的写入。
       3)保存位图数据。
       这里就比较简单了,只需要将LCD的显示的RGB565数据,依次写入第二步创建的BMP文件即可。注意:摄像头采集时已对相邻的数据调转,所以我们要注意写入顺序和相邻数据调整。
       4)关闭文件。
       使用FATFS,在文件创建之后,必须调用f_close,文件才会真正体现在文件系统里面,否则是不会写入的!这个要特别注意,写完之后,一定要调用f_close。
       BMP编码就介绍到这里。

       25.2 硬件设计

       25.2.1 例程功能
       1. 开发板上电后,LCD模块实时显示摄像头捕获的画面,我们先调整好合适的拍摄角度,然后按下KEY0按键就能进行拍照操作,所拍摄的照片以BMP文件格式保存在SD卡根目录的PHOTO文件夹中。拍摄的照片保存后,系统可继续拍摄下一张照片。

       25.2.2 硬件资源

       1. 摄像头
              SCCB_SDA - IO40
              SCCB_SCL - IO41
              DVP_RESET - IO42
              DVP_VSYNC - IO43
              DVP_PWDN - IO44
              DVP_HREF - IO45
              DVP_XCLK - IO46
              DVP_PCLK - IO47
              D0~D7 - DVP_D0~DVP_D7

       2. LCD
              LCD_RD - IO34
              LCD_BL - IO35
              LCD_CS - IO36
              LCD_RST - IO37
              LCD_RS - IO38
              LCD_WR - IO39
              LCD_D0~LCD_D7 - SPI0_D0~SPI0_D7
              LCD_RST - IO37
              LCD_RS - IO38
              LCD_WR - IO39
              LCD_D0~LCD_D7 - SPI0_D0~SPI0_D7

       25.2.3 原理图
       本章实验内容,需要使用到板载的摄像头接口,在正点原子DNK210开发板上有两处摄像头接口分别为位于正点原子DNK210开发板底板上的ATK-MC2640摄像头模块接口,该接口用于连接正点原子的ATK-MC2640模块,另一个摄像头接口位于正点原子CNK210F核心板,该接口同于直接连接OV2640等摄像头模组,但需要特别注意的是,这两个摄像头接口不能同时使用,否则可能导致硬件损坏。
       正点原子DNK210开发板上的ATK-MC2640摄像头模块接口的连接原理图,如下图所示:

第二十五章 照片拍摄实验5271.png
图25.2.3.1 ATK-MC2640摄像头模块接口原理图

       正点原子CNK210F核心板上的OV2640等摄像头模组接口的连接原理图,如下图所示:

第二十五章 照片拍摄实验5348.png
图25.2.3.2 OV2640等摄像头模组接口原理图

       25.3 程序设计

       25.3.1 BMP驱动代码
       这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。BMP驱动源码包括两个文件:bmp.c和bmp.h。
       bmp.h头文件在25.1小节基本讲过,具体请看源码。下面来看到bmp.c文件里面的bmp编码函数:bmp_encode,该函数代码如下:
  1. /**
  2. * @brief       BMP编码函数
  3. *   @note      将当前LCD屏幕的指定区域截图,存为16位格式的BMP文件 RGB565格式.
  4. *              保存为rgb565则需要掩码,需要利用原来的调色板位置增加掩码.这里我们已经增加了掩码.
  5. *              保存为rgb555格式则需要颜色转换,耗时间比较久,所以保存为565是最快速的办法.
  6. *
  7. * @param       filename    : 包含存储路径的文件名(.bmp)
  8. * @param       x, y        : 起始坐标
  9. * @param       width,height: 区域大小
  10. * @param       acolor      : 附加的alphablend的颜色(这个仅对32位色bmp有效!!!)
  11. * @param       mode        : 保存模式
  12. *   @arg                     0, 仅仅创建新文件的方式编码;
  13. *   @arg                     1, 如果之前存在文件,则覆盖之前的文件.如果没有,则创建新的文件;
  14. * @retval      操作结果
  15. *   @arg       0   , 成功
  16. *   @arg       其他, 错误码
  17. */
  18. uint8_t bmp_encode(uint8_t *filename, uint16_t *image_addr, uint16_t width, uint16_t height, uint8_t mode)
  19. {
  20.     FIL *f_bmp;
  21.     uint32_t bw = 0;
  22.     uint16_t bmpheadsize;   /* bmp头大小 */
  23.     BITMAPINFO1 hbmp;        /* bmp头 */
  24.     uint8_t res = 0;
  25.     uint16_t tx, ty;        /* 图像尺寸 */
  26.     uint32_t *databuf;      /* 数据缓存区地址 */
  27.     uint16_t pixcnt;        /* 像素计数器 */
  28.     uint16_t bi4width;      /* 水平像素字节数 */
  29.     uint32_t *addr = (uint32_t *)image_addr + 320 / 2 * 239; /* 偏移到最后一行开头 */

  30.     if (width == 0 || height == 0)return PIC_WINDOW_ERR;        /* 区域错误 */

  31. #if BMP_USE_MALLOC == 1     /* 使用malloc */
  32.    
  33.     /* 开辟至少bi4width大小的字节的内存区域 ,对320宽的屏,640个字节就够了 */
  34.     databuf = (uint32_t *)iomem_malloc(320);

  35.     if (databuf == NULL)return PIC_MEM_ERR;     /* 内存申请失败. */

  36.     f_bmp = (FIL *)iomem_malloc(sizeof(FIL));   /* 开辟FIL字节的内存区域 */

  37.     if (f_bmp == NULL)      /* 内存申请失败 */
  38.     {
  39.         iomem_free(databuf);
  40.         return PIC_MEM_ERR;
  41.     }

  42. #else
  43.     databuf = (uint16_t *)bmpreadbuf;
  44.     f_bmp = &f_bfile;
  45. #endif

  46.     bmpheadsize = sizeof(hbmp);         /* 得到bmp文件头的大小 */
  47.     memset((uint8_t *)&hbmp, 0, sizeof(hbmp));        /* 置零空申请到的内存 */

  48.     hbmp.bmiHeader.biSize = sizeof(BITMAPINFOHEADER1);   /* 信息头大小 */
  49.     hbmp.bmiHeader.biWidth = width;     /* bmp的宽度 */
  50.     hbmp.bmiHeader.biHeight = height;   /* bmp的高度 */
  51.     hbmp.bmiHeader.biPlanes = 1;        /* 恒为1 */
  52.     hbmp.bmiHeader.biBitCount = 16;     /* bmp为16位色bmp */
  53.     hbmp.bmiHeader.biCompression = BI_BITFIELDS;        /* 每个象素的比特由指定的掩码决定 */
  54.     hbmp.bmiHeader.biSizeImage = hbmp.bmiHeader.biHeight * hbmp.bmiHeader.biWidth * hbmp.bmiHeader.biBitCount / 8;  /* bmp数据区大小 */

  55.     hbmp.bmfHeader.bfType = ((uint16_t)'M' << 8) + 'B'; /* BM格式标志 */
  56.     hbmp.bmfHeader.bfSize = bmpheadsize + hbmp.bmiHeader.biSizeImage; /* 整个bmp的大小 */
  57.     hbmp.bmfHeader.bfOffBits = bmpheadsize; /* 到数据区的偏移 */

  58.     hbmp.RGB_MASK[0] = 0X00F800;        /* 红色掩码 */
  59.     hbmp.RGB_MASK[1] = 0X0007E0;        /* 绿色掩码 */
  60.     hbmp.RGB_MASK[2] = 0X00001F;        /* 蓝色掩码 */

  61.     if (mode == 1)
  62.     {
  63.         res = f_open(f_bmp, (const TCHAR *)filename, FA_READ | FA_WRITE);       /* 尝试打开之前的文件 */
  64.     }
  65.    
  66.     if (mode == 0 || res == 0x04)
  67.     {
  68.         res = f_open(f_bmp, (const TCHAR *)filename, FA_WRITE | FA_CREATE_NEW); /* 模式0,或者尝试打开失败,则创建新文件 */
  69.     }
  70.    
  71.     if ((hbmp.bmiHeader.biWidth * 2) % 4)   /* 水平像素(字节)不为4的倍数 */
  72.     {
  73.         bi4width = ((hbmp.bmiHeader.biWidth * 2) / 4 + 1) * 4;  /* 实际要写入的宽度像素,必须为4的倍数 */
  74.     }
  75.     else
  76.     {
  77.         bi4width = hbmp.bmiHeader.biWidth * 2;  /* 刚好为4的倍数 */
  78.     }

  79.     if (res == FR_OK)   /* 创建成功 */
  80.     {
  81.         res = f_write(f_bmp, (uint8_t *)&hbmp, bmpheadsize, &bw);   /* 写入BMP首部 */

  82.         for (ty = height - 1; hbmp.bmiHeader.biHeight; ty--)
  83.         {
  84.             pixcnt = 0;

  85.             for (tx = 0; tx <= width / 2;tx++)
  86.             {     
  87.                  /* 硬件原因在摄像头采集时已对相邻的数据调转,此处针对本硬件设计 */
  88.                 databuf[pixcnt] = ((addr[tx] & 0x0000FFFF) << 16) | ((addr[tx] & 0xFFFF0000) >> 16);   /* 读取RGB565数据*/      
  89.                 pixcnt++;               
  90.             }

  91.             addr = addr - width / 2;
  92.             hbmp.bmiHeader.biHeight--;
  93.             res = f_write(f_bmp, (uint8_t *)databuf, bi4width, &bw);    /* 写入数据 */
  94.         }
  95.         f_close(f_bmp);
  96.     }

  97. #if BMP_USE_MALLOC == 1     /* 使用malloc */
  98.     iomem_free(databuf);
  99.     iomem_free(f_bmp);
  100. #endif
  101.     return res;
  102. }
复制代码
       该函数类似实现了对LCD屏幕的任意指定区域进行截屏保存,用到的方法就是25.1节我们所介绍的方法,该函数实现了将用于LCD显示的RGB565数据保存为16位BMP格式,存放在指定位置(由filename决定)。注意,代码中的BMP_USE_MALLOC是在bmp.h定义的一个宏,用于设置是否使用malloc,本章我们选择使用malloc。

       25.3.2 main.c代码
       main.c中的代码如下所示:
  1. /**
  2. * @brief       文件名自增(避免覆盖)
  3. *   @note      bmp组合成: 形如 "0:PHOTO/PIC13141.bmp" 的文件名
  4. *              jpg组合成: 形如 "0:PHOTO/PIC13141.jpg" 的文件名
  5. * @param       pname : 有效的文件名
  6. * @param       mode  : 0, 创建.bmp文件;  1, 创建.jpg文件;
  7. * @retval      无
  8. */
  9. void camera_new_pathname(uint8_t *pname, uint8_t mode)
  10. {
  11.     uint8_t res;
  12.     uint16_t index = 0;
  13.     FIL *ftemp;
  14.    
  15.     ftemp = (FIL *)iomem_malloc(sizeof(FIL));   /* 开辟FIL字节的内存区域 */

  16.     if (ftemp == NULL) return;  /* 内存申请失败 */

  17.     while (index < 0XFFFF)
  18.     {
  19.         sprintf((char *)pname, "0:PHOTO/PIC%05d.bmp", index);      
  20.         res = f_open(ftemp, (const TCHAR *)pname, FA_READ); /* 尝试打开这个文件 */

  21.         if (res == FR_NO_FILE) break;   /* 该文件名不存在, 正是我们需要的 */

  22.         index++;
  23.     }
  24.     iomem_free(ftemp);
  25. }

  26. int main(void)
  27. {
  28.     uint8_t key;
  29.     uint8_t *disp;
  30.     FRESULT res;
  31.     FATFS fs;
  32.     uint8_t *pname;         /* 带路径的文件名 */

  33.     sysctl_pll_set_freq(SYSCTL_PLL0, 800000000);
  34.     sysctl_pll_set_freq(SYSCTL_PLL1, 400000000);
  35.     sysctl_pll_set_freq(SYSCTL_PLL2, 45158400);
  36.     sysctl_set_power_mode(SYSCTL_POWER_BANK6, SYSCTL_POWER_V18);
  37.     sysctl_set_power_mode(SYSCTL_POWER_BANK7, SYSCTL_POWER_V18);
  38.     sysctl_set_spi0_dvp_data(1);

  39.     lcd_init();
  40.     lcd_set_direction(DIR_YX_LRUD);
  41.     key_init();
  42.     camera_init(0);
  43.     camera_set_pixformat(PIXFORMAT_RGB565);
  44.     camera_set_framesize(320, 240);

  45.     pname = iomem_malloc(30);             /* 为带路径的文件名分配30个字节的内存 */
  46.     /* Initialize SD card */
  47.     if (sd_init() != 0)
  48.     {
  49.         printf("SD card initialization failed!\n");
  50.         while (1);
  51.     }
  52.     printf("SD card initialization succeed!\n");

  53.     /* Filesystem mount SD card */
  54.     res = f_mount(&fs, _T("0:"), 1);
  55.     if (res != FR_OK)
  56.     {
  57.         printf("SD card mount failed! Error code: %d\n", res);
  58.         while (1);
  59.     }
  60.     printf("SD card mount succeed!\n");

  61.     lcd_draw_string(10, 30, "KEY0:Take BMP ", RED);
  62.     sleep(3);
  63.     while (1)
  64.     {
  65.         key = key_scan(0);                  /* 得到键值 */
  66.         if (camera_snapshot(&disp, NULL) == 0)
  67.         {
  68.             lcd_draw_picture(0, 0, 320, 240, (uint16_t *)disp);
  69.             camera_snapshot_release();
  70.         }
  71.         if (key == KEY0_PRES)
  72.         {
  73.             camera_new_pathname(pname, 0);  /* 得到文件名 */   
  74.             res = bmp_encode(pname,(uint16_t *)disp ,320, 240, 1);
  75.         }
  76.     }
  77. }
复制代码
       camera_new_pathname函数生成用于生成新的带路径的文件名,且不会重复,防止文件互相覆盖。
       main函数完成对各相关硬件的初始化,然后挂载SD卡,完成挂载后LCD显示模块提示通过按下KEY0进行拍照,3秒后进入进入主循环以后,LCD模块实时显示摄像头数据,按下KEY0按键,可以实现BMP拍照(实际上就是将摄像头数据进行BMP编码,通过bmp_encode函数实现);

       25.4 运行验证
       将DNK210开发板连接到电脑主机,通过VSCode将固件烧录到开发板中,可以看到LCD上实时地显示这摄像头采集到的画面,此时若按下KEY0按键,便会将最近一次获取到的摄像头数据保存到SD卡根目录下的PHOTO文件夹中,如下图所示:

第二十五章 照片拍摄实验12414.png
图25.4.1 拍摄到的图像

阿莫论坛20周年了!感谢大家的支持与爱护!!

你熬了10碗粥,别人一桶水倒进去,淘走90碗,剩下10碗给你,你看似没亏,其实你那10碗已经没有之前的裹腹了,人家的一桶水换90碗,继续卖。说白了,通货膨胀就是,你的钱是挣来的,他的钱是印来的,掺和在一起,你的钱就贬值了。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-10-16 18:17

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表