Lập trình như tự đá vào mặt mình, sớm hay muộn mũi bạn cũng sẽ chảy máu. Jim McCarthy
STDIO Với sự bùng nổ Internet như hiện nay, việc phát tán các phần mềm, băng đĩa lậu hay các ảnh, video có bản quyền không có xa lạ gì nữa. Người sử dụng máy vi tính dần dần cũng mất đi sự tôn trọng đối với các sản phẩm có bản quyền. Đánh dấu bản quyền thấy được là phương pháp đánh dấu của nhà xuất bản mà người sử dụng có thể dễ dàng thấy được (bằng mắt) hoặc nghe được (bằng tai).
Nội dung bài viết

Giới thiệu

Với sự bùng nổ Internet như hiện nay, việc phát tán các phần mềm, băng đĩa lậu hay các ảnh, video có bản quyền không có xa lạ gì nữa. Người sử dụng máy vi tính dần dần cũng mất đi sự tôn trọng đối với các sản phẩm có bản quyền. Đứng về phía nhà phát triển, thật sự rất khó để có thể ngăn chặn tình trạng trên diễn ra. Bởi vậy, chứng minh một sản phẩm có phải là sản phẩm do mình tạo ra hay không là một giải pháp để hạn chế người dùng phát tán sản phẩm có bản quyền. Trong bài viết này, tôi sẽ hướng dẫn các bạn một trong những phương pháp để đánh dấu bản quyền và kiểm tra xem file ảnh có phải là file do mình đánh dấu hay không. Do bài viết chỉ mang tính minh họa nên tôi chỉ thao tác trên file ảnh có định dạng TGA. Phương pháp này vẫn có thể áp dụng cho các loại định dạng ảnh và audio, video khác.

Tiền đề bài viết

Bài viết được tạo ra nhằm:

  • Kích thích những thành viên của STDIO chia sẻ kiến thức của mình thông qua các bài viết.
  • Nâng cao kiến thức cho các thành viên của STDIO.
  • Thúc đẩy các thành viên STDIO hoạt động trở lại sau Tết Nguyên Đán 2015.

Đối tượng hướng đến

Bài viết này dành cho tất cả các thành viên STDIO và những người muốn tìm hiểu về các phương pháp đánh dấu và kiểm tra bản quyền trên dữ liệu số.

Các phương pháp đánh dấu bản quyền trên file ảnh

Ngày nay, nhìn chung có 2 cách đánh dấu bản quyền trên các file ảnh phổ biến: đánh dấu thấy được và đánh dấu không thấy được.

Đánh dấu bản quyền thấy được

Đánh dấu bản quyền thấy được là phương pháp đánh dấu của nhà xuất bản mà người sử dụng có thể dễ dàng thấy được (bằng mắt) hoặc nghe được (bằng tai). Đối với hình ảnh, bản quyền thường được đánh dấu bằng một dòng chữ ghi tên nhà sản xuất hoặc logo của nhà sản xuất.

ss_1

Như các bạn thấy ở 1 bản in bài viết của STDIO, nó gửi một thông điệp cho những người thấy nó: "Tài liệu này thuộc sở hữu bởi STDIO và Tuấn Trần :: www.stdio.vn/users/index/95/tuan-tran là tác giả" (xem bản in đầy đủ của tài liệu trên theo đường dẫn http://www.stdio.vn/articles/printing/126-ham-tao-mac-dinh-trong-lap-trinh-huong-doi-tuong).

Đánh dấu bản quyền không thấy được

Cách đánh dấu như trên “dường như” quá “lộ”. Mọi người đều có thể thấy, sửa, xóa chúng. Những nhà xuất bản có yêu cầu cao hơn sẽ đòi hỏi làm thế nào để che giấu thông tin của nhà xuất bản. Phương pháp này gọi là đánh dấu bản quyền không thấy được. Phần còn lại của bài viết, tôi sẽ hướng dẫn các bạn phương pháp đánh dấu và kiểm tra bản quyền không thấy được trên các file ảnh có định dạng TGA.

Đề xuất ý tưởng

Với yêu cầu như trên, ý tưởng của tôi là làm thế nào để thêm thông tin (của nhà xuất bản) vào file ảnh mà không làm thay đổi chất lượng cũng như nội dung của file ảnh đó. Điều này sẽ làm cho người xem file ảnh không thể phân biệt được đâu là file ảnh đã được đánh dấu và đâu là file ảnh không được đánh dấu.

Đối với file ảnh TGA, hiện nay có 2 phiên bản được dùng: TGA v1.0 và TGA v2.0. Đối với TGA v1.0, file gồm 2 phần: header và nội dung ảnh. Thay đổi bất kỳ thông tin nào trong file ảnh sẽ làm biến đổi nội dung được hiển thị của ảnh. Đối với TGA v2.0, định dạng mới này cho phép nhà xuất bản có thể chèn bất kỳ thông tin gì vào khu vực có tên Developer Area. Tôi sẽ dùng khu vực này để đánh dấu bản quyền cho những ảnh của mình. Để tìm hiểu thông tin chi tiết về định dạng TGA, các bạn có thể xem tại mục Tham khảo.

Hiện thực

Đánh dấu bản quyền

Định dạng TGA hỗ trợ nhiều dạng ảnh khác nhau như grayscale, RGB, RGBA nén hoặc không nén. Vì bài viết chỉ mang tính minh họa, tôi chỉ hiện thực việc đánh dấu bản quyền trên ảnh RGB và RGBA không nén.

Phương pháp hiện thực của tôi là ghi nội dung của file ảnh cũ vào file ảnh mới (file ảnh có chứa thông tin bản quyền) sau đó ghi thêm thông tin bản quyền và các thông tin kèm theo để phù hợp với định dạng TGA v2.0.

Đọc nội dung của file ảnh cũ (bao gồm header và thông tin ảnh):

fread(&imageWidth, sizeof(short), 1, f);
fread(&imageHeight, sizeof(short), 1, f);
fread(&bitsPerPixel, sizeof(char), 1, f);

int bytesPerPixel = bitsPerPixel/8;
int imageDataSize = imageWidth*imageHeight*bytesPerPixel;
int imageSize = HEADER_SIZE + imageDataSize;

char *imageData = new char[imageSize];
fseek(f, 0, SEEK_SET);
fread(imageData, imageSize, 1, f);

Ghi nội dung của file ảnh cũ vào ảnh mới và thêm thông tin nhà xuất bản:

fwrite(imageData, imageSize, 1, signedFilePtr);
fwrite(STDIO_DEVELOPER_AREA, sizeof(STDIO_DEVELOPER_AREA), 1, signedFilePtr);
writeLEInt(signedFilePtr, 0);           // extension area's offset
writeLEInt(signedFilePtr, imageSize);   // developer area's offset
const char *SIGN = "TRUEVISION-XFILE.";
fwrite(SIGN, 18, 1, signedFilePtr);     // TGA v2.0 signature

Developer Area của tôi gồm 3 thông tin:

  • STDIO Signature: là chuỗi STDIO tôi dùng để nhận biết Developer Area này là do STDIO đánh dấu.
  • Data Length: kích thước vùng dữ liệu chứa thông tin bản quyền.
  • Data: thông tin bản quyền (trong bài viết này, thong tin bản quyền đơn giản chỉ là chuỗi [email protected]).

Vì các số trong định dạng TGA đều được biểu diễn ở dạng little-endian (Tham khảo Little Endian Và Big Endian :: www.stdio.vn//articles/read/10-little-endian-va-big-endian) nên khi ghi số xuống file ta cần phải lưu ý vị trí của các byte trong số đó. Phần hiện thực của tôi như sau:

void writeLEInt(FILE* f, int x)
{
    char buf[4];
    buf[3] = ((x) & 0xFF000000) >> 24;
    buf[2] = ((x) & 0x00FF0000) >> 16;
    buf[1] = ((x) & 0x0000FF00) >> 8;
    buf[0] = ((x) & 0x000000FF);
    fwrite(buf, 4, 1, f);
}

Kiểm tra bản quyền

Phần kiểm tra bản quyền của tôi đơn giản chỉ là kiểm tra xem các điều kiện sau có thỏa mãn hay không:

  • Phiên bản ảnh sử dụng có phải là TGA v2.0 hay không.
  • Developer Area có phải do STDIO thêm vào hay không.
  • Thông tin bản quyền có phải là [email protected] hay không.

Mã nguồn của toàn bộ bài viết

Đánh dấu bản quyền

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

#define OFFSET_IMG_WIDTH    12
#define HEADER_SIZE         18

static const char STDIO_DEVELOPER_AREA[] = 
{
    "STDIO"                 // signature
    "\x13\x00\x00\x00"      // data length
    "[email protected]"    // data
};

void writeLEInt(FILE* f, int x)
{
    char buf[4];
    buf[3] = ((x) & 0xFF000000) >> 24;
    buf[2] = ((x) & 0x00FF0000) >> 16;
    buf[1] = ((x) & 0x0000FF00) >> 8;
    buf[0] = ((x) & 0x000000FF);
    fwrite(buf, 4, 1, f);
}

int main(int argc, char **argv)
{
    if(argc < 2)
    {
        printf("%s <image>\n", argv[0]);
        return -1;
    }

    /* Read image */
    FILE *f = fopen(argv[1], "rb");

    if(f == NULL)
    {
        printf("Can't open img_logo.tga to read\n");
        return -1;
    }

    fseek(f, OFFSET_IMG_WIDTH, SEEK_SET);

    short imageWidth, imageHeight;
    char bitsPerPixel;

    fread(&imageWidth, sizeof(short), 1, f);
    fread(&imageHeight, sizeof(short), 1, f);
    fread(&bitsPerPixel, sizeof(char), 1, f);

    int bytesPerPixel = bitsPerPixel/8;
    int imageDataSize = imageWidth*imageHeight*bytesPerPixel;
    int imageSize = HEADER_SIZE + imageDataSize;

    char *imageData = new char[imageSize];
    fseek(f, 0, SEEK_SET);
    fread(imageData, imageSize, 1, f);
    fclose(f);

    printf("Image Size: (%d, %d)\n", imageWidth, imageHeight);
    printf("Bits per pixel: %d\n", bitsPerPixel);
    printf("Image Size: %d\n", imageSize);

    /* Write image data + image footer to signed image */
    char outputFilename[256];
    sprintf(outputFilename, "signed_%s", argv[1]);
    FILE *signedFilePtr = fopen(outputFilename, "wb");
    if(signedFilePtr == NULL)
    {
        printf("Can't open signed_img_logo.tga to write\n");
        return -1;
    }

    fwrite(imageData, imageSize, 1, signedFilePtr);
    fwrite(STDIO_DEVELOPER_AREA, sizeof(STDIO_DEVELOPER_AREA), 1, signedFilePtr);
    writeLEInt(signedFilePtr, 0);           // extension area's offset
    writeLEInt(signedFilePtr, imageSize);   // developer area's offset
    const char *SIGN = "TRUEVISION-XFILE.";
    fwrite(SIGN, 18, 1, signedFilePtr);     // TGA v2.0 signature

    fclose(signedFilePtr);

    printf("-> Created signed_img_logo.tga\n");

    delete[] imageData; // release buffer to prevent leaking memory

    return 0;
}

Kiểm tra bản quyền

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

#define TGAFOOTER_SIZE	26

unsigned int readLEInt(FILE* f)
{
	char buf[4];
    fread(buf, 4, 1, f);

    return (
    	((buf[0] << 0)	& 0xff) + \
    	((buf[1] << 8) 	& 0xff00) + \
    	((buf[2] << 16) & 0xff0000) + \
    	((buf[3] << 24) & 0xff000000));
}

int main(int argc, char **argv)
{
    if(argc < 2)
    {
        printf("%s <image>\n", argv[0]);
        return -1;
    }

	/* Read signed image */
	FILE *signedFilePtr = fopen(argv[1], "rb");
    if(signedFilePtr == NULL)
    {
        return -1;
    }

    // find image size
    fseek(signedFilePtr, 0, SEEK_END);
    long int fileSize = ftell(signedFilePtr);

    // read image footer
    fseek(signedFilePtr, fileSize - TGAFOOTER_SIZE, SEEK_SET);

    unsigned int developerAreaOffset;
    unsigned int extensionOffset;
    char sig[18];

   	extensionOffset = readLEInt(signedFilePtr);
   	developerAreaOffset = readLEInt(signedFilePtr);
   	fread(sig, 18, 1, signedFilePtr);

   	if(strcmp(sig, "TRUEVISION-XFILE.") != 0)
    {
        printf("ERROR: This is not TGA v2.0 image\n");
        return -1;
    }

    printf("Extension area's offset: %d\n", extensionOffset);
    printf("Developer area's offset: %d\n", developerAreaOffset);
    printf("Signature: %s\n", sig);

   	// read developer area
   	// this area includes:
   	// 		1. STDIO signature: "STDIO"
   	//		2. data length
   	//		3. data
   	fseek(signedFilePtr, developerAreaOffset, SEEK_SET);

   	char stdioSig[6] = { 0 };
   	char *developerAreaData;
   	unsigned int dataSize = 0;

   	fread(stdioSig, 5, 1, signedFilePtr); 		// read STDIO signature

    if(strcmp(stdioSig, "STDIO") != 0)
    {
        printf("ERROR: This image isn't signed by STDIO\n");
        return -1;
    }

   	dataSize = readLEInt(signedFilePtr);	// read data length
   	developerAreaData = new char[dataSize];
   	fread(developerAreaData, dataSize, 1, signedFilePtr);	// read data

    if(strcmp(developerAreaData, "[email protected]") != 0)
    {
        printf("ERROR: License is invalid\n");
        return -1;
    }
   	
   	printf("STDIO Signature: %s\n", stdioSig);
   	printf("Data Length: %d\n", dataSize);
   	printf("Data: %s\n", developerAreaData);

    printf("-> This image is copyrighted by STDIO\n");

   	delete[] developerAreaData;

	return 0;
}

Bạn cần hỗ trợ các dự án kết nối không dây?

Quí doanh nghiệp, cá nhân cần hỗ trợ, hợp tác các dự án IoT, kết nối không dây. Vui lòng liên hệ, hoặc gọi trực tiếp 0942.111912.

  • TỪ KHÓA
  • Arduino
  • ESP32
  • ESP8266
  • Wifi
  • Bluetooth
  • Zigbee
  • Raspberry Pi
THẢO LUẬN
ĐÓNG