برنامه نویسی

نقاشی به اعداد از تصاویر دیجیتال با React/JavaScript

[NOTE: The live web app that encompasses this functionality can be found here: https://www.paintmap.studio. All of the underlying code for that site can be found here: https://github.com/bytebodger/color-map.]

در مقاله‌های قبلی این مجموعه، به جزئیات گسترده‌ای در مورد موضوعاتی مانند پیکسل‌سازی، تطبیق رنگ، پراکندگی و عمق رنگ پرداختم. اما من می خواستم آن را با نشان دادن اینکه چگونه شخصاً خودم را به پایان برسانم استفاده کنید این ویژگی ها – به طور خاص، به عنوان به نقاشی من مربوط می شود.

توضیحات تصویر

موجودی رنگ

پس از اتمام کار کردن با یک تصویر در Paint Map Studio، به اطلاعاتی در مورد خود تصویر تبدیل شده نیاز دارم. در صفحه اصلی، تمام خروجی ها به صورت تصویر رندر شده است. اما در برخی مواقع باید ببینم که چگونه آن تصویر به رنگ ها تبدیل می شود.

هنگامی که تصویر به پایان رسید، دو پیوند جدید در ناوبری بالا ظاهر می شوند. یکی «مپ» است. دیگری “آمار” است. ابتدا به آمار نگاه می کنیم.

STATS فهرستی از تمام رنگ هایی که در تصویر مطابقت داشته اند را به ترتیب نزولی نشان می دهد. پر استفاده ترین رنگ ها در قسمت بالایی قرار دارند. کمتر استفاده شده در پایین است.

و در اینجا مولفه Stats به نظر می رسد:

// Stats.js

export const Stats = () => {
   const uiState = useContext(UIState);
   const navigateTo = useNavigate();
   const allColors = useAllColors();
   let colors = [];

   const getColorCell = (paintName = '') => {
      const color = uiState.stats.colors.find(color => color.name === paintName);
      return <TableCell style={{backgroundColor: `rgb(${color.red}, ${color.green}, ${color.blue})`}}/>;
   }

   const getTableRows = () => {
      colors = allColors.get();
      const colorCounts = sortColorCounts(uiState.stats);
      return colorCounts.map((colorCount, index) => {
         const [paintName, count] = colorCount;
         const paintIndex = colors.findIndex(color => color.name === paintName);
         return (
            <TableRow
               key={paintName}
               sx={{'&:last-child td, &:last-child th': {border: 0}}}
            >
               <TableCell style={{textAlign: css3.textAlign.center}}><b>{index + 1}.</b></TableCell>
               <TableCell style={{textAlign: css3.textAlign.center}}>{paintIndex}</TableCell>
               <TableCell style={{textAlign: css3.textAlign.center}}>{count}</TableCell>
               {getColorCell(paintName)}
               <TableCell>
                  <span
                     className={'paintName'}
                     id={paintName}
                     onClick={handlePaintNameClick}
                  >
                     {paintName}
                  </span>
               </TableCell>
            </TableRow>
         );
      })
   }

   const handlePaintNameClick = (event = {}) => {
      uiState.toggleHighlightedColor(event.target.id);
      navigateTo('/map');
   }

   const sortColorCounts = (stats = {}) => {
      const sort = (a, b) => {
         const [, aCount] = a;
         const [, bCount] = b;
         if (aCount > bCount)
            return -1;
         else if (aCount < bCount)
            return 1;
         else
            return 0;
      };

      const colorCounts = [];
      Object.entries(stats.colorCounts).forEach(colorCount => colorCounts.push(colorCount));
      return colorCounts.sort(sort);
   };

   const navigateToMap = () => navigateTo('/map');

   if (Object.keys(uiState.stats).length === 0)
      return null;

   return <>
      <h4 className={'marginBottom_8'}>Color Stats</h4>
      <div className={'marginBottom_48'}>
         <Typography>
            These are all the colors represented in your generated image.  To see where these colors exist in the image,
            click on the{` `}
            <span
               className={'spanLink'}
               onClick={navigateToMap}
            >
               MAP
            </span>{` `}
            link in the top nav bar.
         </Typography>
      </div>
      <TableContainer component={Paper}>
         <Table
            aria-label={'used paints table'}
            size={'small'}
         >
            <TableHead>
               <TableRow>
                  <TableCell style={{width: 75}}/>
                  <TableCell style={{
                     textAlign: css3.textAlign.center,
                     width: 75,
                  }}>
                     <b>Ref</b>
                  </TableCell>
                  <TableCell style={{
                     textAlign: css3.textAlign.center,
                     width: 75,
                  }}>
                     <b>Blocks</b>
                  </TableCell>
                  <TableCell/>
                  <TableCell><b>Paint</b></TableCell>
               </TableRow>
            </TableHead>
            <TableBody>
               {getTableRows()}
            </TableBody>
         </Table>
      </TableContainer>
      <div className={'minHeight_500'}></div>
   </>
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این به من امکان می دهد قبل از شروع نقاشی ببینم به چه رنگ هایی نیاز دارم و به چه نسبتی.

توضیحات تصویر

نقشه برداری رنگی

پیوند MAP به یک جدول بزرگ منتهی می شود که در آن هر بلوک از تصویر اصلی یک سلول در آن جدول است. هر سلول حاوی عددی است که مربوط به یک رنگ مشخص است. از کجا می دانی که عدد مطابقت دارد که رنگ کنم؟ شما به صفحه آمار نگاه کنید. که کلید رنگ را در اختیار شما قرار می دهد.

کد کامپوننت Map در اینجا آمده است:

// Map.js

export const Map = () => {
   const uiState = useContext(UIState);
   const navigateTo = useNavigate();
   const allColors = useAllColors();
   let colors = [];

   const getTableCells = (cells = [rgbModel], rowIndex = -1) => {
      const { highlightedColor } = uiState;
      return cells.map((cell, cellIndex) => {
         const paintIndex = colors.findIndex(color => color.name === cell.name);
         const darkness = (cell.red + cell.green + cell.blue) / 3;
         let color;
         let backgroundColor;
         if (highlightedColor === cell.name) {
            backgroundColor = '#39ff14';
            color = 'red';
         } else {
            backgroundColor = `rgb(${cell.red}, ${cell.green}, ${cell.blue})`;
            color = darkness < 128 ? 'white' : 'black';
         }
         return (
            <td
               className={'cell'}
               id={cell.name}
               key={`cell-${rowIndex}-${cellIndex}`}
               onClick={handleCellClick}
               style={{
                  backgroundColor,
                  borderWidth: highlightedColor === cell.name ? 5 : 0,
                  color,
               }}
            >
               {paintIndex}
            </td>
         );
      })
   }

   const getTableRows = () => {
      colors = allColors.get();
      return uiState.stats.map.map((row, rowIndex) => {
         return (
            <tr key={`row-${rowIndex}`}>
               {getTableCells(row, rowIndex)}
            </tr>
         )
      })
   }

   const handleCellClick = (event = {}) => {
      uiState.toggleHighlightedColor(event.target.id);
   }

   const navigateToStats = () => navigateTo('/stats');

   if (Object.keys(uiState.stats).length === 0)
      return null;

   return <>
      <h4 className={'marginBottom_8'}>Color Map</h4>
      <div className={'marginBottom_48'}>
         <Typography>
            This is essentially a paint-by-numbers grid for the image that you generated.  You can copy all of the HTML from the
            grid below paste it into a spreadsheet (like Google Sheets).  The key that tells you which colors map to which
            numbers can be seen by clicking on the{` `}
            <span
               className={'spanLink'}
               onClick={navigateToStats}
            >
               STATS
            </span>{` `}
            link in the top nav bar.  Also, clicking on any of the color squares in the image below will highlight <i>every</i> instance
            of that color in the map.  Clicking the same color again will toggle the highlighting <i>off</i>.
         </Typography>
      </div>
      <table className={'borderSpacing_0'}>
         <tbody>
            {getTableRows()}
         </tbody>
      </table>
      <div className={'minHeight_500'}></div>
   </>
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

میز بزرگی که روی صفحه پرتاب می شود ممکن است کمی ناخوشایند به نظر برسد. اما من این کار را انجام داده‌ام زیرا می‌توانید یک جدول HTML را در اکثر محصولات صفحه‌گسترده (مانند Microsoft Excel یا Google Sheets) کپی-ن-پیست کنید و بیشتر اطلاعات را حفظ کنید. بنابراین هنگامی که آن را به یک صفحه گسترده منتقل کردم، سپس از آن صفحه گسترده برای هدایت نقاشی خود برای بقیه مدتی که روی قطعه کار می کنم استفاده می کنم.

به عنوان مثال، این بخشی از صفحه گسترده از قطعه ای است که اکنون روی آن کار می کنم:

توضیحات تصویر

من به صورت دستی آن خطوط شبکه قرمز را در فواصل 10 سلولی اضافه کردم. آنها با شبکه ای که من روی پانل خود ترسیم کرده ام مرتبط هستند. توجه داشته باشید که سلول های سمت راست صفحه فاقد اعداد هستند. دلیلش این است که وقتی آن بخش را نقاشی کردم، اعداد را خالی می‌کنم، بنابراین برای من آسان است که فقط با نگاه کردن به صفحه‌گسترده، بفهمم چه چیزی نقاشی کرده‌ام و چه چیزهایی را هنوز تمام نکرده‌ام.

توضیحات تصویر

در قسط بعدی…

آنجا است بدون قسط بعدی! وای! این خیلی برای نوشتن بود! من نمی دانم به چند نفر در اینجا کمک خواهد کرد (در صورت وجود). اما من می خواستم بسیاری از چیزهایی را که در مورد مدیریت رنگ یاد گرفتم در React/JavaScript ثبت کنم. برخورد با رنگ ها یک مقدار زیادی زمانی که برای اولین بار این مسیر را شروع کردم، بسیار ظریف تر از آن چیزی است که هرگز فکر می کردم.

Building Paint Map Studio فوق العاده بود سرگرم کننده تجربه. نه تنها به عنوان یک ابزار کاربردی در نقاشی من عمل می کند، بلکه توانایی من را برای دستکاری برنامه نویسی تصاویر و مدیریت پویا جنبه های رنگ در آن تصاویر را بسیار گسترش می دهد.

با تشکر از شما برای خواندن!

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا