Search…

Đánh Dấu và Kiểm Tra Bản Quyền Tài Liệu Số

21/09/20207 min read
Hướng dẫn 1 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?

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 ảnh, video có bản quyền không có xa lạ gì nữa. Người sử dụng máy 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 1 sản phẩm có phải là sản phẩm do mình tạo ra hay không là 1 giải pháp để hạn chế người dùng phát tán sản phẩm có bản quyền.

Bài viết hướng dẫn 1 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 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.

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

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.
  • Đá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 1 dòng chữ ghi tên nhà sản xuất hoặc logo của nhà sản xuất.

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

Đá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à 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 sẽ hướng dẫ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 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. Có thể dùng khu vực này để đánh dấu bản quyền cho ả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, 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 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 trước khi đánh dấu, 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 vào file ả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

Giả sử Developer Area hiện tại cần lưu 3 thông tin:

  • STDIO Signature: là chuỗi STDIO 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, thông tin bản quyền là chuỗi developer@stdio.vn).

Vì các số trong định dạng TGA đều được biểu diễn ở dạng little endian nên khi ghi số xuống file cần phải lưu ý vị trí của các byte trong số đó. Phần hiện thực 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 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à developer@stdio.vn 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
    "developer@stdio.vn"    // 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, "developer@stdio.vn") != 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;
}
IO Stream

IO Stream Co., Ltd

30 Trinh Dinh Thao, Hoa Thanh ward, Tan Phu district, Ho Chi Minh city, Vietnam
+84 28 22 00 11 12
developer@iostream.co

383/1 Quang Trung, ward 10, Go Vap district, Ho Chi Minh city
Business license number: 0311563559 issued by the Department of Planning and Investment of Ho Chi Minh City on February 23, 2012

©IO Stream, 2013 - 2024