import qrcode import io import os from django.conf import settings from django.http import HttpResponse from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status from .models import QRCode from .serializers import QRCodeSerializer from .models import QRCode, MergedQRCode from .serializers import QRCodeSerializer, MergedQRCodeSerializer from PIL import Image, ImageDraw, ImageFont import requests from io import BytesIO from pyzbar.pyzbar import decode from functools import wraps def require_api_key(func): @wraps(func) def wrapped(self, request, *args, **kwargs): # Retrieve the API key from the request headers api_key = request.headers.get('X-API-Key') # Check if the API key matches the one in your settings if api_key == settings.STATIC_API_KEY: return func(self, request, *args, **kwargs) else: return Response({'success':'false', 'error_msg':'Unauthorized ', 'errors':{}, 'response':{}, },status=status.HTTP_401_UNAUTHORIZED) return wrapped #### Genrate QR code and Get Qr code class QRCodeAPIView(APIView): @require_api_key def get(self, request, pk=None): if pk is None: return Response({'success':'false', 'error_msg':'ID is required ', 'errors':{}, 'response':{}, },status=status.HTTP_400_BAD_REQUEST) try: qr_code = QRCode.objects.get(pk=pk) except QRCode.DoesNotExist: return Response({'success':'false', 'error_msg':'QR code not found ', 'errors':{}, 'response':{}, },status=status.HTTP_404_NOT_FOUND) # Load the QR code image image_path = qr_code.image_path full_image_path = os.path.join(settings.STATIC_ROOT, image_path) with open(full_image_path, 'rb') as image_file: return HttpResponse(image_file.read(), content_type="image/png") @require_api_key def post(self, request, *args, **kwargs): serializer = QRCodeSerializer(data=request.data) if serializer.is_valid(): dataitem=request.data['data'] print(dataitem) if dataitem==[]: return Response({'success':'false', 'error_msg':'List should not be Empty', 'errors':{}, 'response':{}, },status=status.HTTP_400_BAD_REQUEST) qr_code = serializer.save() qr_code_id = qr_code.id # Generate QR code qr = qrcode.QRCode( version=1, error_correction=qrcode.constants.ERROR_CORRECT_L, box_size=10, border=4, ) # print("Dummyurls",request.data['urls']) concatenated_links = "\n".join(request.data['data']) # print('concatenated_links',concatenated_links) qr.add_data(str(concatenated_links)) qr.make(fit=True) # Convert to image img = qr.make_image(fill="black", back_color="white") image_filename = f"qrcode_{qr_code_id}.png" image_path = os.path.join('qrimages', image_filename) full_image_path = os.path.join(settings.STATIC_ROOT, image_path) # Save image to static directory if not os.path.exists(os.path.dirname(full_image_path)): os.makedirs(os.path.dirname(full_image_path)) img.save(full_image_path) # Update model with image path qr_code.image_path = image_path qr_code.save() qr_code_image_url = request.build_absolute_uri(f"{qr_code_id}/") return Response({ 'success':'true', 'error_msg':'', 'response':{}, "qr_code": serializer.data, "qr_code_image_url": qr_code_image_url }, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) ## Merge and Get multiple and Single QR code from Thired Party api QR code image link class MergedQRCodeThirdPartyApi(APIView): @require_api_key def get(self, request, pk=None): if pk is None: return Response({ 'success':'false', 'error_msg':'', 'response':{}, "error": "ID is required"}, status=status.HTTP_400_BAD_REQUEST) try: qr_code = MergedQRCode.objects.get(pk=pk) except MergedQRCode.DoesNotExist: return Response({ 'success':'false', 'error_msg':'', 'response':{}, "error": "QR code not found"}, status=status.HTTP_404_NOT_FOUND) # Load the QR code image image_path = qr_code.image_path full_image_path = os.path.join(settings.STATIC_ROOT, image_path) with open(full_image_path, 'rb') as image_file: return HttpResponse(image_file.read(), content_type="image/png") @require_api_key def post(self, request, *args, **kwargs): image_paths = request.data.get('image_paths', []) if not image_paths: return Response({ 'success':'false', 'error_msg':'', 'response':{}, "error": "No image paths provided"}, status=status.HTTP_400_BAD_REQUEST) qr_codes = [] combined_data = [] for image_path in image_paths: try: if image_path.startswith(('http://', 'https://')): headers = { 'X-API-Key': settings.STATIC_API_KEY # Add the API key in the headers } # Download image from remote URL response = requests.get(image_path,headers=headers) print('response',response) if response.status_code==200: response.raise_for_status() img = Image.open(BytesIO(response.content)) else: return Response({ 'success':'false', 'error_msg':'', 'response':{}, "error": f"QR code Image api Not Valid"}, status=status.HTTP_400_BAD_REQUEST) else: # Handle local file path full_image_path = os.path.join(settings.MEDIA_ROOT, image_path) img = Image.open(full_image_path) decoded_qr = decode(img) if not decoded_qr: return Response({ 'success':'false', 'error_msg':'', 'response':{}, "error": f"QR code not found in image {image_path}"}, status=status.HTTP_400_BAD_REQUEST) decoded_data = decoded_qr[0].data.decode('utf-8') # Decode QR code data qr_code = QRCode.objects.create( name=f"QR Code for {os.path.basename(image_path)}", data=decoded_data, image_path=image_path ) qr_codes.append(qr_code) combined_data.append(decoded_data) except Exception as e: return Response({ 'success':'false', 'error_msg':'', 'response':{}, "error": f"Error processing image {image_path}: {str(e)}"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) # Generate a new merged QR code qr = qrcode.QRCode( version=1, error_correction=qrcode.constants.ERROR_CORRECT_L, box_size=10, border=4, ) # Join combined data with newlines or another delimiter combined_data_str = "\n".join(combined_data) qr.add_data(combined_data_str) qr.make(fit=True) merged_qr_code = MergedQRCode.objects.create( merged_data=combined_data_str ) merged_qr_code.original_qrcodes.set(qr_codes) merged_qr_code.save() img = qr.make_image(fill="black", back_color="white") merged_image_filename = f"{merged_qr_code.id}externalmerged_qrcode_{len(qr_codes)}.png" merged_image_path = os.path.join('merged_qrcode', merged_image_filename) merged_qr_code.image_path=merged_image_path merged_qr_code.save() full_image_path = os.path.join(settings.STATIC_ROOT, merged_image_path) if not os.path.exists(os.path.dirname(full_image_path)): os.makedirs(os.path.dirname(full_image_path)) img.save(full_image_path) return Response({ 'success':'true', 'error_msg':'', 'response':{}, "merged_qr_code": MergedQRCodeSerializer(merged_qr_code).data, "merged_qr_code_image_url": request.build_absolute_uri(f"{merged_qr_code.id}/") }, status=status.HTTP_201_CREATED) ## Merge and Get multiple and Single QR code from Thired Party api QR code image link and Show the all decoded data on the QR code class MergedQRCodeInfoThirdPartyApi(APIView): @require_api_key def get(self, request, pk=None): if pk is None: return Response({ 'success':'false', "error": "ID is required", 'error_msg':'', 'response':{}, }, status=status.HTTP_400_BAD_REQUEST) try: qr_code = MergedQRCode.objects.get(pk=pk) except MergedQRCode.DoesNotExist: return Response({ 'success':'false', "error": "QR code not found", 'error_msg':'', 'response':{}, }, status=status.HTTP_404_NOT_FOUND) # Load the QR code image image_path = qr_code.image_path full_image_path = os.path.join(settings.STATIC_ROOT, image_path) with open(full_image_path, 'rb') as image_file: return HttpResponse(image_file.read(), content_type="image/png") @require_api_key def post(self, request, *args, **kwargs): image_paths = request.data.get('image_paths', []) if not image_paths: return Response({ "success":'false', "error": "No image paths provided", 'error_msg':'', 'response':{}, }, status=status.HTTP_400_BAD_REQUEST) qr_codes = [] combined_data = [] for image_path in image_paths: try: if image_path.startswith(('http://', 'https://')): # Download image from remote URL headers = { 'X-API-Key': settings.STATIC_API_KEY # Add the API key in the headers } # Download image from remote URL response = requests.get(image_path,headers=headers) print('response',response) if response.status_code == 200: response.raise_for_status() img = Image.open(BytesIO(response.content)) else: return Response({ "success":'false', "error": f"QR code Image API not valid", 'error_msg':'', 'response':{}, }, status=status.HTTP_400_BAD_REQUEST) else: # Handle local file path full_image_path = os.path.join(settings.MEDIA_ROOT, image_path) img = Image.open(full_image_path) decoded_qr = decode(img) if not decoded_qr: return Response({ 'success':'false', 'error': f"QR code not found in image {image_path}", 'error_msg':'', 'response':{}, }, status=status.HTTP_400_BAD_REQUEST) decoded_data = decoded_qr[0].data.decode('utf-8') # Decode QR code data qr_code = QRCode.objects.create( name=f"QR Code for {os.path.basename(image_path)}", data=decoded_data, image_path=image_path ) qr_codes.append(qr_code) combined_data.append(decoded_data) except Exception as e: return Response({ 'success':'false', "error": f"Error processing image {image_path}: {str(e)}", 'error_msg':'', 'response':{}, }, status=status.HTTP_500_INTERNAL_SERVER_ERROR) # Generate a new merged QR code qr = qrcode.QRCode( version=1, error_correction=qrcode.constants.ERROR_CORRECT_L, box_size=10, border=4, ) # Join combined data with newlines or another delimiter combined_data_str = "\n".join(combined_data) qr.add_data(combined_data_str) qr.make(fit=True) merged_qr_code = MergedQRCode.objects.create( merged_data=combined_data_str ) merged_qr_code.original_qrcodes.set(qr_codes) merged_qr_code.save() # Create the QR code image qr_img = qr.make_image(fill="black", back_color="white") # Create a new image (canvas) to fit both the QR code and text qr_width, qr_height = qr_img.size font_size = 20 padding = 10 # Load font (you can replace with a custom font path if needed) try: font = ImageFont.truetype("arial.ttf", font_size) except IOError: font = ImageFont.load_default() # Estimate the width and height for the text block text_lines = combined_data_str.split('\n') # Calculate text dimensions using getbbox (Pillow 8.0+) text_height = sum(font.getbbox(line)[3] - font.getbbox(line)[1] for line in text_lines) + padding text_width = max([font.getbbox(line)[2] - font.getbbox(line)[0] for line in text_lines]) + padding # Create a new image with enough space for the text on the left and the QR code on the right canvas = Image.new('RGB', (qr_width + text_width + 2 * padding, max(qr_height, text_height) + 2 * padding), 'white') draw = ImageDraw.Draw(canvas) # Draw the text on the left current_height = padding for line in text_lines: draw.text((padding, current_height), line, fill="black", font=font) current_height += font.getbbox(line)[3] - font.getbbox(line)[1] + 5 # Add line height # Paste the QR code image on the right side of the canvas canvas.paste(qr_img, (text_width + padding, padding)) # Save the final image merged_image_filename = f"{merged_qr_code.id}merged_info_qrcode_{len(qr_codes)}.png" merged_image_path = os.path.join('merged_infoqr', merged_image_filename) full_image_path = os.path.join(settings.STATIC_ROOT, merged_image_path) if not os.path.exists(os.path.dirname(full_image_path)): os.makedirs(os.path.dirname(full_image_path)) canvas.save(full_image_path) # Save the image path to the database merged_qr_code.image_path = merged_image_path merged_qr_code.save() return Response({ 'success':'true', 'error_msg':'', 'response':{}, "merged_qr_code": MergedQRCodeSerializer(merged_qr_code).data, "merged_qr_code_image_url": request.build_absolute_uri(f"{merged_qr_code.id}/") }, status=status.HTTP_201_CREATED) # Get Qr Image Merged qr code with Info and only qr code class MergedQRCodeRetrieveApi(APIView): @require_api_key def get(self, request, pk=None): if pk is None: try: # Retrieve the merged QR code using the primary key (id) merged_qr_code = MergedQRCode.objects.all() except MergedQRCode.DoesNotExist: return Response({ 'success':'false', 'error_msg':'Merged QR code not found', 'response':{}, }, status=status.HTTP_404_NOT_FOUND) # Build the absolute URL for the QR code image merged_qrdat=[] for mergeddata in merged_qr_code: full_img_url =request.build_absolute_uri(f"{mergeddata.id}/") merged_qrdat.append({"id": mergeddata.id, "img_url": full_img_url}) # merged_qr_code_image_url = request.build_absolute_uri(f"/static/{merged_qr_code.image_path}") # Return the merged QR code data and image URL return Response({ 'success':'true', 'error_msg':'', 'response':{}, "merged_qr_code": merged_qrdat, }, status=status.HTTP_200_OK) if pk is not None: merged_qr_code = MergedQRCode.objects.filter(id=pk) if merged_qr_code: image_path = merged_qr_code[0].image_path full_image_path = os.path.join(settings.STATIC_ROOT, image_path) with open(full_image_path, 'rb') as image_file: return HttpResponse(image_file.read(), content_type="image/png") else: return Response({ 'success':'false', 'error_msg':'', 'response':{}, }, status.HTTP_404_NOT_FOUND) # Merged QR code from the Database QR code Info class MergedQRCodeAPIView(APIView): @require_api_key def get(self, request, pk=None): try: merged_qr_code = MergedQRCode.objects.get(pk=pk) except MergedQRCode.DoesNotExist: return Response({'success':'false', 'error_msg':'Merged QR code not found', 'errors':{}, 'response':{}, },status=status.HTTP_404_NOT_FOUND) # Load the QR code image image_path = merged_qr_code.image_path full_image_path = os.path.join(settings.STATIC_ROOT, image_path) with open(full_image_path, 'rb') as image_file: return HttpResponse(image_file.read(), content_type="image/png") @require_api_key def post(self, request, *args, **kwargs): qr_codes_ids = request.data.get('qr_codes_ids', []) qr_codes = QRCode.objects.filter(id__in=qr_codes_ids) if qr_codes.count() != len(qr_codes_ids): return Response({'success':'false', 'error_msg':'Some QR codes not found', 'errors':{}, 'response':{}, },status=status.HTTP_404_NOT_FOUND) # Combine URLs from all QR codes combined_urls = [] # combined_urls1 = ['https://yuvedtech.com/','https://www.tutorialspoint.com/','https://www.python.org/about/gettingstarted/','https://www.tableau.com/'] for qr_code in qr_codes: combined_urls.extend(qr_code.data) # Generate QR code qr = qrcode.QRCode( version=1, error_correction=qrcode.constants.ERROR_CORRECT_L, box_size=10, border=4, ) print('combined_urls',combined_urls) # print('combined_urls1',combined_urls1) newurls= "\n\n".join(combined_urls) print('newurls',newurls) qr.add_data(str(newurls)) qr.make(fit=True) # Convert to image img = qr.make_image(fill="black", back_color="white") image_filename = f"merged_qrcode{qr_codes_ids}.png" image_path = os.path.join('qrimages', image_filename) full_image_path = os.path.join(settings.STATIC_ROOT, image_path) if not os.path.exists(os.path.dirname(full_image_path)): os.makedirs(os.path.dirname(full_image_path)) img.save(full_image_path) # Save the merged QR code merged_qr_code = MergedQRCode.objects.create(image_path=image_path) merged_qr_code.original_qrcodes.set(qr_codes) merged_qr_code.merged_data=combined_urls merged_qr_code.save() return Response({ 'success':'false', 'error_msg':'', 'errors':{}, "merged_qr_code": MergedQRCodeSerializer(merged_qr_code).data, "merged_qr_code_image_url": request.build_absolute_uri(f"{merged_qr_code.id}/") }, status=status.HTTP_201_CREATED) #Genrate QR code and show scanned data as a PopUP class QRCodeWithPopUpLink(APIView): def post(self, request, *args, **kwargs): links = ["https://www.codingbrains.com/"] concatenated_links = "\n".join(links) # Create a QRCode object qr = qrcode.QRCode( version=1, # controls the size of the QR code (1 is the smallest) error_correction=qrcode.constants.ERROR_CORRECT_L, # about 7% error tolerance box_size=10, # size of each box in pixels border=4, # width of the border (min is 4) ) # Add concatenated data to the QR code qr.add_data(concatenated_links) qr.make(fit=True) # adjust the dimensions of the QR code img = qr.make_image(fill="black", back_color="white") merged_image_filename = f"qrcode_popuplink.png" merged_image_path = os.path.join('qrcode_popuplink', merged_image_filename) full_image_path = os.path.join(settings.STATIC_ROOT, merged_image_path) if not os.path.exists(os.path.dirname(full_image_path)): os.makedirs(os.path.dirname(full_image_path)) img.save(full_image_path) return Response({"Message": f"Popup link QR code genrated in qrcode_popuplink folder "}, status=status.HTTP_201_CREATED)