हाथ में समस्या rasterisation (विकिपीडिया) करने के लिए नीचे फोड़े, और विशेष रूप से scan line conversion (siggraph.org) पर।
siggraph.org लेख कैसे straight lines, circles and ellipses, और convex और concave बहुभुज आकर्षित करने के लिए पर विस्तृत व्याख्या में शामिल है।
हालांकि, यह एक समस्या है जिसे पहले से ही बड़ी संख्या में हल किया जा चुका है।जबकि ओपी निश्चित रूप से आवश्यक प्राइमेटिव (लाइन, इलिप्स, त्रिकोण, बहुभुज) को लागू कर सकता है, वहां एक बहुत ही सरल दृष्टिकोण है।
मेरा सुझाव है कि ओ पी पी 5 के लिए एक सरल NetPBM format पाठक (बाइनरी ग्रेस्केल पिक्समैप) प्रारूप, और netpbm tools (लिनक्स वितरण और BSD वेरिएंट में netpbm
से पैकेज; अन्य प्रणालियों के लिए Netpbm home page देखें) लागू करता है एक आसान करने के लिए किसी भी छवि परिवर्तित करने के लिए पीजीएम (पी 5) फ़ाइल को पढ़ने के लिए, जहां प्रत्येक पिक्सेल ओपी के मैट्रिक्स में एक तत्व से मेल खाता है।
इस तरह, कोई भी उदाहरण का उपयोग कर सकता है वेक्टर ग्राफिक्स का उपयोग करके सिस्टम को आकर्षित करने के लिए इंकस्केप, इसे किसी भी आकार (जैसे पीएनजी छवि के रूप में निर्यात करके) पर रास्टराइज करें, नेटपीबीएम टूल्स (pngtopnm
या anytopnm
का उपयोग करके पीजीएम (पी 5) प्रारूप में कनवर्ट करें, उसके बाद ppmtopgm
), और फ़ाइल पढ़ें। दरअसल, POSIX.1 सिस्टम में (विंडोज़ को छोड़कर बस हर जगह), पीजीएम (पी 5) प्रारूप में किसी भी पिक्समैप छवि को पढ़ने के लिए popen("anytopnm path-to-file | pnmtopng", "r")
(या थोड़ा अधिक जटिल दो -fork()
पाइप समाधान) का उपयोग कर सकते हैं।
वैकल्पिक रूप से, कोई उदाहरण का उपयोग करने पर विचार कर सकता है ImageMagick लाइब्रेरी को किसी भी प्रारूप पिक्समैप छवियों (जेपीईजी, जीआईएफ, पीएनजी इत्यादि) के बारे में पढ़ने के लिए।
व्यक्तिगत रूप से, दोनों एक डेवलपर और उपयोगकर्ता (हालांकि ध्यान दें कि मैं स्पष्ट रूप से एक गैर Windows उपयोगकर्ता हूँ, एक दशक से अधिक में Microsoft उत्पादों का उपयोग नहीं किया) के रूप में, मैं netpbm दृष्टिकोण पसंद करेंगे। कार्यक्रम, mysim
कहें, उदाहरण के लिए उपयोग करेंगे /usr/lib/mysim/read-image
शैल स्क्रिप्ट (या विंडोज़ में प्रोग्राम, शायद मैक; या, यदि परिभाषित किया गया है, तो MYSIM_READ_IMAGE
पर्यावरण चर द्वारा परिभाषित स्क्रिप्ट या प्रोग्राम), कमांड लाइन पर निर्दिष्ट छवि को पढ़ने के लिए, इसे पीजीएम (पी 5) प्रारूप में उत्सर्जित करने के लिए। मुख्य कार्यक्रम केवल सहायक के आउटपुट को पढ़ेगा।
इस तरह, यदि किसी उपयोगकर्ता को इनपुट फ़ाइलों के लिए विशेष हैंडलिंग की आवश्यकता होती है, तो वे मौजूदा स्क्रिप्ट की प्रतिलिपि बना सकते हैं, अपनी आवश्यकताओं के अनुसार इसे संशोधित कर सकते हैं, और कहीं भी अपनी होम निर्देशिका (या वैश्विक रूप से, या यहां तक कि मौजूदा को भी बदल सकते हैं) एक, अगर यह सभी उपयोगकर्ताओं द्वारा वैसे भी उपयोग किया जाता है)।
कार्यक्रम या तो popen()
या fork()
+ execv()
एक कमांड लाइन पैरामीटर के रूप में इनपुट फ़ाइल नाम के साथ, स्क्रिप्ट को निष्पादित करने के लिए उपयोग, और प्रारंभिक मैट्रिक्स के निर्माण के लिए माता-पिता की प्रक्रिया में उत्पादन पढ़ सकते हैं।
मैं कई कारणों से छवि लाइब्रेरी दृष्टिकोण पर इस दृष्टिकोण को प्राथमिकता देता हूं। सबसे पहले, यह अधिक मॉड्यूलर है, जिससे उपयोगकर्ता छवि पढ़ने की प्रक्रिया को ओवरराइड कर सकता है और यदि आवश्यक हो तो उसे कुशल बना सकता है। (मेरे अनुभव में, इस तरह के ओवरराइड की अक्सर आवश्यकता नहीं होती है, लेकिन जब वे होते हैं, तो वे बेहद उपयोगी होते हैं, और निश्चित रूप से इसके लायक होते हैं।) दूसरा, छवि प्रसंस्करण (जो कई मामलों में काफी जटिल है) एक अलग प्रक्रिया में किया जाता है , जिसका मतलब है कि छवि को पूरी तरह से पढ़ा जाने पर छवि को पढ़ने और समझने के लिए आवश्यक सभी स्मृति (कोड और डेटा के लिए) जारी की जाती है। तीसरा, यह दृष्टिकोण Unix philosophy और KISS principle का पालन करता है, जिसमें मजबूत और उपयोगी टूल के विकास के मार्गदर्शन का एक सिद्ध ट्रैक रिकॉर्ड है।
यहाँ एक उदाहरण कार्यक्रम है कि एक द्विआधारी PBM, PGM, या पीपीएम फ़ाइल (netpbm पी 4, पी 5, और पी 6 प्रारूपों, क्रमशः) मानक इनपुट से पढ़ता है, एक मैट्रिक्स संरचना में, 0
साथ मैट्रिक्स भरने है या 1
(छवि से पढ़ने वाले रंग या ग्रेस्केल मानों के आधार पर)। परीक्षण की आसानी के लिए, कार्यक्रम पीजीएम (पी 5) प्रारूप में मानक आउटपुट के लिए मैट्रिक्स आउटपुट करता है।
कार्यक्रम नेटपीबीएम मैनुअल पृष्ठों (PBM (P4), PGM (P5), और PPM (P6) प्रारूपों के क्रमशः क्रमशः प्रारूप विनिर्देश का पालन करता है)।NetPBM formats पर विकिपीडिया लेख वर्तमान में अमान्य टिप्पणियों (शीर्षलेख और डेटा के बीच) के उदाहरण दिखाता है। नेटपीबीएम मैनुअल पेज बताते हैं कि अंतिम हेडर वैल्यू एक सिंगल व्हाइटस्पेस कैरेक्टर के बाद होता है, और कोई टिप्पणी नहीं है। (यदि कोई टिप्पणी अंतिम शीर्षलेख मान का पालन कर सकती है, तो यह जानना असंभव है कि बाइनरी डेटा में #
(बाइनरी 0x23 = 35) कोई टिप्पणी शुरू करता है या वास्तविक डेटा मान है।)
यह स्पष्ट रूप से है सार्वजनिक डोमेन, या समकक्ष, Creative Commons CC0 लाइसेंस के तहत लाइसेंस प्राप्त है। इसका मतलब यह है कि आप वाणिज्यिक परियोजनाओं में भी किसी भी तरह और कहीं भी नीचे दिए गए कोड का उपयोग करने के लिए पूरी तरह से स्वतंत्र हैं, लेकिन इसकी कोई गारंटी नहीं है: यदि यह टूट जाता है, या कुछ तोड़ता है, या आपके बालों को आग लगा देता है, तो आप सभी को रखना टुकड़े और केवल खुद को दोषी ठहराते हैं।
उसने कहा, यह केवल हल्के ढंग से परीक्षण किया गया है, इसलिए यदि आपको इसमें कोई बग मिलती है, तो मुझे टिप्पणियों में बताएं ताकि मैं सत्यापित और ठीक कर सकूं।
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
/* Matrix to read data into */
typedef struct {
int rows;
int cols;
long rowstride;
long colstride;
unsigned char *data; /* data[row*rowstride + col*colstride] */
} matrix;
#define MATRIX_INIT { 0, 0, 0, 0, NULL }
/* NetPBM (binary) formats supported */
#define PNM_PBM 4
#define PNM_PGM 5
#define PNM_PPM 6
/* Error codes from pnm_*() functions */
#define PNM_EOF -1
#define PNM_INVALID -2
#define PNM_OVERFLOW -3
/* This helper function returns the NetPBM file identifier;
PNM_PBM, PNM_PGM, PNM_PPM, or PNM_INVALID if unsupported.
*/
static int pnm_type(FILE *in)
{
/* First character must be 'P'. */
if (getc(in) != 'P')
return PNM_INVALID;
/* Second character determines the type. */
switch (getc(in)) {
case '4': return PNM_PBM;
case '5': return PNM_PGM;
case '6': return PNM_PPM;
default: return PNM_INVALID;
}
}
/* This helper function reads a number from a NetPBM header,
correctly handling comments. Since all numbers in NetPBM
headers are nonnegative, this function returns negative
when an error occurs:
-1: Premature end of input
-2: Value is too large (int overflow)
-3: Invalid input (not a NetPBM format file)
*/
static int pnm_value(FILE *in)
{
int c;
/* Skip leading whitespace and comments. */
c = getc(in);
while (c == '\t' || c == '\n' || c == '\v' ||
c == '\f' || c == '\r' || c == ' ' || c == '#')
if (c == '#') {
while (c != EOF && c != '\n')
c = getc(in);
} else
c = getc(in);
if (c == EOF)
return PNM_EOF;
if (c >= '0' && c <= '9') {
int value = 0;
while (c >= '0' && c <= '9') {
const int oldvalue = value;
value = 10*value + (c - '0');
if ((int)(value/10) != oldvalue)
return PNM_OVERFLOW;
c = getc(in);
}
/* Do not consume the separator. */
if (c != EOF)
ungetc(c, in);
/* Success. */
return value;
}
return PNM_INVALID;
}
/* This helper function consumes the single newline
following the final value in the header.
Returns 0 if success, PNM_INVALID otherwise.
*/
static int pnm_newline(FILE *in)
{
int c;
c = getc(in);
if (c == '\r')
c = getc(in);
if (c == '\n')
return 0;
return PNM_INVALID;
}
static void pnm_matrix_free(matrix *to)
{
if (to) {
free(to->data);
to->rows = 0;
to->cols = 0;
to->rowstride = 0;
to->colstride = 0;
to->data = NULL;
}
}
static int pnm_matrix_init(matrix *to, int rows, int cols)
{
size_t cells, bytes;
if (rows < 1 || cols < 1)
return PNM_INVALID;
cells = (size_t)rows * (size_t)cols;
if ((size_t)(cells/(size_t)rows) != (size_t)cols ||
(size_t)(cells/(size_t)cols) != (size_t)rows)
return PNM_OVERFLOW;
bytes = cells * sizeof to->data[0];
if ((size_t)(bytes/sizeof to->data[0]) != cells)
return PNM_OVERFLOW;
to->data = malloc(bytes);
if (!to->data)
return PNM_OVERFLOW;
to->rows = rows;
to->cols = cols;
/* Default to a row-major data order. */
to->colstride = 1L;
to->rowstride = cols;
return 0;
}
static int pnm_p4_matrix(FILE *in, matrix *to)
{
int rows, cols, result, r, c, byte = 0;
cols = pnm_value(in);
if (cols < 1)
return PNM_INVALID;
rows = pnm_value(in);
if (rows < 1)
return PNM_INVALID;
if (pnm_newline(in))
return PNM_INVALID;
result = pnm_matrix_init(to, rows, cols);
if (result)
return result;
for (r = 0; r < rows; r++) {
const long ri = r * to->rowstride;
for (c = 0; c < cols; c++) {
const long i = ri + c * to->colstride;
switch (c & 7) {
case 0:
byte = getc(in);
if (byte == EOF) {
pnm_matrix_free(to);
return PNM_INVALID;
}
to->data[i] = !!(byte & 128);
break;
case 1:
to->data[i] = !!(byte & 64);
break;
case 2:
to->data[i] = !!(byte & 32);
break;
case 3:
to->data[i] = !!(byte & 16);
break;
case 4:
to->data[i] = !!(byte & 8);
break;
case 5:
to->data[i] = !!(byte & 4);
break;
case 6:
to->data[i] = !!(byte & 2);
break;
case 7:
to->data[i] = !!(byte & 1);
break;
}
}
}
return 0;
}
static int pnm_p5_matrix(FILE *in, matrix *to)
{
int rows, cols, max, r, c, result;
cols = pnm_value(in);
if (cols < 1)
return PNM_INVALID;
rows = pnm_value(in);
if (rows < 1)
return PNM_INVALID;
max = pnm_value(in);
if (max < 1 || max > 65535)
return PNM_INVALID;
if (pnm_newline(in))
return PNM_INVALID;
result = pnm_matrix_init(to, rows, cols);
if (result)
return result;
if (max < 256) {
const int limit = (max + 1)/2;
int val;
for (r = 0; r < rows; r++) {
const long ri = r * to->rowstride;
for (c = 0; c < cols; c++) {
const long i = ri + c * to->colstride;
val = getc(in);
if (val == EOF) {
pnm_matrix_free(to);
return PNM_INVALID;
}
to->data[i] = (val < limit);
}
}
} else {
const int limit = (max + 1)/2;
int val, low;
for (r = 0; r < rows; r++) {
const long ri = r * to->rowstride;
for (c = 0; c < cols; c++) {
const long i = ri + c * to->colstride;
val = getc(in);
low = getc(in);
if (val == EOF || low == EOF) {
pnm_matrix_free(to);
return PNM_INVALID;
}
val = 256*val + low;
to->data[i] = (val < limit);
}
}
}
return 0;
}
static int pnm_p6_matrix(FILE *in, matrix *to)
{
int rows, cols, max, r, c, result;
cols = pnm_value(in);
if (cols < 1)
return PNM_INVALID;
rows = pnm_value(in);
if (rows < 1)
return PNM_INVALID;
max = pnm_value(in);
if (max < 1 || max > 65535)
return PNM_INVALID;
if (pnm_newline(in))
return PNM_INVALID;
result = pnm_matrix_init(to, rows, cols);
if (result)
return result;
if (max < 256) {
const int limit = 128 * max;
int val, rval, gval, bval;
for (r = 0; r < rows; r++) {
const long ri = r * to->rowstride;
for (c = 0; c < cols; c++) {
const long i = ri + c * to->colstride;
rval = getc(in);
gval = getc(in);
bval = getc(in);
if (rval == EOF || gval == EOF || bval == EOF) {
pnm_matrix_free(to);
return PNM_INVALID;
}
val = 54 * rval
+ 183 * gval
+ 19 * bval;
to->data[i] = (val < limit);
}
}
} else {
const int limit = 128 * max;
int val, rhi, rlo, ghi, glo, bhi, blo;
for (r = 0; r < rows; r++) {
const long ri = r * to->rowstride;
for (c = 0; c < cols; c++) {
const long i = ri + c * to->colstride;
rhi = getc(in);
rlo = getc(in);
ghi = getc(in);
glo = getc(in);
bhi = getc(in);
blo = getc(in);
if (rhi == EOF || rlo == EOF ||
ghi == EOF || glo == EOF ||
bhi == EOF || blo == EOF) {
pnm_matrix_free(to);
return PNM_INVALID;
}
val = 54 * (rhi*256 + rlo)
+ 183 * (ghi*256 + glo)
+ 19 * (bhi*256 + blo);
to->data[i] = (val < limit);
}
}
}
return 0;
}
int pnm_matrix(FILE *in, matrix *to)
{
/* If the matrix is specified, initialize it. */
if (to) {
to->rows = 0L;
to->cols = 0L;
to->rowstride = 0L;
to->colstride = 0L;
to->data = NULL;
}
/* Sanity checks on parameters. */
if (!to || !in || ferror(in))
return PNM_INVALID;
switch (pnm_type(in)) {
case PNM_PBM: return pnm_p4_matrix(in, to);
case PNM_PGM: return pnm_p5_matrix(in, to);
case PNM_PPM: return pnm_p6_matrix(in, to);
default: return PNM_INVALID;
}
}
int main(void)
{
int r, c;
matrix m = MATRIX_INIT;
if (pnm_matrix(stdin, &m)) {
fprintf(stderr, "Cannot parse standard input.\n");
return EXIT_FAILURE;
}
fprintf(stderr, "Read %d rows, %d columns, from standard input.\n", m.rows, m.cols);
/* For ease of debugging, we output the matrix as a PGM file. */
printf("P5\n%d %d\n255\n", m.cols, m.rows);
for (r = 0; r < m.rows; r++)
for (c = 0; c < m.cols; c++)
if (m.data[r * m.rowstride + c * m.colstride] == 0)
putchar(255); /* White */
else
putchar(0); /* Black */
return EXIT_SUCCESS;
}
ध्यान दें कि मैं बिट/ग्रेस्केल/रंग रूपांतरण कैसे ओपी मैट्रिक्स का उपयोग करने का इरादा रखता है के संबंध में सही तरीका है कि क्या सत्यापित नहीं किया। (यानी, क्या "सफेद" या हल्के रंगों को मैट्रिक्स में 0
या 1
उत्पन्न करना चाहिए।) यदि आपको इसे पीबीएम छवियों के लिए उलटा करने की आवश्यकता है, तो इसके बजाय !(byte & NUMBER)
का उपयोग करें। यदि आपको इसे पीजीएम या पीपीएम छवियों के लिए उलटा करने की आवश्यकता है, तो इसके बजाय (val >= limit)
का उपयोग करें।
कार्यक्रम वैध सी (यहां तक कि C89 तक) होना चाहिए, और किसी भी आर्किटेक्चर पर संकलित होना चाहिए। विंडोज़ जैसे मूर्ख वास्तुकलाओं पर, आपको "बाइनरी मोड" में मानक इनपुट को खोलना/दोबारा खोलना पड़ सकता है (fopen()
झंडे में शामिल करें), क्योंकि वे अन्यथा इनपुट को उलझ सकते हैं।
लिनक्स पर, मैं संकलित और
gcc -Wall -O2 example.c -o example
./example <inputfile.pbm> result-pbm.pgm
./example <inputfile.pgm> result-pgm.pgm
./example <inputfile.ppm> result-ppm.pgm
वाह यह वास्तव में बहुत अच्छी – frozen
आंतरिक अंक के लिए एक चक्र कार्य करने के लिए लग रहा है अमूर्त आकृतियों के लिए अपने मौजूदा तकनीक का विस्तार एक समारोह, जो यह सत्यापित बनाने यदि पिक्सेल आकार के भीतरी इलाकों में है की आवश्यकता होती है और 1. उदाहरण के लिए करने के लिए यह सेट हो जाएगा, अगर 1 (x-x0)^2 + (y-y0)^2 <त्रिज्या वापस आ जाएगा। इस तरह के एक समारोह के अंदर आप फ़ाइलों से पढ़ने सहित विभिन्न प्रकार की तकनीकों का उपयोग कर सकते हैं। – RIBH